From 0f5b8e921a3c5294730009313659dc50ffc39b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pe=C3=AFo=20Thibault?= Date: Tue, 10 Feb 2026 18:44:41 +0100 Subject: [PATCH 1/2] test(call-omo-agent): add disabled_agents validation tests Closes #1716 ## Summary - Added 4 tests for disabled_agents validation in call_omo_agent tool - Tests verify agent rejection when in disabled_agents list - Tests verify case-insensitive matching - Tests verify agents not in disabled list are allowed - Tests verify empty disabled_agents allows all agents --- src/tools/call-omo-agent/tools.test.ts | 102 +++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/tools/call-omo-agent/tools.test.ts 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 000000000..a560c8bea --- /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") + }) +}) From cd0949ccfa1326974d1ae8b9fbc2fe516643f8be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pe=C3=AFo=20Thibault?= Date: Tue, 10 Feb 2026 18:44:45 +0100 Subject: [PATCH 2/2] fix(call-omo-agent): enforce disabled_agents config (#1716) ## Summary - Added disabled_agents parameter to createCallOmoAgent factory - Check runs after ALLOWED_AGENTS validation, before agent execution - Case-insensitive matching consistent with existing patterns - Clear error message distinguishes 'disabled' from 'invalid agent type' - Threaded disabledAgents config into tool factory from pluginConfig ## Changes - tools.ts: Add disabledAgents parameter and validation check - tool-registry.ts: Pass pluginConfig.disabled_agents to factory --- src/plugin/tool-registry.ts | 2 +- src/tools/call-omo-agent/tools.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugin/tool-registry.ts b/src/plugin/tool-registry.ts index 7236ddc48..162b81ed7 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.ts b/src/tools/call-omo-agent/tools.ts index dbcfcf970..8eca44ea3 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.`