Skip to content

Conversation

@singbong
Copy link

@singbong singbong commented Feb 11, 2026

Problem

Currently, changing an agent's LLM model requires:

  1. Manually editing oh-my-opencode.json configuration file
  2. Restarting the OpenCode session to apply changes

This workflow is inefficient and disrupts the development flow, especially when experimenting with different models during a session.

Solution

Added a new configuration field model_candidates to agent overrides and a builtin slash command /switch-model that enables runtime model switching within an active session.

New Configuration: model_candidates

Each agent can now define a list of alternative models:

{
  "agents": {
    "sisyphus": {
      "model": "zai-coding-plan/glm-4.7",
      "model_candidates": [
        "zai-coding-plan/glm-4.7",
        "google/antigravity-claude-opus-4-6-thinking",
        "cursor-acp/gpt-5.2"
      ]
    },
    "oracle": {
      "model_candidates": ["claude-3-5-opus", "claude-3-7-sonnet"]
    }
  }
}

New Command: /switch-model

The /switch-model command provides:

  1. /switch-model - Show current model assignments for all agents
  2. /switch-model <agent-name> - Show available model candidates for a specific agent
  3. /switch-model <agent-name> <model-id> - Immediately switch the agent to the specified model

Example usage:

/switch-model sisyphus
/switch-model sisyphus google/antigravity-claude-opus-4-6-thinking

Implementation Details

Schema Changes

  • Added model_candidates: z.array(z.string()).optional() to AgentOverrideConfigSchema
  • Added "switch-model" to BuiltinCommandNameSchema enum

Core Architecture

  • Created src/features/model-switcher/state.ts with singleton pattern for runtime state management
  • Implemented loadCandidates(), setActiveModel(), getActiveModel(), getCandidates(), getCurrentModelInfo()
  • Integrated with buildAgent() to apply model overrides during agent creation

Agent Integration

  • Modified createSisyphusAgent(), createHephaestusAgent(), createAtlasAgent() to accept agentName parameter
  • Core agents now use getActiveModel(agentName) for model selection
  • Model switching is session-scoped (in-memory only, no config file modification)

Command Implementation

  • Added /switch-model builtin command with detailed usage instructions
  • Template includes model switching logic and validation

Breaking Changes

None. The model_candidates field is optional, so existing configurations without it continue to work as before.

Testing

  • All unit tests passing (12 tests)
  • Type checking passes
  • Clean build succeeds
  • JSON schema generated correctly

Usage

  1. Add model_candidates to your agent configuration in oh-my-opencode.json
  2. Start an OpenCode session
  3. Use /switch-model <agent-name> <model-id> to change the active model
  4. The new model takes effect for the next message in the current session

Summary by cubic

Add runtime model switching for agents via an optional model_candidates config and a new /switch-model command. This lets you change an agent’s LLM during a session without editing config or restarting.

  • New Features

    • Added model_candidates to agent overrides (optional, included in JSON schema).
    • New /switch-model command:
      • No args: show current models for all agents.
      • : list that agent’s candidates.
      • : switch immediately (validated against candidates).
    • Session-scoped state (in-memory) with getActiveModel/setActiveModel/loadCandidates APIs.
    • Integrated with Sisyphus, Hephaestus, Atlas, and agent builder; agentName is passed so active overrides apply at creation.
  • Migration

    • Optional: add model_candidates to oh-my-opencode.json, start a session, then use /switch-model .
    • Changes are session-only and do not modify the config.
    • Backward compatible: if model_candidates isn’t set, existing behavior stays the same.

Written for commit 530a571. Summary will update on new commits.

- Added model_candidates: z.array(z.string()).optional() to AgentOverrideConfigSchema
- Updated JSON schema generation (build-schema.ts uses correct Zod 4 method)
- Maintains backward compatibility (field is optional)
- JSON schema now includes model_candidates field

Preparation for Task 3: Runtime state management module
…l override

- createSisyphusAgent: add agentName?: string parameter
- createHephaestusAgent: add agentName?: string parameter
- createAtlasAgent: add agentName to OrchestratorContext
- Each create function uses getActiveModel(agentName) for override
- Builtin-agents pass agentName when creating agents

This enables runtime model switching for Sisyphus, Hephaestus, and Atlas
through getActiveModel() integration with the model-switcher state module.
- Add switch-model command template with model switching instructions
- Update BuiltinCommandName type to include 'switch-model'
- Update BuiltinCommandNameSchema enum to include 'switch-model'
- Add switch-model to BUILTIN_COMMAND_DEFINITIONS with argumentHint

The command provides:
- Current model assignments display for all agents
- Model candidates listing for specific agents
- Model switching instructions
- Validation for model candidates
- Clear error messages for invalid models

Template includes detailed instructions for parsing arguments,
getting current model info, validating inputs, and performing
model switches using model-switcher APIs.
- Test loadCandidates() parsing with/without/empty model_candidates
- Test setActiveModel() and getActiveModel() override functionality
- Test getCandidates() and getCurrentModelInfo() state queries
- Test backward compatibility (config without model_candidates)
- Test invalid agent name handling
- 12 test cases all passing

Tests use unique agent names to avoid singleton state interference
between test cases.
@github-actions
Copy link
Contributor

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA).

To sign the CLA, please comment on this PR with:

I have read the CLA Document and I hereby sign the CLA

This is a one-time requirement. Once signed, all your future contributions will be automatically accepted.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 25 files

Confidence score: 3/5

  • Test pollution risk in src/features/model-switcher/model-switcher.test.ts could cause flaky or misleading test results due to shared state between blocks.
  • Runtime model switching may not take effect until restart because src/agents/hephaestus.ts caches model configuration after initialization, which is a concrete user-facing behavior risk.
  • Given the medium severity issues (6–7/10) impacting runtime behavior and test reliability, this is a moderate-risk merge.
  • Pay close attention to src/agents/hephaestus.ts, src/features/model-switcher/model-switcher.test.ts, test-zod4.ts - stale model config, shared-state tests, and accidental experimental file inclusion.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/features/model-switcher/model-switcher.test.ts">

<violation number="1" location="src/features/model-switcher/model-switcher.test.ts:78">
P1: Test pollution due to shared state dependency between test blocks</violation>
</file>

<file name="src/agents/hephaestus.ts">

<violation number="1" location="src/agents/hephaestus.ts:607">
P2: Model configuration becomes stale after agent initialization - runtime model switching may not take effect until agent restart</violation>
</file>

<file name="test-zod4.ts">

<violation number="1" location="test-zod4.ts:1">
P2: Accidental inclusion of temporary experimental file `test-zod4.ts`</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

})
})

describe("Candidate retrieval", () => {
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Test pollution due to shared state dependency between test blocks

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/model-switcher/model-switcher.test.ts, line 78:

<comment>Test pollution due to shared state dependency between test blocks</comment>

<file context>
@@ -0,0 +1,169 @@
+    })
+  })
+
+  describe("Candidate retrieval", () => {
+    test("should return candidates array for agent with candidates", () => {
+      const candidates = getCandidates("test_agent_3")
</file context>
Fix with Cubic

useTaskSystem = false,
agentName?: string
): AgentConfig {
const effectiveModel = agentName ? getActiveModel(agentName) ?? model : model
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Model configuration becomes stale after agent initialization - runtime model switching may not take effect until agent restart

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/agents/hephaestus.ts, line 607:

<comment>Model configuration becomes stale after agent initialization - runtime model switching may not take effect until agent restart</comment>

<file context>
@@ -600,8 +601,10 @@ export function createHephaestusAgent(
+  useTaskSystem = false,
+  agentName?: string
 ): AgentConfig {
+  const effectiveModel = agentName ? getActiveModel(agentName) ?? model : model
   const tools = availableToolNames ? categorizeTools(availableToolNames) : []
   const skills = availableSkills ?? []
</file context>
Fix with Cubic

@@ -0,0 +1,15 @@
import { z } from "zod"
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Accidental inclusion of temporary experimental file test-zod4.ts

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At test-zod4.ts, line 1:

<comment>Accidental inclusion of temporary experimental file `test-zod4.ts`</comment>

<file context>
@@ -0,0 +1,15 @@
+import { z } from "zod"
+
+const testSchema = z.object({
</file context>
Fix with Cubic

@singbong
Copy link
Author

Closing this PR. Will create a new PR for auth-connected model filtering feature.

@singbong singbong closed this Feb 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant