2025-07-25 01:20:43 +00:00
import { App } from "../app/app"
import { Config } from "../config/config"
import z from "zod"
import { Provider } from "../provider/provider"
import { generateObject , type ModelMessage } from "ai"
import PROMPT_GENERATE from "./generate.txt"
import { SystemPrompt } from "../session/system"
export namespace Agent {
export const Info = z
. object ( {
name : z.string ( ) ,
2025-08-07 20:32:12 +00:00
description : z.string ( ) . optional ( ) ,
mode : z.union ( [ z . literal ( "subagent" ) , z . literal ( "primary" ) , z . literal ( "all" ) ] ) ,
topP : z.number ( ) . optional ( ) ,
temperature : z.number ( ) . optional ( ) ,
2025-07-25 01:20:43 +00:00
model : z
. object ( {
modelID : z.string ( ) ,
providerID : z.string ( ) ,
} )
. optional ( ) ,
prompt : z.string ( ) . optional ( ) ,
tools : z.record ( z . boolean ( ) ) ,
} )
. openapi ( {
ref : "Agent" ,
} )
export type Info = z . infer < typeof Info >
2025-08-07 20:32:12 +00:00
2025-07-25 01:20:43 +00:00
const state = App . state ( "agent" , async ( ) = > {
const cfg = await Config . get ( )
const result : Record < string , Info > = {
general : {
name : "general" ,
description :
"General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you." ,
tools : {
todoread : false ,
todowrite : false ,
} ,
2025-08-07 20:32:12 +00:00
mode : "subagent" ,
} ,
build : {
name : "build" ,
tools : { } ,
mode : "primary" ,
} ,
plan : {
name : "plan" ,
tools : {
write : false ,
edit : false ,
patch : false ,
} ,
mode : "primary" ,
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" ,
tools : { } ,
2025-07-25 01:20:43 +00:00
}
2025-08-07 20:32:12 +00:00
if ( value . model ) item . model = Provider . parseModel ( value . model )
2025-07-25 01:20:43 +00:00
if ( value . prompt ) item . prompt = value . prompt
if ( value . tools )
item . tools = {
. . . item . tools ,
. . . value . tools ,
}
if ( value . description ) item . description = value . description
2025-08-07 20:32:12 +00:00
if ( value . temperature != undefined ) item . temperature = value . temperature
if ( value . top_p != undefined ) item . topP = value . top_p
if ( value . mode ) item . mode = value . mode
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 ) )
}
export async function generate ( input : { description : string } ) {
const defaultModel = await Provider . defaultModel ( )
const model = await Provider . getModel ( defaultModel . providerID , defaultModel . modelID )
const system = SystemPrompt . header ( defaultModel . providerID )
system . push ( PROMPT_GENERATE )
const existing = await list ( )
const result = await generateObject ( {
temperature : 0.3 ,
prompt : [
. . . 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 ` ,
} ,
] ,
model : model.language ,
schema : z.object ( {
identifier : z.string ( ) ,
whenToUse : z.string ( ) ,
systemPrompt : z.string ( ) ,
} ) ,
} )
return result . object
}
}