2025-07-25 01:20:43 +00:00
import { Config } from "../config/config"
2025-10-26 19:50:41 +00:00
import z from "zod"
2025-07-25 01:20:43 +00:00
import { Provider } from "../provider/provider"
import { generateObject , type ModelMessage } from "ai"
import { SystemPrompt } from "../session/system"
2025-09-01 21:15:49 +00:00
import { Instance } from "../project/instance"
2025-07-25 01:20:43 +00:00
2025-12-15 02:11:30 +00:00
import PROMPT_GENERATE from "./generate.txt"
import PROMPT_COMPACTION from "./prompt/compaction.txt"
import PROMPT_EXPLORE from "./prompt/explore.txt"
import PROMPT_SUMMARY from "./prompt/summary.txt"
import PROMPT_TITLE from "./prompt/title.txt"
2025-12-28 22:27:11 +00:00
import { PermissionNext } from "@/permission/next"
import { mergeDeep } from "remeda"
2025-12-15 02:11:30 +00:00
2025-07-25 01:20:43 +00:00
export namespace Agent {
export const Info = z
. object ( {
name : z.string ( ) ,
2025-08-07 20:32:12 +00:00
description : z.string ( ) . optional ( ) ,
2025-11-17 06:06:40 +00:00
mode : z.enum ( [ "subagent" , "primary" , "all" ] ) ,
2025-12-15 02:11:30 +00:00
native : z.boolean ( ) . optional ( ) ,
hidden : z.boolean ( ) . optional ( ) ,
2025-08-07 20:32:12 +00:00
topP : z.number ( ) . optional ( ) ,
temperature : z.number ( ) . optional ( ) ,
2025-11-12 00:32:44 +00:00
color : z.string ( ) . optional ( ) ,
2025-12-28 22:27:11 +00:00
permission : PermissionNext.Ruleset ,
2025-07-25 01:20:43 +00:00
model : z
. object ( {
modelID : z.string ( ) ,
providerID : z.string ( ) ,
} )
. optional ( ) ,
prompt : z.string ( ) . optional ( ) ,
2025-08-11 01:34:28 +00:00
options : z.record ( z . string ( ) , z . any ( ) ) ,
2025-12-28 22:27:11 +00:00
steps : z.number ( ) . int ( ) . positive ( ) . optional ( ) ,
2025-07-25 01:20:43 +00:00
} )
2025-09-15 07:12:07 +00:00
. meta ( {
2025-07-25 01:20:43 +00:00
ref : "Agent" ,
} )
export type Info = z . infer < typeof Info >
2025-08-07 20:32:12 +00:00
2025-09-01 21:15:49 +00:00
const state = Instance . state ( async ( ) = > {
2025-07-25 01:20:43 +00:00
const cfg = await Config . get ( )
2025-12-29 16:59:17 +00:00
const defaults = PermissionNext . fromConfig ( {
"*" : "allow" ,
doom_loop : "ask" ,
external_directory : "ask" ,
} )
const user = PermissionNext . fromConfig ( cfg . permission ? ? { } )
2025-08-21 22:25:31 +00:00
2025-07-25 01:20:43 +00:00
const result : Record < string , Info > = {
2025-12-15 14:58:23 +00:00
build : {
name : "build" ,
options : { } ,
2025-12-29 16:59:17 +00:00
permission : PermissionNext.merge ( defaults , user ) ,
2025-12-15 14:58:23 +00:00
mode : "primary" ,
native : true ,
} ,
plan : {
name : "plan" ,
options : { } ,
2025-12-28 22:27:11 +00:00
permission : PermissionNext.merge (
2025-12-29 16:59:17 +00:00
defaults ,
2025-12-28 22:27:11 +00:00
PermissionNext . fromConfig ( {
edit : {
"*" : "deny" ,
".opencode/plan/*.md" : "allow" ,
} ,
} ) ,
2025-12-29 16:59:17 +00:00
user ,
2025-12-28 22:27:11 +00:00
) ,
2025-12-15 14:58:23 +00:00
mode : "primary" ,
native : true ,
} ,
2025-07-25 01:20:43 +00:00
general : {
name : "general" ,
2025-11-29 21:40:08 +00:00
description : ` General-purpose agent for researching complex questions and executing multi-step tasks. Use this agent to execute multiple units of work in parallel. ` ,
2025-12-28 22:27:11 +00:00
permission : PermissionNext.merge (
2025-12-29 16:59:17 +00:00
defaults ,
2025-12-28 22:27:11 +00:00
PermissionNext . fromConfig ( {
todoread : "deny" ,
todowrite : "deny" ,
} ) ,
2025-12-29 16:59:17 +00:00
user ,
2025-12-28 22:27:11 +00:00
) ,
2025-08-11 00:30:25 +00:00
options : { } ,
2025-08-07 20:32:12 +00:00
mode : "subagent" ,
2025-12-15 02:11:30 +00:00
native : true ,
hidden : true ,
2025-11-29 02:13:07 +00:00
} ,
explore : {
name : "explore" ,
2025-12-28 22:27:11 +00:00
permission : PermissionNext.merge (
2025-12-29 16:59:17 +00:00
defaults ,
2025-12-28 22:27:11 +00:00
PermissionNext . fromConfig ( {
"*" : "deny" ,
grep : "allow" ,
glob : "allow" ,
list : "allow" ,
bash : "allow" ,
webfetch : "allow" ,
websearch : "allow" ,
codesearch : "allow" ,
read : "allow" ,
} ) ,
2025-12-29 16:59:17 +00:00
user ,
2025-12-28 22:27:11 +00:00
) ,
2025-11-29 02:47:39 +00:00
description : ` Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions. ` ,
2025-12-15 02:11:30 +00:00
prompt : PROMPT_EXPLORE ,
2025-11-29 02:13:07 +00:00
options : { } ,
mode : "subagent" ,
2025-12-15 02:11:30 +00:00
native : true ,
} ,
compaction : {
name : "compaction" ,
mode : "primary" ,
native : true ,
hidden : true ,
prompt : PROMPT_COMPACTION ,
2025-12-29 16:59:17 +00:00
permission : PermissionNext.merge (
defaults ,
PermissionNext . fromConfig ( {
"*" : "deny" ,
} ) ,
user ,
) ,
2025-12-15 02:11:30 +00:00
options : { } ,
2025-08-07 20:32:12 +00:00
} ,
2025-12-15 02:11:30 +00:00
title : {
name : "title" ,
mode : "primary" ,
options : { } ,
native : true ,
hidden : true ,
2025-12-29 16:59:17 +00:00
permission : PermissionNext.merge (
defaults ,
PermissionNext . fromConfig ( {
"*" : "deny" ,
} ) ,
user ,
) ,
2025-12-15 02:11:30 +00:00
prompt : PROMPT_TITLE ,
} ,
summary : {
name : "summary" ,
mode : "primary" ,
options : { } ,
native : true ,
hidden : true ,
2025-12-29 16:59:17 +00:00
permission : PermissionNext.merge (
defaults ,
PermissionNext . fromConfig ( {
"*" : "deny" ,
} ) ,
user ,
) ,
2025-12-15 02:11:30 +00:00
prompt : PROMPT_SUMMARY ,
2025-08-07 20:32:12 +00:00
} ,
2025-07-25 01:20:43 +00:00
}
2025-12-28 22:27:11 +00:00
2025-07-25 01:20:43 +00:00
for ( const [ key , value ] of Object . entries ( cfg . agent ? ? { } ) ) {
2025-08-05 10:20:00 +00:00
if ( value . disable ) {
delete result [ key ]
continue
}
2025-07-25 01:20:43 +00:00
let item = result [ key ]
if ( ! item )
item = result [ key ] = {
name : key ,
2025-08-07 20:32:12 +00:00
mode : "all" ,
2025-12-29 16:59:17 +00:00
permission : PermissionNext.merge ( defaults , user ) ,
2025-08-11 00:30:25 +00:00
options : { } ,
2025-12-15 02:11:30 +00:00
native : false ,
2025-07-25 01:20:43 +00:00
}
2025-12-28 22:27:11 +00:00
if ( value . model ) item . model = Provider . parseModel ( value . model )
item . prompt = value . prompt ? ? item . prompt
item . description = value . description ? ? item . description
item . temperature = value . temperature ? ? item . temperature
item . topP = value . top_p ? ? item . topP
item . mode = value . mode ? ? item . mode
item . color = value . color ? ? item . color
item . name = value . options ? . name ? ? item . name
item . steps = value . steps ? ? item . steps
item . options = mergeDeep ( item . options , value . options ? ? { } )
item . permission = PermissionNext . merge ( item . permission , PermissionNext . fromConfig ( value . permission ? ? { } ) )
2025-07-25 01:20:43 +00:00
}
return result
} )
export async function get ( agent : string ) {
return state ( ) . then ( ( x ) = > x [ agent ] )
}
export async function list() {
return state ( ) . then ( ( x ) = > Object . values ( x ) )
}
2025-12-28 22:27:11 +00:00
export async function defaultAgent() {
return state ( ) . then ( ( x ) = > Object . keys ( x ) [ 0 ] )
2025-12-20 17:46:48 +00:00
}
2025-12-15 20:55:59 +00:00
export async function generate ( input : { description : string ; model ? : { providerID : string ; modelID : string } } ) {
2025-12-05 16:48:22 +00:00
const cfg = await Config . get ( )
2025-12-15 20:55:59 +00:00
const defaultModel = input . model ? ? ( await Provider . defaultModel ( ) )
2025-07-25 01:20:43 +00:00
const model = await Provider . getModel ( defaultModel . providerID , defaultModel . modelID )
2025-12-04 02:09:03 +00:00
const language = await Provider . getLanguage ( model )
2025-07-25 01:20:43 +00:00
const system = SystemPrompt . header ( defaultModel . providerID )
system . push ( PROMPT_GENERATE )
const existing = await list ( )
const result = await generateObject ( {
2025-12-09 15:46:48 +00:00
experimental_telemetry : {
isEnabled : cfg.experimental?.openTelemetry ,
metadata : {
userId : cfg.username ? ? "unknown" ,
} ,
} ,
2025-07-25 01:20:43 +00:00
temperature : 0.3 ,
2025-12-10 03:09:45 +00:00
messages : [
2025-07-25 01:20:43 +00:00
. . . system . map (
( item ) : ModelMessage = > ( {
role : "system" ,
content : item ,
} ) ,
) ,
{
role : "user" ,
content : ` Create an agent configuration based on this request: \ " ${ input . description } \ ". \ n \ nIMPORTANT: The following identifiers already exist and must NOT be used: ${ existing . map ( ( i ) = > i . name ) . join ( ", " ) } \ n Return ONLY the JSON object, no other text, do not wrap in backticks ` ,
} ,
] ,
2025-12-04 02:09:03 +00:00
model : language ,
2025-07-25 01:20:43 +00:00
schema : z.object ( {
identifier : z.string ( ) ,
whenToUse : z.string ( ) ,
systemPrompt : z.string ( ) ,
} ) ,
} )
return result . object
}
}