feat: allow specifying model provider in preferences (#350)

Add explicit provider targeting for model preferences when the same
model ID exists across multiple providers (e.g., claude-sonnet-4-6
on both Anthropic and Bedrock).

Two formats supported:
- String: "bedrock/claude-sonnet-4-6"
- Object: { model: claude-sonnet-4-6, provider: bedrock }

The provider/model string format already worked in the resolution
code but was undocumented. This adds the provider field to the
object format and documents both approaches.
This commit is contained in:
Flux Labs 2026-03-14 15:06:49 -05:00
parent 6450c5b8d9
commit c1dcca6820
2 changed files with 34 additions and 1 deletions

View file

@ -84,7 +84,9 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
- `models`: per-stage model selection for auto-mode. Keys: `research`, `planning`, `execution`, `completion`. Values can be:
- Simple string: `"claude-sonnet-4-6"` — single model, no fallbacks
- Provider-qualified string: `"bedrock/claude-sonnet-4-6"` — targets a specific provider when the same model ID exists across multiple providers
- Object with fallbacks: `{ model: "claude-opus-4-6", fallbacks: ["glm-5", "minimax-m2.5"] }` — tries fallbacks in order if primary fails
- Object with provider: `{ model: "claude-opus-4-6", provider: "bedrock" }` — explicit provider targeting in object format
- Omit a key to use whatever model is currently active. Fallbacks are tried when model switching fails (provider unavailable, rate limited, etc.).
- `skill_discovery`: controls how GSD discovers and applies skills during auto-mode. Valid values:
@ -181,6 +183,29 @@ models:
When a model fails to switch (provider unavailable, rate limited, credits exhausted), GSD automatically tries the next model in the `fallbacks` list. This ensures auto-mode continues even when your preferred provider hits limits.
## Provider Targeting
When the same model ID exists across multiple providers (e.g., `claude-sonnet-4-6` on both Anthropic and Bedrock), use the `provider/model` format or the `provider` field to target a specific one:
```yaml
---
version: 1
models:
# String format: provider/model
research: bedrock/claude-sonnet-4-6
planning: anthropic/claude-opus-4-6
# Object format: explicit provider field
execution:
model: claude-sonnet-4-6
provider: bedrock
fallbacks:
- anthropic/claude-sonnet-4-6
---
```
If you use a bare model ID (no provider prefix) and it exists in multiple providers, GSD will warn you and resolve to the first available match. Use `provider/model` format to avoid ambiguity.
**Cost-optimized example** — use cheap models with expensive ones as fallback for critical phases:
```yaml

View file

@ -28,6 +28,8 @@ export interface GSDSkillRule {
export interface GSDPhaseModelConfig {
/** Primary model ID (e.g., "claude-opus-4-6") */
model: string;
/** Provider name to disambiguate when the same model ID exists across providers (e.g., "bedrock", "anthropic") */
provider?: string;
/** Fallback models to try in order if primary fails (e.g., rate limits, credits exhausted) */
fallbacks?: string[];
}
@ -580,8 +582,14 @@ export function resolveModelWithFallbacksForUnit(unitType: string): ResolvedMode
return { primary: phaseConfig, fallbacks: [] };
}
// When provider is explicitly set, prepend it to the model ID so the
// resolution code in auto.ts can do an explicit provider match.
const primary = phaseConfig.provider && !phaseConfig.model.includes("/")
? `${phaseConfig.provider}/${phaseConfig.model}`
: phaseConfig.model;
return {
primary: phaseConfig.model,
primary,
fallbacks: phaseConfig.fallbacks ?? [],
};
}