Refactor LLM verification and update dependencies
- Removed OpenAI and related dependencies from package.json and package-lock.json. - Simplified LLM verification logic to focus on OpenCode server. - Updated tests to reflect changes in LLM provider handling. - Added CI and CD workflows for automated processes in Gitea.
This commit is contained in:
+15
-53
@@ -16,17 +16,10 @@ import { step, line, ok, error, result } from './log.js';
|
||||
const httpsAgent = GITEA_SKIP_TLS_VERIFY ? new https.Agent({ rejectUnauthorized: false }) : undefined;
|
||||
const api = (path) => `${GITEA_SERVER_URL.replace(/\/$/, '')}/api/v1${path}`;
|
||||
const giteaHeaders = (token) => ({ Authorization: `token ${token}`, 'Content-Type': 'application/json' });
|
||||
const usesResponsesApi = (provider, model) => provider === 'openai' && /^gpt-5\.5(?:-|$)/i.test(model || '');
|
||||
const opencodeModelConfig = (model) => {
|
||||
const [providerID, modelID] = model.includes('/') ? model.split('/', 2) : [process.env.OPENCODE_PROVIDER || 'google', model];
|
||||
return { providerID, modelID };
|
||||
};
|
||||
const applyOpenCodeAuth = (headers) => {
|
||||
const password = process.env.OPENCODE_SERVER_PASSWORD;
|
||||
if (!password) return;
|
||||
const username = process.env.OPENCODE_SERVER_USERNAME || 'opencode';
|
||||
headers['Authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
|
||||
};
|
||||
const opencodeAxiosOptions = (headers) => ({
|
||||
headers,
|
||||
timeout: 30000,
|
||||
@@ -70,58 +63,28 @@ export async function verifyCommentToken(token = GITEA_COMMENT_TOKEN) {
|
||||
|
||||
/**
|
||||
* 驗證 LLM 設定可用:
|
||||
* - 須已選定一個 provider
|
||||
* - Ollama 檢查 base URL 是否可連線
|
||||
* - 其餘 provider 以最小請求驗證認證,多把 Key 只要一把成功即可
|
||||
* - 僅支援 OpenCode server
|
||||
* - 檢查 OpenCode base URL 是否可連線,並確認 provider/model 已設定
|
||||
*/
|
||||
export async function verifyLLM() {
|
||||
const { provider, apiKeys, baseURL, model } = getLLMConfig();
|
||||
if (!provider) return { ok: false, error: '未設定任何 LLM provider 或 API Key' };
|
||||
const { provider, baseURL, model } = getLLMConfig();
|
||||
if (!provider) return { ok: false, error: '未設定 OpenCode server,請設定 OPENCODE_BASE_URL' };
|
||||
if (!baseURL) return { ok: false, provider, error: `${provider} 缺少 base URL` };
|
||||
|
||||
const base = baseURL.replace(/\/$/, '');
|
||||
const headers = { 'Content-Type': 'application/json' };
|
||||
|
||||
if (provider === 'ollama') {
|
||||
try {
|
||||
await axios.get(`${base}/models`, { timeout: 30000 });
|
||||
return { ok: true, provider };
|
||||
} catch (e) {
|
||||
return { ok: false, provider, error: `Ollama base URL 無法連線: ${e.message}` };
|
||||
}
|
||||
const { providerID, modelID } = opencodeModelConfig(model);
|
||||
try {
|
||||
await axios.get(`${base}/global/health`, opencodeAxiosOptions(headers));
|
||||
const providers = await axios.get(`${base}/config/providers`, opencodeAxiosOptions(headers));
|
||||
const configuredProvider = providers.data.providers?.find(p => p.id === providerID);
|
||||
if (!configuredProvider) return { ok: false, provider, error: `OpenCode server 未設定 provider=${providerID}` };
|
||||
if (!configuredProvider.models?.[modelID]) return { ok: false, provider, error: `OpenCode server provider=${providerID} 未列出 model=${modelID}` };
|
||||
return { ok: true, provider };
|
||||
} catch (e) {
|
||||
return { ok: false, provider, error: `OpenCode server 驗證失敗: ${e.message}` };
|
||||
}
|
||||
|
||||
if (provider === 'opencode') {
|
||||
const { providerID, modelID } = opencodeModelConfig(model);
|
||||
applyOpenCodeAuth(headers);
|
||||
try {
|
||||
await axios.get(`${base}/global/health`, opencodeAxiosOptions(headers));
|
||||
const providers = await axios.get(`${base}/config/providers`, opencodeAxiosOptions(headers));
|
||||
const configuredProvider = providers.data.providers?.find(p => p.id === providerID);
|
||||
if (!configuredProvider) return { ok: false, provider, error: `OpenCode server 未設定 provider=${providerID}` };
|
||||
if (!configuredProvider.models?.[modelID]) return { ok: false, provider, error: `OpenCode server provider=${providerID} 未列出 model=${modelID}` };
|
||||
return { ok: true, provider };
|
||||
} catch (e) {
|
||||
return { ok: false, provider, error: `OpenCode server 驗證失敗: ${e.message}` };
|
||||
}
|
||||
}
|
||||
|
||||
if (provider === 'claude') headers['anthropic-version'] = '2023-06-01';
|
||||
const endpoint = usesResponsesApi(provider, model) ? `${base}/responses` : `${base}/chat/completions`;
|
||||
const payload = usesResponsesApi(provider, model)
|
||||
? { model, input: 'ping', max_output_tokens: 1, temperature: 0 }
|
||||
: { model, messages: [{ role: 'user', content: 'ping' }], max_tokens: 1, temperature: 0 };
|
||||
|
||||
for (let i = 0; i < apiKeys.length; i++) {
|
||||
headers['Authorization'] = `Bearer ${apiKeys[i]}`;
|
||||
try {
|
||||
await axios.post(endpoint, payload, { headers, timeout: 30000 });
|
||||
return { ok: true, provider, keyIndex: i + 1, total: apiKeys.length };
|
||||
} catch (e) {
|
||||
line(`[preflight] LLM key[${i + 1}/${apiKeys.length}] 驗證失敗: ${e.message}`);
|
||||
}
|
||||
}
|
||||
return { ok: false, provider, error: `所有 ${apiKeys.length} 把 ${provider} API Key 驗證失敗` };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,8 +135,7 @@ export async function runPreflight(workspace = process.env.GITHUB_WORKSPACE || '
|
||||
error(`LLM 驗證失敗: ${llm.error}`);
|
||||
return false;
|
||||
}
|
||||
if (llm.keyIndex) ok(`LLM provider=${llm.provider} 驗證通過(key ${llm.keyIndex}/${llm.total})`);
|
||||
else ok(`LLM provider=${llm.provider} 連線正常`);
|
||||
ok(`LLM provider=${llm.provider} 連線正常`);
|
||||
|
||||
result(true, '前置驗證通過');
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user