Skip to content

[BUG] Sub-session agents fail to resolve OpenRouter model IDs — no model/provider override in createAgentProvider() #23909

@Paatricious

Description

@Paatricious

Description

When sub-agents (explore, librarian, oracle, hephaestus, etc.) are spawned via the oh-my-openagent plugin, they fail to resolve OpenRouter model IDs (e.g. anthropic/claude-sonnet-4.6, google/gemini-3-flash) because createAgentProvider() performs a hardcoded lookup in models.SupportedModels using the agent's configured model ID. Sub-session agents are created with config.AgentTask (see agent-tool.go:57), which reads from config.Agents[AgentTask].Model — a static global config key, not the model/provider specified by the parent session or plugin.

The oh-my-openagent plugin calls promptAsync with model: { providerID: "openrouter", modelID: "anthropic/claude-sonnet-4.6" } in the request body. However, OpenCode's server-side agent creation completely ignores this field and instead uses the hardcoded AgentTask model from global config. This means:

  1. OpenRouter model IDs (e.g. anthropic/claude-sonnet-4.6) do not exist in models.SupportedModels — OpenCode uses its own prefixed IDs (e.g. openrouter.claude-3.5-sonnet, openrouter.gpt-4o)
  2. Even if the ID existed, createAgentProvider() at agent.go:712 does models.SupportedModels[agentConfig.Model] with no fallback or override mechanism
  3. The error manifests as "Provider returned error" (when model resolution partially succeeds but provider lookup fails) or "Missing Authentication header" (when the model can't be resolved at all and falls back to a broken provider)

Plugins

oh-my-openagent v3.17.4

OpenCode version

1.3.5 (may affect later versions too — root cause is in the model resolution code path)

Steps to reproduce

  1. Configure openrouter provider with a valid API key in opencode.json
  2. Set an agent's model to an OpenRouter model ID like anthropic/claude-sonnet-4.6 or google/gemini-3-flash
  3. Have the main agent (Sisyphus) spawn a sub-agent via oh-my-openagent's call_omo_agent tool
  4. Observe the sub-agent fails with "Provider returned error" or "Missing Authentication header"

Root Cause Analysis

File: internal/llm/agent/agent.go:706-757createAgentProvider()

func createAgentProvider(agentName config.AgentName) (provider.Provider, error) {
	cfg := config.Get()
	agentConfig, ok := cfg.Agents[agentName]
	if !ok {
		return nil, fmt.Errorf("agent %s not found", agentName)
	}
	model, ok := models.SupportedModels[agentConfig.Model]  // ← LINE 712: HARD LOOKUP
	if !ok {
		return nil, fmt.Errorf("model %s not supported", agentConfig.Model)
	}
	providerCfg, ok := cfg.Providers[model.Provider]
	if !ok {
		return nil, fmt.Errorf("provider %s not supported", model.Provider)
	}
	// ...
}

File: internal/llm/agent/agent-tool.go:57 — Sub-session creation

agent, err := NewAgent(config.AgentTask, b.sessions, b.messages, TaskAgentTools(b.lspClients))
// ↑ Uses AgentTask's hardcoded model from global config
// Does NOT accept or use any model/provider override from the caller

File: internal/llm/models/models.go:50-98SupportedModels

func init() {
	maps.Copy(SupportedModels, AnthropicModels)
	maps.Copy(SupportedModels, OpenAIModels)
	maps.Copy(SupportedModels, GeminiModels)
	maps.Copy(SupportedModels, OpenRouterModels)  // Uses prefixed IDs like "openrouter.gpt-4o"
	// ...
}

The OpenRouter models use prefixed IDs (e.g. "openrouter.gpt-4.1", "openrouter.claude-3.5-sonnet"), while oh-my-openagent sends raw OpenRouter IDs (e.g. "anthropic/claude-sonnet-4.6"). These don't match, so the lookup fails.

Key finding: No per-request model/provider override mechanism exists.

  • UpdateAgentModel() exists but is a one-time config mutation, not per-request
  • Agent struct has only Model, MaxTokens, ReasoningEffort — no override fields
  • The prompt body's model field is silently ignored by the server-side agent creation

Suggested Fix

Two possible approaches:

A) Add model/provider override to agent creation:

// In agent-tool.go, pass model override from the session context
agent, err := NewAgent(config.AgentTask, b.sessions, b.messages,
    TaskAgentTools(b.lspClients),
    TaskAgentModelOverride(overrideModelID)) // NEW: optional override

B) Add a model ID alias/translation layer:

  • When a model ID is not found in SupportedModels, attempt to match it against OpenRouter model definitions by comparing APIModel fields
  • E.g. "anthropic/claude-sonnet-4.6" → find OpenRouter model with matching APIModel

Operating System

Windows 11 24H2

Terminal

Windows Terminal

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions