mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
95 lines
3.4 KiB
TypeScript
95 lines
3.4 KiB
TypeScript
/**
|
|
* Issue #2911 — Built-in GitHub Copilot Claude Opus / Gemini models fail.
|
|
*
|
|
* The `github` provider has `format: "openai"` (baseUrl .../chat/completions)
|
|
* and a separate `responsesBaseUrl` (.../responses). A model only routes to the
|
|
* Responses API when it sets `targetFormat: "openai-responses"`.
|
|
*
|
|
* GitHub Copilot's Responses API does NOT serve the Claude/Gemini models, so
|
|
* `claude-opus-4.7`, `gemini-3.1-pro-preview` and other non-OpenAI models
|
|
* failed with a 400. The working `claude-sonnet-4.6`
|
|
* carries no `targetFormat` and goes through chat/completions.
|
|
*
|
|
* Fix: drop `targetFormat: "openai-responses"` from the Claude/Gemini entries so
|
|
* they use the provider default (chat/completions). The native OpenAI `gpt-*`
|
|
* models legitimately keep the Responses API and must NOT be touched.
|
|
*/
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
|
|
const { getModelsByProviderId } = await import("../../open-sse/config/providerModels.ts");
|
|
|
|
type ModelEntry = { id: string; targetFormat?: string; [k: string]: unknown };
|
|
|
|
function githubModel(id: string): ModelEntry | undefined {
|
|
const provider = (REGISTRY as Record<string, { models?: ModelEntry[] }>)["github"];
|
|
return provider?.models?.find((m) => m.id === id);
|
|
}
|
|
|
|
// Claude/Gemini models that must NOT route through the Responses API.
|
|
const MUST_NOT_BE_RESPONSES = [
|
|
"claude-fable-5",
|
|
"claude-opus-5",
|
|
"claude-opus-4.7",
|
|
"claude-opus-4.8",
|
|
"claude-opus-4.8-fast",
|
|
"claude-opus-4.5",
|
|
"claude-sonnet-4.6",
|
|
"claude-sonnet-5",
|
|
"claude-sonnet-4.5",
|
|
"claude-haiku-4.5",
|
|
"gemini-3.1-pro-preview",
|
|
"gemini-3.7-flash",
|
|
];
|
|
|
|
for (const id of MUST_NOT_BE_RESPONSES) {
|
|
test(`#2911 github/${id} must not use openai-responses targetFormat`, () => {
|
|
const model = githubModel(id);
|
|
assert.ok(model, `${id} must be registered under github`);
|
|
assert.notEqual(
|
|
model.targetFormat,
|
|
"openai-responses",
|
|
`github/${id} must route via chat/completions (Copilot Responses API rejects it)`
|
|
);
|
|
});
|
|
}
|
|
|
|
test("#2911 github/claude-sonnet-4.6 baseline stays on chat/completions (no targetFormat)", () => {
|
|
const model = githubModel("claude-sonnet-4.6");
|
|
assert.ok(model, "claude-sonnet-4.6 must be registered");
|
|
assert.notEqual(model.targetFormat, "openai-responses");
|
|
});
|
|
|
|
// Regression guard: models with `/responses` in the curated Copilot catalog keep the Responses API.
|
|
for (const id of [
|
|
"gpt-5.3-codex",
|
|
"gpt-5.4-mini",
|
|
"gpt-5.4",
|
|
"gpt-5.5",
|
|
"gpt-5.6-sol",
|
|
"gpt-5.6-terra",
|
|
"gpt-5.6-luna",
|
|
"mai-code-1-flash",
|
|
"gpt-5-mini",
|
|
"oswe-vscode-prime",
|
|
]) {
|
|
test(`#2911 github/${id} (OpenAI-native) still uses openai-responses`, () => {
|
|
const model = githubModel(id);
|
|
assert.ok(model, `${id} must be registered`);
|
|
assert.equal(
|
|
model.targetFormat,
|
|
"openai-responses",
|
|
`github/${id} is OpenAI-native and must keep the Responses API`
|
|
);
|
|
});
|
|
}
|
|
|
|
// Sanity: lookup-by-id helper resolves the same entries.
|
|
test("#2911 getModelsByProviderId(github) reflects the targetFormat changes", () => {
|
|
const models = getModelsByProviderId("github") as ModelEntry[];
|
|
const opus47 = models.find((m) => m.id === "claude-opus-4.7");
|
|
assert.ok(opus47, "claude-opus-4.7 resolvable via getModelsByProviderId");
|
|
assert.notEqual(opus47.targetFormat, "openai-responses");
|
|
});
|