( modelFallbacks: ModelFallbacks | undefined, modelString: string )
| 70 | * fallback models' chains are never chased, so chains cannot loop at runtime. |
| 71 | */ |
| 72 | export function resolveModelFallbackChain( |
| 73 | modelFallbacks: ModelFallbacks | undefined, |
| 74 | modelString: string |
| 75 | ): string[] { |
| 76 | if (!modelFallbacks) { |
| 77 | return []; |
| 78 | } |
| 79 | |
| 80 | const canonicalSource = normalizeToCanonical(modelString).trim(); |
| 81 | const entry = modelFallbacks[canonicalSource]; |
| 82 | if (!entry || entry.enabled === false || !Array.isArray(entry.models)) { |
| 83 | return []; |
| 84 | } |
| 85 | // Refusal is the only trigger today; entries restricted to other (future) |
| 86 | // triggers must not fire on refusals. |
| 87 | if (entry.triggers !== undefined && !entry.triggers.includes("model_refusal")) { |
| 88 | return []; |
| 89 | } |
| 90 | |
| 91 | return sanitizeModelFallbackChain(canonicalSource, entry.models); |
| 92 | } |
| 93 | |
| 94 | /** |
| 95 | * Sanitize a full fallback map for persistence: canonical keys, sanitized |
no test coverage detected