diff --git a/assets/oh-my-opencode.schema.json b/assets/oh-my-opencode.schema.json index f0f6bf753..20f98e4f8 100644 --- a/assets/oh-my-opencode.schema.json +++ b/assets/oh-my-opencode.schema.json @@ -80,7 +80,6 @@ "non-interactive-env", "interactive-bash-session", "thinking-block-validator", - "ultrawork-model-override", "ralph-loop", "category-skill-reminder", "compaction-context-injector", @@ -279,21 +278,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -467,21 +451,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -655,21 +624,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -843,21 +797,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -1031,21 +970,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -1219,21 +1143,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -1407,21 +1316,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -1595,21 +1489,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -1783,21 +1662,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -1971,21 +1835,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -2159,21 +2008,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -2347,21 +2181,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -2535,21 +2354,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -2723,21 +2527,6 @@ ], "additionalProperties": false }, - "ultrawork": { - "type": "object", - "properties": { - "model": { - "type": "string" - }, - "variant": { - "type": "string" - } - }, - "required": [ - "model" - ], - "additionalProperties": false - }, "reasoningEffort": { "type": "string", "enum": [ @@ -3373,4 +3162,4 @@ } }, "additionalProperties": false -} \ No newline at end of file +} diff --git a/docs/guide/installation.md b/docs/guide/installation.md index f266a9907..051887c2d 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -68,15 +68,6 @@ Ask the user these questions to determine CLI options: **Provider Priority**: Native (anthropic/, openai/, google/) > GitHub Copilot > OpenCode Zen > Z.ai Coding Plan -#### Claude Subscription Model Assignments - -| Subscription | Sisyphus (Daily) | Ultrawork Mode | -| ------------ | ---------------- | -------------- | -| **max20** | `anthropic/claude-opus-4-6` (max) | Already on Opus — no override | -| **standard** | `anthropic/claude-sonnet-4-6` (max) | `anthropic/claude-opus-4-6` (max) | - -Standard Claude subscribers use Sonnet 4.6 for daily driving and automatically switch to Opus 4.6 when ultrawork mode is activated (by typing `ultrawork` or `ulw`). - MUST STRONGLY WARNING, WHEN USER SAID THEY DON'T HAVE CLAUDE SUBSCRIPTION, SISYPHUS AGENT MIGHT NOT WORK IDEALLY. ### Step 1: Install OpenCode (if not installed) diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index 580fc15e2..22e486a97 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -94,11 +94,7 @@ exports[`generateModelConfig single native provider uses Claude models when only "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-sonnet-4-6", - "ultrawork": { - "model": "anthropic/claude-opus-4-6", - "variant": "max", - }, + "model": "anthropic/claude-opus-4-6", "variant": "max", }, }, @@ -483,11 +479,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-sonnet-4-6", - "ultrawork": { - "model": "anthropic/claude-opus-4-6", - "variant": "max", - }, + "model": "anthropic/claude-opus-4-6", "variant": "max", }, }, @@ -1044,11 +1036,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-sonnet-4-6", - "ultrawork": { - "model": "anthropic/claude-opus-4-6", - "variant": "max", - }, + "model": "anthropic/claude-opus-4-6", "variant": "max", }, }, @@ -1192,11 +1180,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-sonnet-4-6", - "ultrawork": { - "model": "anthropic/claude-opus-4-6", - "variant": "max", - }, + "model": "anthropic/claude-opus-4-6", "variant": "max", }, }, @@ -1257,11 +1241,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-sonnet-4-6", - "ultrawork": { - "model": "anthropic/claude-opus-4-6", - "variant": "max", - }, + "model": "anthropic/claude-opus-4-6", "variant": "max", }, }, @@ -1405,11 +1385,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-sonnet-4-6", - "ultrawork": { - "model": "anthropic/claude-opus-4-6", - "variant": "max", - }, + "model": "anthropic/claude-opus-4-6", "variant": "max", }, }, diff --git a/src/cli/config-manager.test.ts b/src/cli/config-manager.test.ts index 1d6b0a071..922301226 100644 --- a/src/cli/config-manager.test.ts +++ b/src/cli/config-manager.test.ts @@ -240,52 +240,6 @@ describe("config-manager ANTIGRAVITY_PROVIDER_CONFIG", () => { }) describe("generateOmoConfig - model fallback system", () => { - test("generates sonnet model with ultrawork opus for Claude standard subscription", () => { - // #given user has Claude standard subscription (not max20) - const config: InstallConfig = { - hasClaude: true, - isMax20: false, - hasOpenAI: false, - hasGemini: false, - hasCopilot: false, - hasOpencodeZen: false, - hasZaiCodingPlan: false, - hasKimiForCoding: false, - } - - // #when generating config - const result = generateOmoConfig(config) - - // #then Sisyphus uses sonnet for daily driving with ultrawork opus override - const sisyphus = (result.agents as Record).sisyphus - expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json") - expect(sisyphus.model).toBe("anthropic/claude-sonnet-4-6") - expect(sisyphus.variant).toBe("max") - expect(sisyphus.ultrawork).toEqual({ model: "anthropic/claude-opus-4-6", variant: "max" }) - }) - - test("generates native opus models without ultrawork when Claude max20 subscription", () => { - // #given user has Claude max20 subscription - const config: InstallConfig = { - hasClaude: true, - isMax20: true, - hasOpenAI: false, - hasGemini: false, - hasCopilot: false, - hasOpencodeZen: false, - hasZaiCodingPlan: false, - hasKimiForCoding: false, - } - - // #when generating config - const result = generateOmoConfig(config) - - // #then Sisyphus uses opus directly, no ultrawork override needed - const sisyphus = (result.agents as Record).sisyphus - expect(sisyphus.model).toBe("anthropic/claude-opus-4-6") - expect(sisyphus.ultrawork).toBeUndefined() - }) - test("uses github-copilot sonnet fallback when only copilot available", () => { // #given user has only copilot (no max plan) const config: InstallConfig = { diff --git a/src/cli/model-fallback-types.ts b/src/cli/model-fallback-types.ts index 6f62a36fa..98dcab86e 100644 --- a/src/cli/model-fallback-types.ts +++ b/src/cli/model-fallback-types.ts @@ -11,15 +11,9 @@ export interface ProviderAvailability { isMaxPlan: boolean } -export interface UltraworkConfig { - model: string - variant?: string -} - export interface AgentConfig { model: string variant?: string - ultrawork?: UltraworkConfig } export interface CategoryConfig { diff --git a/src/cli/model-fallback.ts b/src/cli/model-fallback.ts index bca8d3b44..34076eb6a 100644 --- a/src/cli/model-fallback.ts +++ b/src/cli/model-fallback.ts @@ -76,15 +76,6 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { continue } - if (avail.native.claude && !avail.isMaxPlan) { - agents[role] = { - model: "anthropic/claude-sonnet-4-6", - variant: "max", - ultrawork: { model: "anthropic/claude-opus-4-6", variant: "max" }, - } - continue - } - const resolved = resolveModelFromChain(fallbackChain, avail) if (resolved) { const variant = resolved.variant ?? req.variant diff --git a/src/config/schema/agent-overrides.ts b/src/config/schema/agent-overrides.ts index 0abcb5c90..876560ec6 100644 --- a/src/config/schema/agent-overrides.ts +++ b/src/config/schema/agent-overrides.ts @@ -32,11 +32,6 @@ export const AgentOverrideConfigSchema = z.object({ budgetTokens: z.number().optional(), }) .optional(), - /** Ultrawork model override configuration. */ - ultrawork: z.object({ - model: z.string(), - variant: z.string().optional(), - }).optional(), /** Reasoning effort level (OpenAI). Overrides category and default settings. */ reasoningEffort: z.enum(["low", "medium", "high", "xhigh"]).optional(), /** Text verbosity level. */ diff --git a/src/config/schema/hooks.ts b/src/config/schema/hooks.ts index 868b8ffcd..cf3d5009b 100644 --- a/src/config/schema/hooks.ts +++ b/src/config/schema/hooks.ts @@ -25,7 +25,6 @@ export const HookNameSchema = z.enum([ "interactive-bash-session", "thinking-block-validator", - "ultrawork-model-override", "ralph-loop", "category-skill-reminder", diff --git a/src/hooks/index.ts b/src/hooks/index.ts index f34e92708..950cc9745 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -47,4 +47,3 @@ export { createTasksTodowriteDisablerHook } from "./tasks-todowrite-disabler"; export { createWriteExistingFileGuardHook } from "./write-existing-file-guard"; export { createHashlineReadEnhancerHook } from "./hashline-read-enhancer"; -export { createUltraworkModelOverrideHook } from "./ultrawork-model-override"; diff --git a/src/hooks/ultrawork-model-override/hook.test.ts b/src/hooks/ultrawork-model-override/hook.test.ts deleted file mode 100644 index 66bf2478e..000000000 --- a/src/hooks/ultrawork-model-override/hook.test.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { describe, expect, it } from "vitest" -import { createUltraworkModelOverrideHook } from "./hook" - -interface ChatParamsInput { - agent: string - message: { - variant: string - model?: { providerID?: string; modelID?: string } - } - sessionID?: string -} - -interface ChatParamsOutput { - // Not used by this hook -} - -function createMockParams(overrides: { - agent?: string - variant?: string - model?: { providerID?: string; modelID?: string } - sessionID?: string -}): { input: ChatParamsInput; output: ChatParamsOutput } { - const agent = overrides.agent ?? "sisyphus" - const variant = overrides.variant ?? "max" - const model = overrides.model - const sessionID = overrides.sessionID - - return { - input: { - agent, - message: { variant, model }, - sessionID, - }, - output: {}, - } -} - -describe("createUltraworkModelOverrideHook", () => { - describe("model swap works", () => { - it("variant max, ultrawork config exists → model swapped", async () => { - // given - const agents = { - sisyphus: { - ultrawork: { - model: "openai/gpt-5.2", - }, - }, - } - const hook = createUltraworkModelOverrideHook({ agents }) - const { input, output } = createMockParams({}) - - // when - await hook["chat.params"](input, output) - - // then - expect(input.message.model).toEqual({ - providerID: "openai", - modelID: "gpt-5.2", - }) - }) - }) - - describe("no-op on non-max variant", () => { - it("variant high → model unchanged", async () => { - // given - const agents = { - sisyphus: { - ultrawork: { - model: "openai/gpt-5.2", - }, - }, - } - const hook = createUltraworkModelOverrideHook({ agents }) - const { input, output } = createMockParams({ variant: "high" }) - - // when - await hook["chat.params"](input, output) - - // then - expect(input.message.model).toBeUndefined() - }) - }) - - describe("no-op without config", () => { - it("agent has no ultrawork config → model unchanged", async () => { - // given - const agents = { - hephaestus: { - ultrawork: { - model: "openai/gpt-5.2", - }, - }, - } - const hook = createUltraworkModelOverrideHook({ agents }) - const { input, output } = createMockParams({}) - - // when - await hook["chat.params"](input, output) - - // then - expect(input.message.model).toBeUndefined() - }) - }) - - describe("empty ultrawork config", () => { - it("ultrawork: {} → no-op (model required)", async () => { - // given - const agents = { - sisyphus: { - ultrawork: undefined, - }, - } - const hook = createUltraworkModelOverrideHook({ agents }) - const { input, output } = createMockParams({}) - - // when - await hook["chat.params"](input, output) - - // then - expect(input.message.model).toBeUndefined() - }) - }) - - describe("model string parsing", () => { - it("openai/gpt-5.2 → { providerID: openai, modelID: gpt-5.2 }", async () => { - // given - const agents = { - sisyphus: { - ultrawork: { - model: "openai/gpt-5.2", - }, - }, - } - const hook = createUltraworkModelOverrideHook({ agents }) - const { input, output } = createMockParams({}) - - // when - await hook["chat.params"](input, output) - - // then - expect(input.message.model).toEqual({ - providerID: "openai", - modelID: "gpt-5.2", - }) - }) - }) - - describe("nested slashes", () => { - it("google-vertex-anthropic/claude-opus-4-6 → { providerID: google-vertex-anthropic, modelID: claude-opus-4-6 } (first / only)", async () => { - // given - const agents = { - sisyphus: { - ultrawork: { - model: "google-vertex-anthropic/claude-opus-4-6", - }, - }, - } - const hook = createUltraworkModelOverrideHook({ agents }) - const { input, output } = createMockParams({}) - - // when - await hook["chat.params"](input, output) - - // then - expect(input.message.model).toEqual({ - providerID: "google-vertex-anthropic", - modelID: "claude-opus-4-6", - }) - }) - }) - - describe("variant override", () => { - it("ultrawork.variant exists → message.variant updated", async () => { - // given - const agents = { - sisyphus: { - ultrawork: { - model: "openai/gpt-5.2", - variant: "high", - }, - }, - } - const hook = createUltraworkModelOverrideHook({ agents }) - const { input, output } = createMockParams({}) - - // when - await hook["chat.params"](input, output) - - // then - expect(input.message.variant).toBe("high") - }) - }) - - describe("agent name normalization", () => { - it("Sisyphus (Ultraworker) → sisyphus config key lookup", async () => { - // given - const agents = { - sisyphus: { - ultrawork: { - model: "openai/gpt-5.2", - }, - }, - } - const hook = createUltraworkModelOverrideHook({ agents }) - const { input, output } = createMockParams({ agent: "Sisyphus (Ultraworker)" }) - - // when - await hook["chat.params"](input, output) - - // then - expect(input.message.model).toEqual({ - providerID: "openai", - modelID: "gpt-5.2", - }) - }) - }) -}) \ No newline at end of file diff --git a/src/hooks/ultrawork-model-override/hook.ts b/src/hooks/ultrawork-model-override/hook.ts deleted file mode 100644 index cc14f9ebc..000000000 --- a/src/hooks/ultrawork-model-override/hook.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { AgentOverrides } from "../../config" -import { log } from "../../shared" -import { getAgentConfigKey } from "../../shared/agent-display-names" - -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null -} - -function getUltraworkConfig(agents: AgentOverrides | undefined, configKey: string) { - if (!agents) return undefined - - for (const [agentKey, override] of Object.entries(agents)) { - if (getAgentConfigKey(agentKey) === configKey) { - return override?.ultrawork - } - } - - return undefined -} - -export function createUltraworkModelOverrideHook(args: { agents?: AgentOverrides }) { - let didLogSpikeInput = false - - return { - "chat.params": async (input: unknown, output: unknown): Promise => { - if (!didLogSpikeInput) { - didLogSpikeInput = true - - const inputRecord = isRecord(input) ? input : null - const messageRecord = isRecord(inputRecord?.message) ? inputRecord.message : null - - log("ultrawork-model-override spike: raw chat.params input", { - inputType: typeof input, - outputType: typeof output, - hasMessage: messageRecord !== null, - messageKeys: messageRecord ? Object.keys(messageRecord) : [], - hasMessageModel: messageRecord ? "model" in messageRecord : false, - messageModelType: messageRecord ? typeof messageRecord.model : "undefined", - }) - } - - if (!isRecord(input)) return - - const message = input.message - if (!isRecord(message)) return - if (message.variant !== "max") return - - const agentName = input.agent - if (typeof agentName !== "string") return - - const configKey = getAgentConfigKey(agentName) - const ultrawork = getUltraworkConfig(args.agents, configKey) - if (!ultrawork?.model) return - - const separatorIndex = ultrawork.model.indexOf("/") - const providerID = separatorIndex === -1 ? ultrawork.model : ultrawork.model.slice(0, separatorIndex) - const modelID = separatorIndex === -1 ? "" : ultrawork.model.slice(separatorIndex + 1) - - const previousModel = isRecord(message.model) - ? { - providerID: - typeof message.model.providerID === "string" ? message.model.providerID : undefined, - modelID: typeof message.model.modelID === "string" ? message.model.modelID : undefined, - } - : undefined - - message.model = { providerID, modelID } - - if (ultrawork.variant !== undefined) { - message.variant = ultrawork.variant - } - - log("ultrawork-model-override: swapped model", { - sessionID: typeof input.sessionID === "string" ? input.sessionID : undefined, - agent: agentName, - configKey, - from: previousModel, - to: message.model, - variant: message.variant, - }) - }, - } -} diff --git a/src/hooks/ultrawork-model-override/index.ts b/src/hooks/ultrawork-model-override/index.ts deleted file mode 100644 index 32794e94c..000000000 --- a/src/hooks/ultrawork-model-override/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { createUltraworkModelOverrideHook } from "./hook" diff --git a/src/plugin-interface.ts b/src/plugin-interface.ts index e0ea2e8dd..0bc24ddae 100644 --- a/src/plugin-interface.ts +++ b/src/plugin-interface.ts @@ -31,7 +31,6 @@ export function createPluginInterface(args: { tool: tools, "chat.params": async (input, output) => { - await hooks.ultraworkModelOverride?.["chat.params"]?.(input, output) const handler = createChatParamsHandler({ anthropicEffort: hooks.anthropicEffort }) await handler(input, output) }, diff --git a/src/plugin/hooks/create-session-hooks.ts b/src/plugin/hooks/create-session-hooks.ts index 4d3a66ed3..f7047a90a 100644 --- a/src/plugin/hooks/create-session-hooks.ts +++ b/src/plugin/hooks/create-session-hooks.ts @@ -25,7 +25,6 @@ import { createPreemptiveCompactionHook, } from "../../hooks" import { createAnthropicEffortHook } from "../../hooks/anthropic-effort" -import { createUltraworkModelOverrideHook } from "../../hooks/ultrawork-model-override" import { detectExternalNotificationPlugin, getNotificationConflictWarning, @@ -56,7 +55,6 @@ export type SessionHooks = { questionLabelTruncator: ReturnType taskResumeInfo: ReturnType anthropicEffort: ReturnType | null - ultraworkModelOverride: ReturnType | null } export function createSessionHooks(args: { @@ -171,10 +169,6 @@ export function createSessionHooks(args: { ? safeHook("anthropic-effort", () => createAnthropicEffortHook()) : null - const ultraworkModelOverride = isHookEnabled("ultrawork-model-override") - ? safeHook("ultrawork-model-override", () => createUltraworkModelOverrideHook({ agents: pluginConfig.agents })) - : null - return { contextWindowMonitor, preemptiveCompaction, @@ -197,6 +191,5 @@ export function createSessionHooks(args: { questionLabelTruncator, taskResumeInfo, anthropicEffort, - ultraworkModelOverride, } }