2026-07-03 05:28:34 +00:00
import * as Tool from "./tool"
2026-07-03 05:51:28 +00:00
import type { Tool as AITool , ToolExecutionOptions } from "ai"
2026-07-03 05:28:34 +00:00
import type { Tool as MCPToolDef } from "@modelcontextprotocol/sdk/types.js"
import { Cause , Effect , Schema } from "effect"
import {
CodeMode ,
Tool as SandboxTool ,
toolError ,
type ExecuteResult ,
type JsonSchema ,
type ToolDefinition ,
} from "@opencode-ai/codemode"
import { MCP } from "@/mcp"
import { McpCatalog } from "@/mcp/catalog"
import { Agent } from "@/agent/agent"
import { Session } from "@/session/session"
import { Permission } from "@/permission"
import { Plugin } from "@/plugin"
export const CODE_MODE_TOOL = "execute"
const DESCRIPTION = [
"Execute a JavaScript/TypeScript program that orchestrates the connected MCP tools inside a confined runtime." ,
"The full usage guide and the catalog of available tools follow below." ,
] . join ( "\n" )
export const Parameters = Schema . Struct ( {
code : Schema.String.annotate ( {
description : [
"JavaScript source to execute." ,
"Inside CodeMode, `tools` contains only the MCP/CodeMode tools listed in this execute tool's description; top-level opencode tools like bash, read, or lsp are not available unless listed there." ,
"Call available tools using the exact signatures shown in this execute tool's description, compose the results, and `return` the final value." ,
] . join ( " " ) ,
} ) ,
} )
2026-07-03 06:57:12 +00:00
type CallEntry = { tool : string ; status : "running" | "completed" | "error" ; input? : Record < string , unknown > }
2026-07-03 05:28:34 +00:00
type Metadata = {
toolCalls : CallEntry [ ]
error? : boolean
}
2026-07-03 06:57:12 +00:00
type Attachment = NonNullable < Tool.ExecuteResult [ " attachments " ] > [ number ]
2026-07-03 05:28:34 +00:00
2026-07-03 06:57:12 +00:00
type CatalogEntry = {
2026-07-03 05:28:34 +00:00
path : string
key : string
server : string
local : string
description : string
tool : AITool
inputSchema : JsonSchema
outputSchema? : JsonSchema
}
const toJsonSchema = ( schema : unknown ) : JsonSchema = > schema as JsonSchema
function fallbackInputSchema ( tool : AITool ) : JsonSchema {
const schema = ( tool . inputSchema as { jsonSchema? : unknown } | undefined ) ? . jsonSchema
if ( schema && typeof schema === "object" ) return toJsonSchema ( schema )
return { type : "object" , properties : { } }
}
2026-07-03 06:57:12 +00:00
function groupByServer (
2026-07-03 05:28:34 +00:00
mcpTools : Record < string , AITool > ,
servers : readonly string [ ] ,
mcpDefs : Record < string , MCPToolDef > = { } ,
) : Map < string , CatalogEntry [ ] > {
const byLongest = [ . . . servers ] . sort ( ( a , b ) = > b . length - a . length )
const groups = new Map < string , CatalogEntry [ ] > ( )
for ( const key of Object . keys ( mcpTools ) . sort ( ( a , b ) = > a . localeCompare ( b ) ) ) {
2026-07-03 06:57:12 +00:00
const server =
byLongest . find ( ( name ) = > key . startsWith ( name + "_" ) ) ? ? ( key . includes ( "_" ) ? key . slice ( 0 , key . indexOf ( "_" ) ) : key )
2026-07-03 05:28:34 +00:00
const local = server && key . startsWith ( server + "_" ) ? key . slice ( server . length + 1 ) : key
const def = mcpDefs [ key ]
const entry : CatalogEntry = {
path : ` ${ server } . ${ local } ` ,
key ,
server ,
local ,
description : mcpTools [ key ] ! . description ? ? def ? . description ? ? "" ,
tool : mcpTools [ key ] ! ,
inputSchema : def?.inputSchema ? toJsonSchema ( def . inputSchema ) : fallbackInputSchema ( mcpTools [ key ] ! ) ,
. . . ( def ? . outputSchema ? { outputSchema : toJsonSchema ( def . outputSchema ) } : { } ) ,
}
groups . set ( server , [ . . . ( groups . get ( server ) ? ? [ ] ) , entry ] )
}
return groups
}
2026-07-03 06:39:25 +00:00
export function describeCatalog (
2026-07-03 05:28:34 +00:00
mcpTools : Record < string , AITool > ,
mcpDefs : Record < string , MCPToolDef > ,
servers : readonly string [ ] ,
) : string {
return CodeMode . make ( {
2026-07-03 06:39:25 +00:00
tools : toolTree (
2026-07-03 06:57:12 +00:00
[ . . . groupByServer ( mcpTools , servers , mcpDefs ) . values ( ) ]
. flat ( )
. filter ( ( entry ) = > entry . tool . execute !== undefined ) ,
2026-07-03 06:39:25 +00:00
( ) = > ( ) = > Effect . fail ( toolError ( "Tool preview is not executable." ) ) ,
) ,
2026-07-03 05:28:34 +00:00
} ) . instructions ( )
}
function displayInput ( input : unknown ) : Record < string , unknown > | undefined {
if ( input === null || input === undefined ) return
if ( typeof input === "object" && ! Array . isArray ( input ) ) {
const value = input as Record < string , unknown >
if ( Object . keys ( value ) . length > 0 ) return value
return
}
return { input }
}
const lastSegment = ( uri : string ) = > {
const trimmed = uri . split ( /[?#]/ , 1 ) [ 0 ] ! . replace ( /\/+$/ , "" )
const segment = trimmed . slice ( trimmed . lastIndexOf ( "/" ) + 1 )
return segment . length > 0 ? segment : undefined
}
const dataUrl = ( mime : string , base64 : string ) = > ` data: ${ mime } ;base64, ${ base64 } `
const mediaMarker = ( files : number , images : number ) = > {
const noun = files === images ? "image" : "file"
return ` [ ${ files } ${ noun } ${ files === 1 ? "" : "s" } attached to the result] `
}
2026-07-03 06:57:12 +00:00
function toProgramValue ( raw : unknown , collect : ( attachment : Attachment ) = > void ) : unknown {
2026-07-03 05:28:34 +00:00
if ( raw === null || typeof raw !== "object" ) return raw
const record = raw as { structuredContent? : unknown ; content? : unknown }
const content = Array . isArray ( record . content ) ? record . content : [ ]
const text : string [ ] = [ ]
let files = 0
let images = 0
const push = ( attachment : Attachment ) = > {
files += 1
if ( attachment . mime . startsWith ( "image/" ) ) images += 1
collect ( attachment )
}
for ( const item of content ) {
if ( ! item || typeof item !== "object" ) continue
const block = item as Record < string , unknown >
switch ( block . type ) {
case "text" :
if ( typeof block . text === "string" ) text . push ( block . text )
break
case "image" :
case "audio" :
if ( typeof block . data === "string" && typeof block . mimeType === "string" ) {
push ( { type : "file" , mime : block.mimeType , url : dataUrl ( block . mimeType , block . data ) } )
}
break
case "resource" : {
const res = block . resource as Record < string , unknown > | undefined
if ( res && typeof res === "object" ) {
const mime = typeof res . mimeType === "string" ? res . mimeType : "application/octet-stream"
const uri = typeof res . uri === "string" ? res.uri : undefined
if ( typeof res . blob === "string" ) {
push ( { type : "file" , mime , url : dataUrl ( mime , res . blob ) , filename : uri ? lastSegment ( uri ) : undefined } )
} else if ( typeof res . text === "string" ) {
text . push ( res . text )
}
}
break
}
case "resource_link" :
if ( typeof block . uri === "string" ) {
push ( {
type : "file" ,
mime : typeof block . mimeType === "string" ? block . mimeType : "application/octet-stream" ,
url : block.uri ,
filename : typeof block . name === "string" ? block.name : lastSegment ( block . uri ) ,
} )
}
break
}
}
if ( record . structuredContent !== undefined && record . structuredContent !== null ) return record . structuredContent
if ( text . length > 0 ) return text . join ( "\n" )
if ( files > 0 ) return mediaMarker ( files , images )
if ( Array . isArray ( record . content ) ) return null // MCP-shaped result with nothing extractable
return raw
}
type Run = ( input : unknown ) = > Effect . Effect < unknown , unknown >
function toolTree ( catalog : readonly CatalogEntry [ ] , run : ( entry : CatalogEntry ) = > Run ) {
const tree : Record < string , Record < string , ToolDefinition > > = { }
for ( const entry of catalog ) {
const namespace = ( tree [ entry . server ] ? ? = { } )
namespace [ entry . local ] = SandboxTool . make ( {
description : entry.description ,
input : entry.inputSchema ,
output : entry.outputSchema ,
run : run ( entry ) ,
} )
}
return tree
}
2026-07-03 05:51:28 +00:00
const invokeChildTool = Effect . fn ( "CodeMode.invokeChildTool" ) ( function * < R > ( input : {
plugin : Plugin.Interface
entry : CatalogEntry
args : any
callID : string
options : ToolExecutionOptions
ctx : Tool.Context
execute : ( args : any , options : ToolExecutionOptions ) = > R | PromiseLike < R >
} ) {
yield * input . plugin . trigger (
"tool.execute.before" ,
{ tool : input.entry.key , sessionID : input.ctx.sessionID , callID : input.callID } ,
{ args : input.args } ,
)
const result : R = yield * Effect . gen ( function * ( ) {
yield * input . ctx . ask ( { permission : input.entry.key , metadata : { } , patterns : [ "*" ] , always : [ "*" ] } )
return yield * Effect . promise ( ( ) = > Promise . resolve ( input . execute ( input . args , input . options ) ) )
} ) . pipe (
Effect . withSpan ( "Tool.execute" , {
attributes : {
"tool.name" : input . entry . key ,
"tool.call_id" : input . callID ,
"session.id" : input . ctx . sessionID ,
"message.id" : input . ctx . messageID ,
} ,
} ) ,
)
yield * input . plugin . trigger (
"tool.execute.after" ,
{ tool : input.entry.key , sessionID : input.ctx.sessionID , callID : input.callID , args : input.args } ,
result ,
)
return result
} )
2026-07-03 05:28:34 +00:00
export const CodeModeTool = Tool . define (
CODE_MODE_TOOL ,
Effect . gen ( function * ( ) {
const mcp = yield * MCP . Service
const agents = yield * Agent . Service
const sessions = yield * Session . Service
const plugin = yield * Plugin . Service
const init : Tool.DefWithoutID < typeof Parameters , Metadata > = {
description : DESCRIPTION ,
parameters : Parameters ,
execute : Effect.fn ( "CodeMode.execute" ) ( function * ( params , ctx ) {
if ( ctx . abort . aborted ) {
return {
title : CODE_MODE_TOOL ,
metadata : { toolCalls : [ ] , error : true } ,
output : "Execution cancelled." ,
} satisfies Tool . ExecuteResult < Metadata >
}
const agent = yield * agents . get ( ctx . agent )
const session = yield * sessions . get ( ctx . sessionID ) . pipe ( Effect . orDie )
const ruleset = Permission . merge ( agent . permission , session . permission ? ? [ ] )
const mcpTools = Permission . visibleTools ( yield * mcp . tools ( ) , ruleset )
const servers = Object . keys ( yield * mcp . clients ( ) ) . map ( McpCatalog . sanitize )
2026-07-03 06:39:25 +00:00
const catalog = [ . . . groupByServer ( mcpTools , servers , yield * mcp . defs ( ) ) . values ( ) ]
. flat ( )
. filter ( ( entry ) = > entry . tool . execute !== undefined )
2026-07-03 05:28:34 +00:00
const calls : CallEntry [ ] = [ ]
const attachments : Attachment [ ] = [ ]
const collect = ( attachment : Attachment ) = > void attachments . push ( attachment )
2026-07-03 06:57:12 +00:00
const publish = ( ) = >
ctx . metadata ( { title : CODE_MODE_TOOL , metadata : { toolCalls : calls.map ( ( c ) = > ( { . . . c } ) ) } } )
2026-07-03 05:28:34 +00:00
let childCalls = 0
const callTool = ( entry : CatalogEntry ) = > ( input : unknown ) = >
2026-07-03 06:57:12 +00:00
Effect . gen ( function * ( ) {
childCalls += 1
const raw = yield * invokeChildTool ( {
plugin ,
entry ,
args : input ? ? { } ,
callID : ` ${ ctx . callID ? ? entry . key } / ${ childCalls } ` ,
options : { toolCallId : ctx.callID ? ? entry . key , abortSignal : ctx.abort , messages : [ ] } ,
ctx ,
execute : entry.tool.execute ! ,
} )
return toProgramValue ( raw , collect )
} ) . pipe (
Effect . catchCause ( ( cause ) = > {
if ( Cause . hasInterruptsOnly ( cause ) ) return Effect . interrupt
const error = Cause . squash ( cause )
return Effect . fail ( toolError ( error instanceof Error ? error.message : String ( error ) , error ) )
2026-07-03 05:28:34 +00:00
} ) ,
)
const runtime = CodeMode . make ( {
tools : toolTree ( catalog , callTool ) ,
onToolCallStart : ( { index , name , input } ) = >
Effect . suspend ( ( ) = > {
const shown = displayInput ( input )
calls [ index ] = { tool : name , status : "running" , . . . ( shown ? { input : shown } : { } ) }
return publish ( )
} ) ,
onToolCallEnd : ( { index , outcome } ) = >
Effect . suspend ( ( ) = > {
const current = calls [ index ]
if ( current ) calls [ index ] = { . . . current , status : outcome === "success" ? "completed" : "error" }
return publish ( )
} ) ,
} )
2026-07-03 06:23:44 +00:00
// Bridge ai-sdk AbortSignal cancellation into the Effect fiber.
2026-07-03 05:28:34 +00:00
const cancelled = Effect . callback < ExecuteResult > ( ( resume ) = > {
const onAbort = ( ) = >
resume (
Effect . succeed < ExecuteResult > ( {
ok : false ,
error : { kind : "ExecutionFailure" , message : "Execution cancelled." } ,
toolCalls : calls.map ( ( call ) = > ( { name : call.tool } ) ) ,
} ) ,
)
if ( ctx . abort . aborted ) return onAbort ( )
ctx . abort . addEventListener ( "abort" , onAbort , { once : true } )
return Effect . sync ( ( ) = > ctx . abort . removeEventListener ( "abort" , onAbort ) )
} )
const result = yield * Effect . raceFirst ( runtime . execute ( params . code ) , cancelled )
const logs = result . logs ? ? [ ]
const attached = attachments . length > 0 ? { attachments } : { }
2026-07-03 06:57:12 +00:00
const hints = result . ok
? [ ]
: ( result . error . suggestions ? ? [ ] ) . filter ( ( hint ) = > ! result . error . message . includes ( hint ) )
const metadata : Metadata = result . ok ? { toolCalls : calls } : { toolCalls : calls , error : true }
let output : string
2026-07-03 05:28:34 +00:00
if ( result . ok ) {
2026-07-03 06:57:12 +00:00
if ( typeof result . value === "string" ) output = result . value
else if ( result . value === undefined ) output = "undefined"
else {
try {
output = JSON . stringify ( result . value , null , 2 ) ? ? String ( result . value )
} catch {
output = String ( result . value )
}
}
} else {
output = [ result . error . message , . . . hints ] . join ( "\n" )
2026-07-03 05:28:34 +00:00
}
2026-07-03 06:57:12 +00:00
if ( logs . length > 0 )
output = output . length > 0 ? ` ${ output } \ n \ nLogs: \ n ${ logs . join ( "\n" ) } ` : ` Logs: \ n ${ logs . join ( "\n" ) } `
2026-07-03 05:28:34 +00:00
return {
title : CODE_MODE_TOOL ,
2026-07-03 06:57:12 +00:00
metadata ,
output ,
2026-07-03 05:28:34 +00:00
. . . attached ,
} satisfies Tool . ExecuteResult < Metadata >
} ) ,
}
return init
} ) ,
)