refactor(qoder): dedupe PAT exchange logic, validate PAT keys properly

PAT-to-job-token exchange was duplicated between the executor and the model service, each with its own cache. Consolidate into qoderModels.js and have the executor import it.

Also add a qoder case to the API-key validate route - the generic OpenAI-compat probe cannot validate a PAT (needs job-token exchange + COSY signing first), so bulk-add always reported unknown for qoder keys.
This commit is contained in:
decolua
2026-08-05 11:26:22 +07:00
parent d433c0b295
commit 1eb37db32d
3 changed files with 24 additions and 106 deletions

View File

@@ -4,6 +4,7 @@ import { isOpenAICompatibleProvider, isAnthropicCompatibleProvider, isCustomEmbe
import { getDefaultModel } from "open-sse/config/providerModels.js";
import { resolveOllamaLocalHost, resolveXiaomiTokenplanBaseUrl, PROVIDERS } from "open-sse/config/providers.js";
import { openaiToCommandCodeRequest } from "open-sse/translator/request/openai-to-commandcode.js";
import { resolveQoderCredentials, resolveQoderModels } from "open-sse/services/qoderModels.js";
import { normalizeProviderId } from "@/lib/providerNormalization";
// Probe a webSearch/webFetch provider using its searchConfig/fetchConfig.
@@ -581,6 +582,20 @@ export async function POST(request) {
break;
}
case "qoder": {
// PAT (pt-...) needs the job-token exchange before it can sign
// anything — the generic OpenAI-compat probe below can't validate it.
try {
const resolved = await resolveQoderCredentials({ apiKey, providerSpecificData }, null, AbortSignal.timeout(8000));
const result = await resolveQoderModels(resolved, { forceRefresh: true });
isValid = !!result?.models?.length;
} catch (err) {
isValid = false;
error = err.message;
}
break;
}
default: {
// Generic probe for OpenAI-compatible providers (config-driven from PROVIDERS)
const cfg = PROVIDERS[provider];