diff --git a/src/plugin/tool-registry.ts b/src/plugin/tool-registry.ts index 7236ddc489..162b81ed77 100644 --- a/src/plugin/tool-registry.ts +++ b/src/plugin/tool-registry.ts @@ -48,7 +48,7 @@ export function createToolRegistry(args: { const { ctx, pluginConfig, managers, skillContext, availableCategories } = args const backgroundTools = createBackgroundTools(managers.backgroundManager, ctx.client) - const callOmoAgent = createCallOmoAgent(ctx, managers.backgroundManager) + const callOmoAgent = createCallOmoAgent(ctx, managers.backgroundManager, pluginConfig.disabled_agents ?? []) const isMultimodalLookerEnabled = !(pluginConfig.disabled_agents ?? []).some( (agent) => agent.toLowerCase() === "multimodal-looker", diff --git a/src/tools/call-omo-agent/tools.test.ts b/src/tools/call-omo-agent/tools.test.ts new file mode 100644 index 0000000000..a560c8bead --- /dev/null +++ b/src/tools/call-omo-agent/tools.test.ts @@ -0,0 +1,102 @@ +import { describe, test, expect, mock } from "bun:test" +import type { PluginInput } from "@opencode-ai/plugin" +import type { BackgroundManager } from "../../features/background-agent" +import { createCallOmoAgent } from "./tools" + +describe("createCallOmoAgent", () => { + const mockCtx = { + client: {}, + directory: "/test", + } as unknown as PluginInput + + const mockBackgroundManager = { + launch: mock(() => Promise.resolve({ + id: "test-task-id", + sessionID: null, + description: "Test task", + agent: "test-agent", + status: "pending", + })), + } as unknown as BackgroundManager + + test("should reject agent in disabled_agents list", async () => { + //#given + const toolDef = createCallOmoAgent(mockCtx, mockBackgroundManager, ["explore"]) + const executeFunc = toolDef.execute as Function + + //#when + const result = await executeFunc( + { + description: "Test", + prompt: "Test prompt", + subagent_type: "explore", + run_in_background: true, + }, + { sessionID: "test", messageID: "msg", agent: "test", abort: new AbortController().signal } + ) + + //#then + expect(result).toContain("disabled via disabled_agents") + }) + + test("should reject agent in disabled_agents list with case-insensitive matching", async () => { + //#given + const toolDef = createCallOmoAgent(mockCtx, mockBackgroundManager, ["Explore"]) + const executeFunc = toolDef.execute as Function + + //#when + const result = await executeFunc( + { + description: "Test", + prompt: "Test prompt", + subagent_type: "explore", + run_in_background: true, + }, + { sessionID: "test", messageID: "msg", agent: "test", abort: new AbortController().signal } + ) + + //#then + expect(result).toContain("disabled via disabled_agents") + }) + + test("should allow agent not in disabled_agents list", async () => { + //#given + const toolDef = createCallOmoAgent(mockCtx, mockBackgroundManager, ["librarian"]) + const executeFunc = toolDef.execute as Function + + //#when + const result = await executeFunc( + { + description: "Test", + prompt: "Test prompt", + subagent_type: "explore", + run_in_background: true, + }, + { sessionID: "test", messageID: "msg", agent: "test", abort: new AbortController().signal } + ) + + //#then + // Should not contain disabled error - may fail for other reasons but disabled check should pass + expect(result).not.toContain("disabled via disabled_agents") + }) + + test("should allow all agents when disabled_agents is empty", async () => { + //#given + const toolDef = createCallOmoAgent(mockCtx, mockBackgroundManager, []) + const executeFunc = toolDef.execute as Function + + //#when + const result = await executeFunc( + { + description: "Test", + prompt: "Test prompt", + subagent_type: "explore", + run_in_background: true, + }, + { sessionID: "test", messageID: "msg", agent: "test", abort: new AbortController().signal } + ) + + //#then + expect(result).not.toContain("disabled via disabled_agents") + }) +}) diff --git a/src/tools/call-omo-agent/tools.ts b/src/tools/call-omo-agent/tools.ts index dbcfcf970e..8eca44ea31 100644 --- a/src/tools/call-omo-agent/tools.ts +++ b/src/tools/call-omo-agent/tools.ts @@ -8,7 +8,8 @@ import { executeSync } from "./sync-executor" export function createCallOmoAgent( ctx: PluginInput, - backgroundManager: BackgroundManager + backgroundManager: BackgroundManager, + disabledAgents: string[] = [] ): ToolDefinition { const agentDescriptions = ALLOWED_AGENTS.map( (name) => `- ${name}: Specialized agent for ${name} tasks` @@ -44,6 +45,11 @@ export function createCallOmoAgent( const normalizedAgent = args.subagent_type.toLowerCase() as AllowedAgentType args = { ...args, subagent_type: normalizedAgent } + // Check if agent is disabled + if (disabledAgents.some((disabled) => disabled.toLowerCase() === normalizedAgent)) { + return `Error: Agent "${normalizedAgent}" is disabled via disabled_agents configuration. Remove it from disabled_agents in your oh-my-opencode.json to use it.` + } + if (args.run_in_background) { if (args.session_id) { return `Error: session_id is not supported in background mode. Use run_in_background=false to continue an existing session.`