feat(core): enhance availability routing with wrapped fallback and single-model policies (#13874)

This commit is contained in:
Adam Weidman
2025-12-01 12:41:06 -08:00
committed by GitHub
parent 806cd112ac
commit b4df7e351b
5 changed files with 65 additions and 24 deletions

View File

@@ -72,8 +72,11 @@ export function getModelPolicyChain(
/**
* Provides a default policy scaffold for models not present in the catalog.
*/
export function createDefaultPolicy(model: string): ModelPolicy {
return definePolicy({ model });
export function createDefaultPolicy(
model: string,
options?: { isLastResort?: boolean },
): ModelPolicy {
return definePolicy({ model, isLastResort: options?.isLastResort });
}
export function validateModelPolicyChain(chain: ModelPolicyChain): void {

View File

@@ -22,6 +22,7 @@ describe('policyHelpers', () => {
isInFallbackMode: () => false,
} as unknown as Config;
const chain = resolvePolicyChain(config);
expect(chain).toHaveLength(1);
expect(chain[0]?.model).toBe('custom-model');
});
@@ -46,7 +47,7 @@ describe('policyHelpers', () => {
];
const context = buildFallbackPolicyContext(chain, 'b');
expect(context.failedPolicy?.model).toBe('b');
expect(context.candidates.map((p) => p.model)).toEqual(['c']);
expect(context.candidates.map((p) => p.model)).toEqual(['c', 'a']);
});
it('returns full chain when model is not in policy list', () => {

View File

@@ -34,7 +34,9 @@ export function resolvePolicyChain(config: Config): ModelPolicyChain {
return chain;
}
return [createDefaultPolicy(activeModel), ...chain];
// If the user specified a model not in the default chain, we assume they want
// *only* that model. We do not fallback to the default chain.
return [createDefaultPolicy(activeModel, { isLastResort: true })];
}
/**
@@ -52,9 +54,11 @@ export function buildFallbackPolicyContext(
if (index === -1) {
return { failedPolicy: undefined, candidates: chain };
}
// Return [candidates_after, candidates_before] to prioritize downgrades
// (continuing the chain) before wrapping around to upgrades.
return {
failedPolicy: chain[index],
candidates: chain.slice(index + 1),
candidates: [...chain.slice(index + 1), ...chain.slice(0, index)],
};
}