2025-12-27 17:56:40 +08:00
import { tool , type PluginInput , type ToolDefinition } from "@opencode-ai/plugin"
2025-12-12 18:39:53 +09:00
import { ALLOWED_AGENTS , CALL_OMO_AGENT_DESCRIPTION } from "./constants"
2026-02-08 21:11:07 +09:00
import type { AllowedAgentType , CallOmoAgentArgs , ToolContextWithMetadata } from "./types"
2025-12-12 18:39:53 +09:00
import type { BackgroundManager } from "../../features/background-agent"
2026-03-04 20:43:55 +01:00
import type { CategoriesConfig , AgentOverrides } from "../../config/schema"
import type { FallbackEntry } from "../../shared/model-requirements"
import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements"
import { getAgentConfigKey } from "../../shared/agent-display-names"
import { normalizeFallbackModels } from "../../shared/model-resolver"
import { buildFallbackChainFromModels } from "../../shared/fallback-chain-from-models"
2026-02-08 16:24:13 +09:00
import { log } from "../../shared"
2026-02-08 21:11:07 +09:00
import { executeBackground } from "./background-executor"
import { executeSync } from "./sync-executor"
2025-12-28 17:00:32 +09:00
2026-03-04 20:43:55 +01:00
function resolveFallbackChainForCallOmoAgent ( args : {
subagentType : string
agentOverrides? : AgentOverrides
userCategories? : CategoriesConfig
} ) : FallbackEntry [ ] | undefined {
const { subagentType , agentOverrides , userCategories } = args
const agentConfigKey = getAgentConfigKey ( subagentType )
const agentRequirement = AGENT_MODEL_REQUIREMENTS [ agentConfigKey ]
const agentOverride = agentOverrides ? . [ agentConfigKey as keyof AgentOverrides ]
? ? ( agentOverrides
? Object . entries ( agentOverrides ) . find ( ( [ key ] ) = > key . toLowerCase ( ) === agentConfigKey ) ? . [ 1 ]
: undefined )
const normalizedFallbackModels = normalizeFallbackModels (
agentOverride ? . fallback_models
? ? ( agentOverride ? . category ? userCategories ? . [ agentOverride . category ] ? . fallback_models : undefined )
)
const defaultProviderID = agentRequirement ? . fallbackChain ? . [ 0 ] ? . providers ? . [ 0 ] ? ? "opencode"
const configuredFallbackChain = buildFallbackChainFromModels ( normalizedFallbackModels , defaultProviderID )
return configuredFallbackChain ? ? agentRequirement ? . fallbackChain
}
2025-12-12 18:39:53 +09:00
export function createCallOmoAgent (
ctx : PluginInput ,
2026-02-10 18:44:45 +01:00
backgroundManager : BackgroundManager ,
2026-03-04 20:43:55 +01:00
disabledAgents : string [ ] = [ ] ,
agentOverrides? : AgentOverrides ,
userCategories? : CategoriesConfig ,
2025-12-27 17:56:40 +08:00
) : ToolDefinition {
2025-12-12 18:39:53 +09:00
const agentDescriptions = ALLOWED_AGENTS . map (
( name ) = > ` - ${ name } : Specialized agent for ${ name } tasks `
) . join ( "\n" )
const description = CALL_OMO_AGENT_DESCRIPTION . replace ( "{agents}" , agentDescriptions )
return tool ( {
description ,
args : {
description : tool.schema.string ( ) . describe ( "A short (3-5 words) description of the task" ) ,
prompt : tool.schema.string ( ) . describe ( "The task for the agent to perform" ) ,
subagent_type : tool.schema
2026-01-23 00:55:01 +09:00
. string ( )
2026-02-04 11:38:24 +09:00
. describe ( "The type of specialized agent to use for this task (explore or librarian only)" ) ,
2025-12-12 18:39:53 +09:00
run_in_background : tool.schema
. boolean ( )
. describe ( "REQUIRED. true: run asynchronously (use background_output to get results), false: run synchronously and wait for completion" ) ,
session_id : tool.schema.string ( ) . describe ( "Existing Task session to continue" ) . optional ( ) ,
} ,
async execute ( args : CallOmoAgentArgs , toolContext ) {
2025-12-28 17:00:32 +09:00
const toolCtx = toolContext as ToolContextWithMetadata
2025-12-12 18:39:53 +09:00
log ( ` [call_omo_agent] Starting with agent: ${ args . subagent_type } , background: ${ args . run_in_background } ` )
2026-02-08 21:11:07 +09:00
// Case-insensitive agent validation - allows "Explore", "EXPLORE", "explore" etc.
if (
! ALLOWED_AGENTS . some (
( name ) = > name . toLowerCase ( ) === args . subagent_type . toLowerCase ( ) ,
)
) {
2025-12-12 18:39:53 +09:00
return ` Error: Invalid agent type " ${ args . subagent_type } ". Only ${ ALLOWED_AGENTS . join ( ", " ) } are allowed. `
}
2026-02-08 16:24:13 +09:00
2026-02-08 21:11:07 +09:00
const normalizedAgent = args . subagent_type . toLowerCase ( ) as AllowedAgentType
2026-01-23 00:55:01 +09:00
args = { . . . args , subagent_type : normalizedAgent }
2025-12-12 18:39:53 +09:00
2026-02-10 18:44:45 +01:00
// 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. `
}
2026-03-09 13:11:03 +09:00
const fallbackChain = resolveFallbackChainForCallOmoAgent ( {
subagentType : args.subagent_type ,
agentOverrides ,
userCategories ,
} )
2025-12-12 18:39:53 +09:00
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. `
}
2026-03-04 20:43:55 +01:00
return await executeBackground ( args , toolCtx , backgroundManager , ctx . client , fallbackChain )
2025-12-12 18:39:53 +09:00
}
2026-03-09 13:11:03 +09:00
return await executeSync ( args , toolCtx , ctx , undefined , fallbackChain )
2025-12-12 18:39:53 +09:00
} ,
} )
}