Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,279 changes: 3,278 additions & 1 deletion assets/oh-my-opencode.schema.json

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions script/build-schema.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#!/usr/bin/env bun
import * as z from "zod"
import { zodToJsonSchema } from "zod-to-json-schema"
import { OhMyOpenCodeConfigSchema } from "../src/config/schema"

const SCHEMA_OUTPUT_PATH = "assets/oh-my-opencode.schema.json"

async function main() {
console.log("Generating JSON Schema...")

const jsonSchema = zodToJsonSchema(OhMyOpenCodeConfigSchema, {
target: "draft7",
const jsonSchema = z.toJSONSchema(OhMyOpenCodeConfigSchema, {
io: "input",
target: "draft-7",
})

const finalSchema = {
Expand Down
9 changes: 7 additions & 2 deletions src/agents/agent-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { CategoriesConfig, CategoryConfig, GitMasterConfig } from "../confi
import type { BrowserAutomationProvider } from "../config/schema"
import { mergeCategories } from "../shared/merge-categories"
import { resolveMultipleSkills } from "../features/opencode-skill-loader/skill-content"
import { getActiveModel } from "../features/model-switcher"

export type AgentSource = AgentFactory | AgentConfig

Expand All @@ -17,9 +18,13 @@ export function buildAgent(
categories?: CategoriesConfig,
gitMasterConfig?: GitMasterConfig,
browserProvider?: BrowserAutomationProvider,
disabledSkills?: Set<string>
disabledSkills?: Set<string>,
agentName?: string
): AgentConfig {
const base = isFactory(source) ? source(model) : { ...source }
const activeModel = agentName ? getActiveModel(agentName) : undefined
const effectiveModel = activeModel ?? model

const base = isFactory(source) ? source(effectiveModel) : { ...source }
const categoryConfigs: Record<string, CategoryConfig> = mergeCategories(categories)

const agentWithCategory = base as AgentConfig & { category?: string; skills?: string[]; variant?: string }
Expand Down
7 changes: 6 additions & 1 deletion src/agents/atlas/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { buildCategorySkillsDelegationGuide } from "../dynamic-agent-prompt-buil
import type { CategoryConfig } from "../../config/schema"
import { mergeCategories } from "../../shared/merge-categories"
import { createAgentToolRestrictions } from "../../shared/permission-compat"
import { getActiveModel } from "../../features/model-switcher"

import { getDefaultAtlasPrompt } from "./default"
import { getGptAtlasPrompt } from "./gpt"
Expand Down Expand Up @@ -47,6 +48,7 @@ export interface OrchestratorContext {
availableAgents?: AvailableAgent[]
availableSkills?: AvailableSkill[]
userCategories?: Record<string, CategoryConfig>
agentName?: string
}

/**
Expand Down Expand Up @@ -93,6 +95,9 @@ function buildDynamicOrchestratorPrompt(ctx?: OrchestratorContext): string {
}

export function createAtlasAgent(ctx: OrchestratorContext): AgentConfig {
const activeModel = ctx.agentName ? getActiveModel(ctx.agentName) : undefined
const effectiveModel = activeModel ?? ctx.model

const restrictions = createAgentToolRestrictions([
"task",
"call_omo_agent",
Expand All @@ -102,7 +107,7 @@ export function createAtlasAgent(ctx: OrchestratorContext): AgentConfig {
description:
"Orchestrates work via task() to complete ALL tasks in a todo list until fully done. (Atlas - OhMyOpenCode)",
mode: MODE,
...(ctx.model ? { model: ctx.model } : {}),
...(effectiveModel ? { model: effectiveModel } : {}),
temperature: 0.1,
prompt: buildDynamicOrchestratorPrompt(ctx),
color: "#10B981",
Expand Down
3 changes: 3 additions & 0 deletions src/agents/builtin-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { maybeCreateSisyphusConfig } from "./builtin-agents/sisyphus-agent"
import { maybeCreateHephaestusConfig } from "./builtin-agents/hephaestus-agent"
import { maybeCreateAtlasConfig } from "./builtin-agents/atlas-agent"
import { buildCustomAgentMetadata, parseRegisteredAgentSummaries } from "./custom-agent-summaries"
import { loadCandidates } from "../features/model-switcher"

type AgentSource = AgentFactory | AgentConfig

Expand Down Expand Up @@ -67,6 +68,8 @@ export async function createBuiltinAgents(
disabledSkills?: Set<string>,
useTaskSystem = false
): Promise<Record<string, AgentConfig>> {
loadCandidates(agentOverrides)

const connectedProviders = readConnectedProvidersCache()
// IMPORTANT: Do NOT call OpenCode client APIs during plugin initialization.
// This function is called from config handler, and calling client API causes deadlock.
Expand Down
1 change: 1 addition & 0 deletions src/agents/builtin-agents/atlas-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export function maybeCreateAtlasConfig(input: {
availableAgents,
availableSkills,
userCategories,
agentName: "atlas",
})

if (atlasResolvedVariant) {
Expand Down
2 changes: 1 addition & 1 deletion src/agents/builtin-agents/general-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function collectPendingBuiltinAgents(input: {
if (!resolution) continue
const { model, variant: resolvedVariant } = resolution

let config = buildAgent(source, model, mergedCategories, gitMasterConfig, browserProvider, disabledSkills)
let config = buildAgent(source, model, mergedCategories, gitMasterConfig, browserProvider, disabledSkills, agentName)

// Apply resolved variant from model fallback chain
if (resolvedVariant) {
Expand Down
3 changes: 2 additions & 1 deletion src/agents/builtin-agents/hephaestus-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export function maybeCreateHephaestusConfig(input: {
undefined,
availableSkills,
availableCategories,
useTaskSystem
useTaskSystem,
"hephaestus"
)

hephaestusConfig = { ...hephaestusConfig, variant: hephaestusResolvedVariant ?? "medium" }
Expand Down
3 changes: 2 additions & 1 deletion src/agents/builtin-agents/sisyphus-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ export function maybeCreateSisyphusConfig(input: {
undefined,
availableSkills,
availableCategories,
useTaskSystem
useTaskSystem,
"sisyphus"
)

if (sisyphusResolvedVariant) {
Expand Down
7 changes: 5 additions & 2 deletions src/agents/hephaestus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
buildAntiPatternsSection,
categorizeTools,
} from "./dynamic-agent-prompt-builder"
import { getActiveModel } from "../features/model-switcher"

const MODE: AgentMode = "primary"

Expand Down Expand Up @@ -600,8 +601,10 @@ export function createHephaestusAgent(
availableToolNames?: string[],
availableSkills?: AvailableSkill[],
availableCategories?: AvailableCategory[],
useTaskSystem = false
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

const tools = availableToolNames ? categorizeTools(availableToolNames) : []
const skills = availableSkills ?? []
const categories = availableCategories ?? []
Expand All @@ -613,7 +616,7 @@ export function createHephaestusAgent(
description:
"Autonomous Deep Worker - goal-oriented execution with GPT 5.2 Codex. Explores thoroughly before acting, uses explore/librarian agents for comprehensive context, completes tasks end-to-end. Inspired by AmpCode deep mode. (Hephaestus - OhMyOpenCode)",
mode: MODE,
model,
model: effectiveModel,
maxTokens: 32000,
prompt,
color: "#D97706", // Forged Amber - Golden heated metal, divine craftsman
Expand Down
7 changes: 5 additions & 2 deletions src/agents/sisyphus.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AgentConfig } from "@opencode-ai/sdk"
import type { AgentMode, AgentPromptMetadata } from "./types"
import { isGptModel } from "./types"
import { getActiveModel } from "../features/model-switcher"

const MODE: AgentMode = "primary"
export const SISYPHUS_PROMPT_METADATA: AgentPromptMetadata = {
Expand Down Expand Up @@ -506,8 +507,10 @@ export function createSisyphusAgent(
availableToolNames?: string[],
availableSkills?: AvailableSkill[],
availableCategories?: AvailableCategory[],
useTaskSystem = false
useTaskSystem = false,
agentName?: string
): AgentConfig {
const effectiveModel = agentName ? getActiveModel(agentName) ?? model : model
const tools = availableToolNames ? categorizeTools(availableToolNames) : []
const skills = availableSkills ?? []
const categories = availableCategories ?? []
Expand All @@ -520,7 +523,7 @@ export function createSisyphusAgent(
description:
"Powerful AI orchestrator. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically via category+skills combinations. Uses explore for internal code (parallel-friendly), librarian for external docs. (Sisyphus - OhMyOpenCode)",
mode: MODE,
model,
model: effectiveModel,
maxTokens: 64000,
prompt,
color: "#00CED1",
Expand Down
2 changes: 2 additions & 0 deletions src/config/schema/agent-overrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export const AgentOverrideConfigSchema = z.object({
textVerbosity: z.enum(["low", "medium", "high"]).optional(),
/** Provider-specific options. Passed directly to OpenCode SDK. */
providerOptions: z.record(z.string(), z.unknown()).optional(),
/** Model candidates for fallback selection. */
model_candidates: z.array(z.string()).optional(),
})

export const AgentOverridesSchema = z.object({
Expand Down
2 changes: 2 additions & 0 deletions src/config/schema/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const BuiltinCommandNameSchema = z.enum([
"refactor",
"start-work",
"stop-continuation",
"handoff",
"switch-model",
])

export type BuiltinCommandName = z.infer<typeof BuiltinCommandNameSchema>
17 changes: 17 additions & 0 deletions src/features/builtin-commands/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { STOP_CONTINUATION_TEMPLATE } from "./templates/stop-continuation"
import { REFACTOR_TEMPLATE } from "./templates/refactor"
import { START_WORK_TEMPLATE } from "./templates/start-work"
import { HANDOFF_TEMPLATE } from "./templates/handoff"
import { SWITCH_MODEL_TEMPLATE } from "./templates/switch-model"

const BUILTIN_COMMAND_DEFINITIONS: Record<BuiltinCommandName, Omit<CommandDefinition, "name">> = {
"init-deep": {
Expand Down Expand Up @@ -94,6 +95,22 @@ $ARGUMENTS
</user-request>`,
argumentHint: "[goal]",
},
"switch-model": {
description: "(builtin) Switch the active LLM model for a specific agent in the current session",
template: `<command-instruction>
${SWITCH_MODEL_TEMPLATE}
</command-instruction>

<session-context>
Session ID: $SESSION_ID
Timestamp: $TIMESTAMP
</session-context>

<user-request>
$ARGUMENTS
</user-request>`,
argumentHint: "[agent] [model]",
},
}

export function loadBuiltinCommands(
Expand Down
Loading
Loading