refactor(delegate-task): deduplicate DelegatedModelConfig + registry refactor

- Move DelegatedModelConfig to src/shared/model-resolution-types.ts
- Re-export from delegate-task/types.ts (preserving import paths)
- Replace background-agent/types.ts local duplicate with shared import
- Consolidate model-settings-compatibility.ts registry patterns
This commit is contained in:
Ravi Tharuma
2026-03-18 20:37:50 +01:00
parent 1e70f64001
commit 1f5d7702ff
7 changed files with 273 additions and 204 deletions
@@ -299,4 +299,178 @@ describe("resolveCompatibleModelSettings", () => {
],
})
})
// Provider-agnostic detection: model ID is the source of truth, not provider ID
test("detects Claude via any provider (provider-agnostic)", () => {
for (const providerID of ["anthropic", "aws-bedrock", "bedrock", "amazon-bedrock", "opencode", "my-custom-proxy", "google-vertex-anthropic"]) {
const result = resolveCompatibleModelSettings({
providerID,
modelID: "claude-sonnet-4-6",
desired: { variant: "max" },
})
expect(result.variant).toBe("high")
expect(result.changes[0]?.reason).toBe("unsupported-by-model-family")
}
})
test("detects Claude 3 Opus via any provider", () => {
const result = resolveCompatibleModelSettings({
providerID: "some-unknown-proxy",
modelID: "claude-3-opus-20240229",
desired: { variant: "max" },
})
expect(result.variant).toBe("max")
expect(result.changes).toEqual([])
})
test("detects OpenAI reasoning models without requiring openai provider", () => {
const result = resolveCompatibleModelSettings({
providerID: "azure-openai",
modelID: "o3-mini",
desired: { reasoningEffort: "high" },
})
expect(result.reasoningEffort).toBe("high")
expect(result.changes).toEqual([])
})
// -----------------------------------------------------------------------
// Registry coverage — every model family from FAMILY_CAPABILITIES
// -----------------------------------------------------------------------
describe("model family registry coverage", () => {
const familyCases: Array<{
name: string
modelID: string
expectedVariants: string[]
hasReasoningEffort: boolean
}> = [
{ name: "Gemini", modelID: "gemini-3.1-pro", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
{ name: "Kimi (kimi)", modelID: "kimi-k2.5", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
{ name: "Kimi (k2)", modelID: "k2-v2", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
{ name: "GLM", modelID: "glm-5", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
{ name: "Minimax", modelID: "minimax-m2.5", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
{ name: "DeepSeek", modelID: "deepseek-r2", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
{ name: "Mistral", modelID: "mistral-large-next", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
{ name: "Codestral → Mistral", modelID: "codestral-2506", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
{ name: "Llama", modelID: "llama-4-maverick", expectedVariants: ["low", "medium", "high"], hasReasoningEffort: false },
]
for (const { name, modelID, expectedVariants, hasReasoningEffort } of familyCases) {
test(`${name} (${modelID}): keeps supported variant`, () => {
const highest = expectedVariants[expectedVariants.length - 1]
const result = resolveCompatibleModelSettings({
providerID: "any-provider",
modelID,
desired: { variant: highest },
})
expect(result.variant).toBe(highest)
expect(result.changes).toEqual([])
})
test(`${name} (${modelID}): downgrades unsupported variant`, () => {
const result = resolveCompatibleModelSettings({
providerID: "any-provider",
modelID,
desired: { variant: "max" },
})
const highest = expectedVariants[expectedVariants.length - 1]
expect(result.variant).toBe(highest)
expect(result.changes[0]?.reason).toBe("unsupported-by-model-family")
})
test(`${name} (${modelID}): ${hasReasoningEffort ? "keeps" : "drops"} reasoningEffort`, () => {
const result = resolveCompatibleModelSettings({
providerID: "any-provider",
modelID,
desired: { reasoningEffort: "high" },
})
if (hasReasoningEffort) {
expect(result.reasoningEffort).toBe("high")
expect(result.changes).toEqual([])
} else {
expect(result.reasoningEffort).toBeUndefined()
expect(result.changes[0]?.reason).toBe("unsupported-by-model-family")
}
})
}
})
// GPT-5 specific: supports xhigh variant and xhigh reasoningEffort
test("GPT-5 keeps xhigh variant and reasoningEffort", () => {
const result = resolveCompatibleModelSettings({
providerID: "openai",
modelID: "gpt-5.4",
desired: { variant: "xhigh", reasoningEffort: "xhigh" },
})
expect(result).toEqual({
variant: "xhigh",
reasoningEffort: "xhigh",
changes: [],
})
})
// Reasoning effort: "none" and "minimal" are valid per Vercel AI SDK
test("GPT-5 keeps none reasoningEffort", () => {
const result = resolveCompatibleModelSettings({
providerID: "openai",
modelID: "gpt-5.4",
desired: { reasoningEffort: "none" },
})
expect(result).toEqual({
variant: undefined,
reasoningEffort: "none",
changes: [],
})
})
test("GPT-5 keeps minimal reasoningEffort", () => {
const result = resolveCompatibleModelSettings({
providerID: "openai",
modelID: "gpt-5.4",
desired: { reasoningEffort: "minimal" },
})
expect(result).toEqual({
variant: undefined,
reasoningEffort: "minimal",
changes: [],
})
})
test("o-series keeps none reasoningEffort", () => {
const result = resolveCompatibleModelSettings({
providerID: "openai",
modelID: "o3-mini",
desired: { reasoningEffort: "none" },
})
expect(result).toEqual({
variant: undefined,
reasoningEffort: "none",
changes: [],
})
})
// Passthrough: undefined desired values produce no changes
test("no-op when desired settings are empty", () => {
const result = resolveCompatibleModelSettings({
providerID: "anthropic",
modelID: "claude-opus-4-6",
desired: {},
})
expect(result).toEqual({
variant: undefined,
reasoningEffort: undefined,
changes: [],
})
})
})