From 6956ce0a19159ec74abe721d8473b978cd6499e5 Mon Sep 17 00:00:00 2001 From: Kenny Date: Sun, 18 Jan 2026 22:08:27 -0500 Subject: [PATCH] fix: correct config.data.model access pattern and use dynamic config paths - Fixed delegate-task/tools.ts to access openCodeConfig.data.model instead of openCodeConfig.model - Updated error messages to use getOpenCodeConfigPaths() for cross-platform paths - Fixed 12 test mocks to use correct { data: { model: ... } } structure - Fixes delegation failing with 'requires a default model' even when model is configured --- src/plugin-handlers/config-handler.ts | 4 +++- src/tools/delegate-task/tools.test.ts | 22 +++++++++++----------- src/tools/delegate-task/tools.ts | 12 +++++++++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/plugin-handlers/config-handler.ts b/src/plugin-handlers/config-handler.ts index fedc14de0..0149f177f 100644 --- a/src/plugin-handlers/config-handler.ts +++ b/src/plugin-handlers/config-handler.ts @@ -22,6 +22,7 @@ import { loadAllPluginComponents } from "../features/claude-code-plugin-loader"; import { createBuiltinMcps } from "../mcp"; import type { OhMyOpenCodeConfig } from "../config"; import { log } from "../shared"; +import { getOpenCodeConfigPaths } from "../shared/opencode-config-dir"; import { migrateAgentConfig } from "../shared/permission-compat"; import { PROMETHEUS_SYSTEM_PROMPT, PROMETHEUS_PERMISSION } from "../agents/prometheus-prompt"; import { DEFAULT_CATEGORIES } from "../tools/delegate-task/constants"; @@ -100,9 +101,10 @@ export function createConfigHandler(deps: ConfigHandlerDeps) { } if (!(config.model as string | undefined)?.trim()) { + const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null }) throw new Error( 'oh-my-opencode requires a default model.\n\n' + - 'Add this to ~/.config/opencode/opencode.jsonc:\n\n' + + `Add this to ${paths.configJsonc}:\n\n` + ' "model": "anthropic/claude-sonnet-4-5"\n\n' + '(Replace with your preferred provider/model)' ) diff --git a/src/tools/delegate-task/tools.test.ts b/src/tools/delegate-task/tools.test.ts index 423c50296..301ff3a59 100644 --- a/src/tools/delegate-task/tools.test.ts +++ b/src/tools/delegate-task/tools.test.ts @@ -125,7 +125,7 @@ describe("sisyphus-task", () => { ) // #then returns descriptive error message - expect(result).toContain("No default model configured") + expect(result).toContain("oh-my-opencode requires a default model") }) }) @@ -304,7 +304,7 @@ describe("sisyphus-task", () => { const mockClient = { app: { agents: async () => ({ data: [] }) }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, session: { create: async () => ({ data: { id: "test-session" } }), prompt: async () => ({ data: {} }), @@ -363,7 +363,7 @@ describe("sisyphus-task", () => { const mockManager = { launch: async () => ({}) } const mockClient = { app: { agents: async () => ({ data: [] }) }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, session: { create: async () => ({ data: { id: "test-session" } }), prompt: async () => ({ data: {} }), @@ -406,7 +406,7 @@ describe("sisyphus-task", () => { const mockManager = { launch: async () => ({}) } const mockClient = { app: { agents: async () => ({ data: [] }) }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, session: { create: async () => ({ data: { id: "test-session" } }), prompt: async () => ({ data: {} }), @@ -453,7 +453,7 @@ describe("sisyphus-task", () => { const mockManager = { launch: async () => ({}) } const mockClient = { app: { agents: async () => ({ data: [] }) }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, session: { get: async () => ({ data: { directory: "/project" } }), create: async () => ({ data: { id: "test-session" } }), @@ -528,7 +528,7 @@ describe("sisyphus-task", () => { ], }), }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, app: { agents: async () => ({ data: [] }), }, @@ -586,7 +586,7 @@ describe("sisyphus-task", () => { data: [], }), }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, } const tool = createDelegateTask({ @@ -638,7 +638,7 @@ describe("sisyphus-task", () => { messages: async () => ({ data: [] }), status: async () => ({ data: {} }), }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, app: { agents: async () => ({ data: [{ name: "ultrabrain", mode: "subagent" }] }), }, @@ -698,7 +698,7 @@ describe("sisyphus-task", () => { }), status: async () => ({ data: { "ses_sync_success": { type: "idle" } } }), }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, app: { agents: async () => ({ data: [{ name: "ultrabrain", mode: "subagent" }] }), }, @@ -751,7 +751,7 @@ describe("sisyphus-task", () => { messages: async () => ({ data: [] }), status: async () => ({ data: {} }), }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, app: { agents: async () => ({ data: [{ name: "ultrabrain", mode: "subagent" }] }), }, @@ -805,7 +805,7 @@ describe("sisyphus-task", () => { }), status: async () => ({ data: {} }), }, - config: { get: async () => ({ model: SYSTEM_DEFAULT_MODEL }) }, + config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, app: { agents: async () => ({ data: [] }) }, } diff --git a/src/tools/delegate-task/tools.ts b/src/tools/delegate-task/tools.ts index b55f4d4c4..110def28d 100644 --- a/src/tools/delegate-task/tools.ts +++ b/src/tools/delegate-task/tools.ts @@ -11,7 +11,7 @@ import { discoverSkills } from "../../features/opencode-skill-loader" import { getTaskToastManager } from "../../features/task-toast-manager" import type { ModelFallbackInfo } from "../../features/task-toast-manager/types" import { subagentSessions, getSessionAgent } from "../../features/claude-code-session-state" -import { log, getAgentToolRestrictions, resolveModel } from "../../shared" +import { log, getAgentToolRestrictions, resolveModel, getOpenCodeConfigPaths } from "../../shared" type OpencodeClient = PluginInput["client"] @@ -415,7 +415,7 @@ ${textContent || "(No text output)"}` let systemDefaultModel: string | undefined try { const openCodeConfig = await client.config.get() - systemDefaultModel = (openCodeConfig as { model?: string })?.model + systemDefaultModel = (openCodeConfig as { data?: { model?: string } })?.data?.model } catch { // Config fetch failed, proceed without system default systemDefaultModel = undefined @@ -434,7 +434,13 @@ ${textContent || "(No text output)"}` if (args.category) { // Guard: require system default model for category delegation if (!systemDefaultModel) { - return `No default model configured. Set a model in your OpenCode config (model field).` + const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null }) + return ( + 'oh-my-opencode requires a default model.\n\n' + + `Add this to ${paths.configJsonc}:\n\n` + + ' "model": "anthropic/claude-sonnet-4-5"\n\n' + + '(Replace with your preferred provider/model)' + ) } const resolved = resolveCategoryConfig(args.category, {