fix: resolve ProviderModelNotFoundError on non-Claude runtimes (#1156)

Extend resolve_model_ids to accept "omit" value: returns empty string
so non-Claude runtimes (OpenCode, Codex, Gemini, etc.) use their
configured default model instead of unresolvable Claude aliases.

- resolve_model_ids: "omit" short-circuits before alias resolution
- model_overrides still respected (checked first) for explicit IDs
- Installer sets resolve_model_ids: "omit" in ~/.gsd/defaults.json
  for non-Claude runtimes during install
- 4 new tests covering omit behavior and override passthrough
- Fix websearch test mocks for fs.writeSync output change (#1276)

Closes #1156

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-03-21 00:57:20 -04:00
parent 3f2c0a16e0
commit 02254db611
4 changed files with 63 additions and 8 deletions

View File

@@ -205,7 +205,7 @@ function loadConfig(cwd) {
exa_search: false,
text_mode: false, // when true, use plain-text numbered lists instead of AskUserQuestion menus
sub_repos: [],
resolve_model_ids: false, // when true, resolve aliases (opus/sonnet/haiku) to full model IDs
resolve_model_ids: false, // false: return alias as-is | true: map to full Claude model ID | "omit": return '' (runtime uses its default)
context_window: 200000, // default 200k; set to 1000000 for Opus/Sonnet 4.6 1M models
phase_naming: 'sequential', // 'sequential' (default, auto-increment) or 'custom' (arbitrary string IDs)
};
@@ -885,12 +885,20 @@ const MODEL_ALIAS_MAP = {
function resolveModelInternal(cwd, agentType) {
const config = loadConfig(cwd);
// Check per-agent override first
// Check per-agent override first — always respected regardless of resolve_model_ids.
// Users who set fully-qualified model IDs (e.g., "openai/gpt-5.4") get exactly that.
const override = config.model_overrides?.[agentType];
if (override) {
return override;
}
// resolve_model_ids: "omit" — return empty string so the runtime uses its configured
// default model. For non-Claude runtimes (OpenCode, Codex, etc.) that don't recognize
// Claude aliases (opus/sonnet/haiku/inherit). Set automatically during install. See #1156.
if (config.resolve_model_ids === 'omit') {
return '';
}
// Fall back to profile lookup
const profile = String(config.model_profile || 'balanced').toLowerCase();
const agentModels = MODEL_PROFILES[agentType];
@@ -898,8 +906,8 @@ function resolveModelInternal(cwd, agentType) {
if (profile === 'inherit') return 'inherit';
const alias = agentModels[profile] || agentModels['balanced'] || 'sonnet';
// If resolve_model_ids is true, map alias to full model ID
// This prevents 404s when the Task tool passes aliases directly to the API
// resolve_model_ids: true — map alias to full Claude model ID
// Prevents 404s when the Task tool passes aliases directly to the API
if (config.resolve_model_ids) {
return MODEL_ALIAS_MAP[alias] || alias;
}