@gencode/agents 0.7.4 → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -83,7 +83,7 @@ Preview:
|
|
|
83
83
|
`),n.line,r.content);if(a===null)throw Error(`Line ${n.line} out of range in ${n.filePath}`);return await Wu(e,n.filePath,a,{providerId:t?.providerId,pluginId:t?.pluginId,sessionId:t?.sessionId,onMemoryChanged:t?.onMemoryChanged}),{content:[{type:`text`,text:`Memory updated: ${r.id} (line ${n.line})`}],details:{id:r.id}}}return await Wu(e,r.id,r.content,{providerId:t?.providerId,pluginId:t?.pluginId,sessionId:t?.sessionId,onMemoryChanged:t?.onMemoryChanged}),{content:[{type:`text`,text:`Memory updated: ${r.id}`}],details:{id:r.id}}}catch(e){throw Error(`Failed to update memory: ${e instanceof Error?e.message:String(e)}`)}}}}const md=K.Object({query:K.Optional(K.String({description:`Search query; omit to browse recent sessions.`})),role_filter:K.Optional(K.Union([K.Literal(`user`),K.Literal(`assistant`),K.Literal(`tool_result`)],{description:`Optional role filter for transcript matching.`})),limit:K.Optional(K.Number({description:`Max sessions to return (default 3, max 5).`,minimum:1,maximum:5})),summary_mode:K.Optional(K.Union([K.Literal(`llm`),K.Literal(`off`)],{description:`Summary mode: "llm" (default) or "off" for extractive only.`,default:`llm`}))});function hd(e,t){return{name:`session_search`,label:`Session Search`,description:`Search past conversation transcripts across sessions for cross-session recall. Use when the user asks about what was discussed, decided, or done in previous chats (e.g. last time, before, remember when). Omit query to browse recent sessions with zero LLM cost; include query to search transcripts and return summaries. Do not use this as the only source for stable project policy/config if long-term memory docs exist (use memory_search for durable docs).`,parameters:md,async execute(n,r){let i=gd(r.limit),a=r.summary_mode??`llm`,o=r.query?.trim(),s=r.role_filter;if(!o){let n=await _d(e,i,t),r={mode:`recent`,count:n.length,results:n};return{content:[{type:`text`,text:JSON.stringify(r,null,2)}],details:r}}let c=await vd({dataDir:e,query:o,roleFilter:s,messageLimit:50,sessionLimit:i,currentSessionId:t?.sessionId,sessionStoreName:t?.sessionStoreName});if(c.length===0){let e={mode:`query`,query:o,count:0,results:[]};return{content:[{type:`text`,text:JSON.stringify(e,null,2)}],details:e}}let l=[];for(let n of c){let r=jd(o,n.snippets);if(a===`off`){l.push({session_id:n.sessionId,summary:r,when:n.when,source:n.source,meta:{summary_source:`extractive`,snippet:n.snippets[0],score:Number(n.score.toFixed(4))}});continue}if(!t?.llm){l.push({session_id:n.sessionId,summary:r,when:n.when,source:n.source,meta:{summary_source:`extractive_short_circuit`,snippet:n.snippets[0],score:Number(n.score.toFixed(4)),summary_error:`llm configuration unavailable`}});continue}try{let i=await Cc({entries:Od(Dd(await m(e,n.sessionId,{storeName:t?.sessionStoreName})),o,1e5),llm:t.llm,instructions:Ad({query:o})});l.push({session_id:n.sessionId,summary:i.trim()||r,when:n.when,source:n.source,meta:{summary_source:`llm`,snippet:n.snippets[0],score:Number(n.score.toFixed(4))}})}catch(e){l.push({session_id:n.sessionId,summary:r,when:n.when,source:n.source,meta:{summary_source:`llm_fallback_extractive`,snippet:n.snippets[0],score:Number(n.score.toFixed(4)),summary_error:e instanceof Error?e.message:String(e)}})}}let u={mode:`query`,query:o,count:l.length,results:l};return{content:[{type:`text`,text:JSON.stringify(u,null,2)}],details:u}}}}function gd(e){return Number.isFinite(e)?Math.min(Math.max(Math.trunc(e),1),5):3}async function _d(e,t,n){let r=await y(e,{storeName:n?.sessionStoreName}),i=[];for(let t of r){if(t===n?.sessionId)continue;let r=await M(e,t,{storeName:n?.sessionStoreName});r&&i.push({id:t,when:r.updatedAt||r.createdAt||``,source:r.channel??`unknown`,title:r.title?.trim()||`Session activity summary unavailable.`})}return i.sort((e,t)=>t.when.localeCompare(e.when)),i.slice(0,t).map(e=>({session_id:e.id,summary:e.title,when:e.when,source:e.source,meta:{summary_source:`extractive`,snippet:e.title}}))}async function vd(e){let t=e.messageLimit??50,n=(await y(e.dataDir,{storeName:e.sessionStoreName})).filter(t=>t!==e.currentSessionId),r=Sd(e.query),i=(await Md(n,6,async t=>yd({dataDir:e.dataDir,sessionId:t,terms:r,roleFilter:e.roleFilter,storeName:e.sessionStoreName}))).flat().sort(Ed).slice(0,t);if(i.length===0)return[];let a=new Map;for(let e of i){let t=a.get(e.sessionId)??{sessionId:e.sessionId,score:0,snippets:[],matchedMessageCount:0,when:e.timestamp||``,source:`unknown`};t.score+=e.score,t.matchedMessageCount+=1,t.snippets.length<3&&!t.snippets.includes(e.snippet)&&t.snippets.push(e.snippet),e.timestamp&&e.timestamp>t.when&&(t.when=e.timestamp),a.set(e.sessionId,t)}let o=Array.from(a.values());for(let t of o){let n=await M(e.dataDir,t.sessionId,{storeName:e.sessionStoreName});n&&(t.when=n.updatedAt||n.createdAt||t.when,t.source=n.channel??`unknown`)}return o.sort((e,t)=>t.score===e.score?t.when.localeCompare(e.when):t.score-e.score),o.slice(0,e.sessionLimit)}async function yd(t){let n=await l(e(t.dataDir,t.sessionId,{storeName:t.storeName}));if(n===null)return[];let r=[],i=n.split(`
|
|
84
84
|
`);for(let e of i){let n=e.trim();if(!n||!bd(n,t.terms))continue;let i;try{i=JSON.parse(n)}catch{continue}if(!xd(i.role)||t.roleFilter&&i.role!==t.roleFilter||typeof i.content!=`string`||i.content.trim().length===0)continue;let a=wd(i.content,t.terms,i.role);if(a<=0)continue;let o=Td(i.content);r.push({sessionId:t.sessionId,score:a,snippet:o,timestamp:typeof i.timestamp==`string`?i.timestamp:``}),r.length>20&&(r.sort(Ed),r.length=20)}return r.sort(Ed),r}function bd(e,t){let n=e.toLowerCase();for(let e of t)if(e&&n.includes(e))return!0;return!1}function xd(e){return e===`user`||e===`assistant`||e===`tool_result`}function Sd(e){let t=e.toLowerCase().trim(),n=new Set;t.length>0&&n.add(t);let r=t.match(/[\p{L}\p{N}_-]+/gu)??[];for(let e of r)e.length>=2&&n.add(e);let i=Array.from(t).filter(e=>Cd(e)).join(``);if(i.length>=2)for(let e=0;e<=i.length-2;e+=1)n.add(i.slice(e,e+2));return Array.from(n).slice(0,30)}function Cd(e){let t=e.codePointAt(0)??0;return t>=19968&&t<=40959||t>=13312&&t<=19903||t>=12352&&t<=12543||t>=44032&&t<=55215}function wd(e,t,n){let r=e.toLowerCase(),i=0;for(let e of t)e&&r.includes(e)&&(i+=1);if(i===0)return 0;let a=n===`user`?1.2:n===`assistant`?1:.7;return i*i*a}function Td(e){let t=e.replace(/\s+/g,` `).trim();return t.length>280?`${t.slice(0,277)}...`:t}function Ed(e,t){return t.score===e.score?t.timestamp.localeCompare(e.timestamp):t.score-e.score}function Dd(e){return e.filter(e=>e.role===`user`||e.role===`assistant`||e.role===`tool_result`)}function Od(e,t,n){if(e.length===0)return e;let r=Sd(t);if(e.reduce((e,t)=>e+t.content.length,0)<=n)return e;let i=[];for(let t=0;t<e.length;t+=1){let n=e[t].content.toLowerCase();r.some(e=>e&&n.includes(e))&&i.push(t)}if(i.length===0)return kd(e,n);let a=i[0],o=i[0],s=e[a].content.length;for(;s<n&&(a>0||o<e.length-1);){if(o<e.length-1){let t=e[o+1].content.length;if(s+t<=n)o+=1,s+=t;else break}if(a>0){let t=e[a-1].content.length;if(s+t<=n)--a,s+=t;else break}}return e.slice(a,o+1)}function kd(e,t){let n=[],r=0;for(let i=e.length-1;i>=0;--i){let a=e[i];if(r+a.content.length>t)break;n.push(a),r+=a.content.length}return n.reverse()}function Ad(e){let t=e.languageHint?.trim(),n=[`Summarize this past session for retrieval use.`,`Focus query: ${e.query}`,`Prioritize: final outcome, key actions, concrete evidence (files/commands/ids), unresolved items.`,`Do not invent facts. If evidence is missing, say so explicitly.`,`Keep it concise and factual.`];return t&&n.push(`Respond in: ${t}`),n.join(`
|
|
85
85
|
`)}function jd(e,t){return t.length===0?`No direct transcript snippet was extracted for query: ${e}`:`Extractive summary for "${e}":\n${t.slice(0,3).map((e,t)=>`${t+1}. ${e}`).join(`
|
|
86
|
-
`)}`}async function Md(e,t,n){if(e.length===0)return[];let r=Math.max(1,Math.trunc(t)),i=Array(e.length),a=0,o=Array(Math.min(r,e.length)).fill(0).map(async()=>{for(;;){let t=a;if(a+=1,t>=e.length)break;i[t]=await n(e[t])}});return await Promise.all(o),i}const Nd=K.Object({category:K.Optional(K.String({description:`Reserved category filter field. Not used yet.`}))}),Pd=K.Object({name:K.String({description:`The skill name. Use skill_list first to see available skills.`}),skillPath:K.Optional(K.String({description:`Optional explicit path to a skill directory or SKILL.md. Use this for scene skills outside the shared skills registry.`}))});function Fd(e,t,n=[]){return[...n,...t,Et(e)]}function Id(e,t,n=[]){let r=Fd(e,t,n);return{name:`skill_list`,label:`Skill List`,description:`List available skills with compact metadata. Use skill_load to load one.`,parameters:Nd,async execute(e,t){let n=await Mt(r),i={skills:n.map(e=>({name:e.name,description:e.description})),count:n.length};return{content:[{type:`text`,text:JSON.stringify({success:!0,...i,hint:`Use skill_load(name) to load the skill's SKILL.md entrypoint.`})}],details:i}}}}function Ld(e){let t=Fd(e.dataDir,e.pluginDirs,e.skillsLoadPaths),n=new Set;return{name:`skill_load`,label:`Skill Load`,description:`Load a skill's SKILL.md entrypoint. Optionally override lookup with skillPath.`,parameters:Pd,async execute(r,i){let a=await Ft(t,i.name,i.skillPath);return a?(n.has(a.skill.name)||(n.add(a.skill.name),await e.reportSkillUsed?.({type:`skill_used`,skillName:a.skill.name,agent:`aimax:main`,taskId:`aimax[${e.sessionId}]`})),{content:[{type:`text`,text:JSON.stringify({success:!0,name:a.skill.name,description:a.skill.description,content:a.content,path:a.skill.location,usage_hint:`This returns only SKILL.md. If the skill references other files, read them later with normal file tools using paths relative to the skill directory.`})}],details:{name:a.skill.name,description:a.skill.description,content:a.content,path:a.skill.location}}):{content:[{type:`text`,text:JSON.stringify({success:!1,error:i.skillPath?.trim()?`Skill '${i.name}' not found at '${i.skillPath}'.`:`Skill '${i.name}' not found.`})}],details:{name:i.name,description:``,content:``,path:``}}}}}const Rd=K.Object({});function zd(e,t,n){return{name:`get_goal`,label:`Get Goal`,description:`Get the current thread goal, including status, budget, token and time usage, and remaining token budget. Returns null when no goal is set.`,parameters:Rd,async execute(r,i){let a=await z(e,t,{storeName:n});if(!a)return{content:[{type:`text`,text:JSON.stringify({goal:null})}],details:{}};let o=await V(e,t,a,{storeName:n}),s={goal:{...a,objective:o,remainingTokens:a.tokenBudget===null?void 0:Math.max(0,a.tokenBudget-a.tokensUsed)}};return{content:[{type:`text`,text:JSON.stringify(s,null,2)}],details:{}}}}}const Bd=K.Object({status:K.String({description:`Status to set. Only 'complete' is allowed.`})});function Vd(e,t,n,r,i=t){return{name:`update_goal`,label:`Update Goal`,description:`Update the existing goal. Only supports marking the goal as complete. Use this only when the objective has actually been achieved and no required work remains. Do not mark a goal complete merely because its budget is nearly exhausted or because you are stopping work.`,parameters:Bd,async execute(a,o){if(o.status!==`complete`)return{content:[{type:`text`,text:JSON.stringify({goal:null,error:`Invalid status: "${o.status}". Only "complete" is allowed via this tool.`},null,2)}],details:{}};let s=await z(e,t,{storeName:n});if(!s)return{content:[{type:`text`,text:JSON.stringify({goal:null,error:`No active goal exists for this session. Use the CLI to set a goal first.`},null,2)}],details:{}};if(s.status===`complete`)return{content:[{type:`text`,text:JSON.stringify({goal:s},null,2)}],details:{}};let c=await I(e,t,{status:`complete`},{storeName:n,eventSource:`tool`});if(!c)return{content:[{type:`text`,text:JSON.stringify({goal:null,error:`Failed to update goal.`},null,2)}],details:{}};r&&await tn(r,i,{before:s,after:c,action:`completed`});let l={goal:{...c,remainingTokens:c.tokenBudget===null?void 0:Math.max(0,c.tokenBudget-c.tokensUsed)}};return{content:[{type:`text`,text:JSON.stringify(l,null,2)}],details:{}}}}}const Hd=K.Object({task:K.String({description:`The task description for the subagent to execute`}),label:K.Optional(K.String({description:`Optional short label to identify this subagent`})),agent:K.Optional(K.String({description:`Optional custom agent name to use for this subagent. Must exactly match one of the names listed in the Custom Agents prompt section; do not guess or invent names.`}))}),Ud=K.Object({task:K.String({description:`The task description for the subagent to execute`}),label:K.Optional(K.String({description:`Optional short label to identify this subagent`})),agent:K.Optional(K.String({description:`Optional custom agent name to use for this subagent. Must exactly match one of the names listed in the Custom Agents prompt section; do not guess or invent names.`}))}),Wd=K.Object({tasks:K.Array(Hd,{description:`Tasks to run as subagents. The tool runs at most 5 at the same time.`})});function Gd(e){let t=e.label?`"${e.label}"`:`task: ${Le(e.task)}`;return e.status===`done`?`[Subagent completed] ${t}\n\n${Kd(e.result??`(no output)`)}`:e.status===`error`?`[Subagent failed] ${t}\n\nError: ${e.error??`unknown error`}`:`[Subagent killed] ${t}`}function Kd(e){let t=e.trim().match(/^\[Subagent (?:completed|failed|killed)\][^\n]*(?:\n\n([\s\S]*))?$/);return t?t[1]?.trim()||`(no output)`:e}async function qd(e,t,n){let{registry:r,parentSessionId:i,parentSessionDir:a,depth:o,dataDir:s,channel:c,llm:l,loopDetection:u,inheritedRunParams:d,spawnFn:f}=e,p=n.task.trim(),m=n.label?.trim(),h=n.agent?.trim();if(X.info(`subagent spawn requested`,{parentSessionId:i,depth:o+1,label:m,requestedAgentName:h,taskLength:p.length,taskPreview:fa(p)}),!p){let e={status:`error`,error:`task must not be empty`};return X.warn(`subagent spawn rejected`,{parentSessionId:i,depth:o+1,reason:e.error}),{content:[{type:`text`,text:JSON.stringify(e)}],details:e}}let g=r.checkSpawnAllowed(i,o+1);if(!g.allowed){let e={status:`forbidden`,error:g.reason};return X.warn(`subagent spawn rejected`,{parentSessionId:i,depth:o+1,reason:e.error}),{content:[{type:`text`,text:JSON.stringify(e)}],details:e}}let _=Ge(),v=new AbortController,y=t,b=Nr(d.agentPolicy?.availableAgents??[],h);if(h&&!b){let e={status:`error`,error:`Unknown custom agent: ${h}`};return X.warn(`subagent spawn rejected`,{parentSessionId:i,depth:o+1,requestedAgentName:h,reason:e.error}),{content:[{type:`text`,text:JSON.stringify(e)}],details:e}}let x={parentSessionId:i,parentDir:a};try{await C(s,c,{storeName:d.sessionStoreName,subagent:x,sessionId:y})}catch(e){let t={status:`error`,error:`Failed to create session: ${e instanceof Error?e.message:String(e)}`};return X.error(`subagent session creation failed`,{parentSessionId:i,depth:o+1,error:t.error}),{content:[{type:`text`,text:JSON.stringify(t)}],details:t}}X.info(`subagent session created`,{parentSessionId:i,childSessionId:y,depth:o+1,runId:_,requestedAgentName:h,selectedAgent:b?.name});let S={runId:_,childSessionId:y,parentSessionId:i,task:p,label:m,depth:o+1,status:`running`,startedAt:Date.now(),abortController:v};await d.onProgress?.({type:`subagent_spawn`,childSessionId:y,task:p,label:m,sessionId:i,messageId:d.messageId,depth:o+1});let w=f({dataDir:s,sessionId:y,message:b?zr(b,p):p,channel:c,llm:b?.model?{...l,model:b.model}:l,...d,agentPolicy:{availableAgents:d.agentPolicy?.availableAgents??[],...b?{activeAgent:b}:{}},loopDetection:u,abortSignal:v.signal,sessionPathScope:{subagent:{parentSessionId:i,parentDir:a}},subagentContext:{depth:o+1,parentSessionId:i}}).then(e=>{if(e.error){r.fail(_,e.error);return}r.complete(_,e.text||`(no output)`)}).catch(e=>{let t=e instanceof Error?e.message:String(e);r.fail(_,t)});r.register(S,w),X.info(`subagent run registered`,{runId:_,parentSessionId:i,childSessionId:y,depth:o+1,selectedAgent:b?.name}),await w,X.info(`subagent run settled`,{runId:_,parentSessionId:i,childSessionId:y,status:S.status,durationMs:S.endedAt?S.endedAt-S.startedAt:void 0,hasError:!!S.error}),r.markAnnounced(_),await d.onProgress?.({type:`subagent_complete`,childSessionId:y,task:p,status:S.status,sessionId:i,messageId:d.messageId,depth:o+1});let T=Gd({task:p,label:m,status:S.status,result:S.result,error:S.error});if(S.status===`done`){let e={status:`done`,childSessionId:y,runId:_,result:S.result??``};return X.info(`subagent spawn completed`,{runId:_,parentSessionId:i,childSessionId:y,status:e.status,resultLength:e.result.length}),{content:[{type:`text`,text:T}],details:e}}let E=S.status===`killed`?{status:`killed`,childSessionId:y,runId:_,error:`subagent killed`}:{status:`error`,childSessionId:y,runId:_,error:S.error??`unknown error`};return X.warn(`subagent spawn completed with non-success status`,{runId:_,parentSessionId:i,childSessionId:y,status:E.status,error:E.error}),{content:[{type:`text`,text:T}],isError:!0,details:E}}function Jd(e,t,n,r,i,a,o,s,c,l){let u={registry:e,parentSessionId:t,parentSessionDir:n,depth:r,dataDir:i,channel:a,llm:o,loopDetection:s,inheritedRunParams:c,spawnFn:l};return{name:`subagent_spawn`,label:`Spawn Subagent`,description:`Spawn an isolated subagent session to delegate a task. `+(r===0?"IMPORTANT: You MUST use this tool whenever the user explicitly mentions 'subagent', '@subagent', or asks for subagent-based execution. You MUST also use this tool when the user mentions '@<agent-name>' where <agent-name> matches a custom agent listed in the Custom Agents section — set the `agent` field to that exact name. Do not use it for routine decomposition or inferred parallelism — only when the user or system instructions explicitly require subagent delegation or parallel agent execution. ":`WARNING: You are already running as a subagent (depth ${r}). Spawning further subagents creates deeply nested hierarchies that are expensive and error-prone. Only use this tool if the current task genuinely cannot be completed with available tools directly. Prefer direct tool calls (exec, read_file, write_file, etc.) over spawning another subagent. `)+`Waits for the subagent to finish and returns the final subagent result as this tool call's result.`,parameters:Ud,async execute(e,t){return qd(u,e,t)}}}function Yd(e,t,n,r,i,a,o,s,c,l){let u={registry:e,parentSessionId:t,parentSessionDir:n,depth:r,dataDir:i,channel:a,llm:o,loopDetection:s,inheritedRunParams:c,spawnFn:l};return{name:`batch_subagent_spawn`,label:`Batch Spawn Subagents`,description:`Spawn multiple isolated subagent sessions from one tool call, running at most 5 subagents concurrently. Use this when the user explicitly asks for parallel subagent execution or when several independent subagent tasks should be delegated together. Each task waits for its subagent to finish; the tool returns all final subagent results in input order.`,parameters:Wd,async execute(n,i){let a=i.tasks??[];if(a.length===0){let e={status:`error`,results:[]};return{content:[{type:`text`,text:JSON.stringify({...e,error:`tasks must not be empty`})}],isError:!0,details:e}}X.info(`batch subagent spawn requested`,{parentSessionId:t,depth:r+1,taskCount:a.length,concurrencyLimit:5});let o=Array(a.length),s=0,c=Math.max(0,5-e.countActive(t)),l=Math.min(5,c,a.length);if(l===0){let n=e.checkSpawnAllowed(t,r+1),i=n.allowed?`Maximum concurrent subagents (5) reached for this session`:n.reason;for(let[e,t]of a.entries())o[e]={status:`forbidden`,error:i,index:e,task:t.task.trim(),label:t.label?.trim()}}else{let e=async()=>{for(;s<a.length;){let e=s++,t=a[e];o[e]={...(await qd(u,`${n}-${e+1}`,t)).details,index:e,task:t.task.trim(),label:t.label?.trim()}}};await Promise.all(Array.from({length:l},()=>e()))}let d=o.filter(e=>e.status!==`done`),f=d.length===0?`done`:d.length===o.length?`error`:`partial_error`,p={status:f,results:o},m=[`[Batch subagents ${f}] ${o.length-d.length}/${o.length} completed`,...o.map(e=>{let t=e.label?`"${e.label}"`:`#${e.index+1}`;return e.status===`done`?`- ${t}: done\n${Kd(e.result)}`:`- ${t}: ${e.status}\n${e.error}`})].join(`
|
|
86
|
+
`)}`}async function Md(e,t,n){if(e.length===0)return[];let r=Math.max(1,Math.trunc(t)),i=Array(e.length),a=0,o=Array(Math.min(r,e.length)).fill(0).map(async()=>{for(;;){let t=a;if(a+=1,t>=e.length)break;i[t]=await n(e[t])}});return await Promise.all(o),i}const Nd=K.Object({category:K.Optional(K.String({description:`Reserved category filter field. Not used yet.`}))}),Pd=K.Object({name:K.String({description:`The skill name. Use skill_list first to see available skills.`}),skillPath:K.Optional(K.String({description:`Optional explicit path to a skill directory or SKILL.md. Use this for scene skills outside the shared skills registry.`}))});function Fd(e,t,n=[]){return[...n,...t,Et(e)]}function Id(e,t,n=[]){let r=Fd(e,t,n);return{name:`skill_list`,label:`Skill List`,description:`List available skills with compact metadata. Use skill_load to load one.`,parameters:Nd,async execute(e,t){let n=await Mt(r),i={skills:n.map(e=>({name:e.name,description:e.description})),count:n.length};return{content:[{type:`text`,text:JSON.stringify({success:!0,...i,hint:`Use skill_load(name) to load the skill's SKILL.md entrypoint.`})}],details:i}}}}function Ld(e){let t=Fd(e.dataDir,e.pluginDirs,e.skillsLoadPaths),n=new Set;return{name:`skill_load`,label:`Skill Load`,description:`Load a skill's SKILL.md entrypoint. Optionally override lookup with skillPath.`,parameters:Pd,async execute(r,i){let a=await Ft(t,i.name,i.skillPath);return a?(n.has(a.skill.name)||(n.add(a.skill.name),await e.reportSkillUsed?.({type:`skill_used`,skillName:a.skill.name,agent:`aimax:main`,taskId:`aimax[${e.sessionId}]`})),{content:[{type:`text`,text:JSON.stringify({success:!0,name:a.skill.name,description:a.skill.description,content:a.content,path:a.skill.location,usage_hint:`This returns only SKILL.md. If the skill references other files, read them later with normal file tools using paths relative to the skill directory.`})}],details:{name:a.skill.name,description:a.skill.description,content:a.content,path:a.skill.location}}):{content:[{type:`text`,text:JSON.stringify({success:!1,error:i.skillPath?.trim()?`Skill '${i.name}' not found at '${i.skillPath}'.`:`Skill '${i.name}' not found.`})}],details:{name:i.name,description:``,content:``,path:``}}}}}const Rd=K.Object({});function zd(e,t,n){return{name:`get_goal`,label:`Get Goal`,description:`Get the current thread goal, including status, budget, token and time usage, and remaining token budget. Returns null when no goal is set.`,parameters:Rd,async execute(r,i){let a=await z(e,t,{storeName:n});if(!a)return{content:[{type:`text`,text:JSON.stringify({goal:null})}],details:{}};let o=await V(e,t,a,{storeName:n}),s={goal:{...a,objective:o,remainingTokens:a.tokenBudget===null?void 0:Math.max(0,a.tokenBudget-a.tokensUsed)}};return{content:[{type:`text`,text:JSON.stringify(s,null,2)}],details:{}}}}}const Bd=K.Object({status:K.String({description:`Status to set. Only 'complete' is allowed.`})});function Vd(e,t,n,r,i=t){return{name:`update_goal`,label:`Update Goal`,description:`Update the existing goal. Only supports marking the goal as complete. Use this only when the objective has actually been achieved and no required work remains. Do not mark a goal complete merely because its budget is nearly exhausted or because you are stopping work.`,parameters:Bd,async execute(a,o){if(o.status!==`complete`)return{content:[{type:`text`,text:JSON.stringify({goal:null,error:`Invalid status: "${o.status}". Only "complete" is allowed via this tool.`},null,2)}],details:{}};let s=await z(e,t,{storeName:n});if(!s)return{content:[{type:`text`,text:JSON.stringify({goal:null,error:`No active goal exists for this session. Use the CLI to set a goal first.`},null,2)}],details:{}};if(s.status===`complete`)return{content:[{type:`text`,text:JSON.stringify({goal:s},null,2)}],details:{}};let c=await I(e,t,{status:`complete`},{storeName:n,eventSource:`tool`});if(!c)return{content:[{type:`text`,text:JSON.stringify({goal:null,error:`Failed to update goal.`},null,2)}],details:{}};r&&await tn(r,i,{before:s,after:c,action:`completed`});let l={goal:{...c,remainingTokens:c.tokenBudget===null?void 0:Math.max(0,c.tokenBudget-c.tokensUsed)}};return{content:[{type:`text`,text:JSON.stringify(l,null,2)}],details:{}}}}}const Hd=K.Object({task:K.String({description:`The task description for the subagent to execute`}),label:K.Optional(K.String({description:`Optional short label to identify this subagent`})),agent:K.Optional(K.String({description:`Optional custom agent name to use for this subagent. Must exactly match one of the names listed in the Custom Agents prompt section; do not guess or invent names.`}))}),Ud=K.Object({task:K.String({description:`The task description for the subagent to execute`}),label:K.Optional(K.String({description:`Optional short label to identify this subagent`})),agent:K.Optional(K.String({description:`Optional custom agent name to use for this subagent. Must exactly match one of the names listed in the Custom Agents prompt section; do not guess or invent names.`}))}),Wd=K.Object({tasks:K.Array(Hd,{description:`Tasks to run as subagents. The tool runs at most 5 at the same time.`})});function Gd(e){let t=e.label?`"${e.label}"`:`task: ${Le(e.task)}`;return e.status===`done`?`${t}\n\n${Kd(e.result??`(no output)`)}`:e.status===`error`?`${t}\n\nError: ${e.error??`unknown error`}`:`${t}\n\nStopped.`}function Kd(e){let t=e.trim().match(/^\[Subagent (?:completed|failed|killed)\][^\n]*(?:\n\n([\s\S]*))?$/);return t?t[1]?.trim()||`(no output)`:e}async function qd(e,t,n){let{registry:r,parentSessionId:i,parentSessionDir:a,depth:o,dataDir:s,channel:c,llm:l,loopDetection:u,inheritedRunParams:d,spawnFn:f}=e,p=n.task.trim(),m=n.label?.trim(),h=n.agent?.trim();if(X.info(`subagent spawn requested`,{parentSessionId:i,depth:o+1,label:m,requestedAgentName:h,taskLength:p.length,taskPreview:fa(p)}),!p){let e={status:`error`,error:`task must not be empty`};return X.warn(`subagent spawn rejected`,{parentSessionId:i,depth:o+1,reason:e.error}),{content:[{type:`text`,text:JSON.stringify(e)}],details:e}}let g=r.checkSpawnAllowed(i,o+1);if(!g.allowed){let e={status:`forbidden`,error:g.reason};return X.warn(`subagent spawn rejected`,{parentSessionId:i,depth:o+1,reason:e.error}),{content:[{type:`text`,text:JSON.stringify(e)}],details:e}}let _=Ge(),v=new AbortController,y=t,b=Nr(d.agentPolicy?.availableAgents??[],h);if(h&&!b){let e={status:`error`,error:`Unknown custom agent: ${h}`};return X.warn(`subagent spawn rejected`,{parentSessionId:i,depth:o+1,requestedAgentName:h,reason:e.error}),{content:[{type:`text`,text:JSON.stringify(e)}],details:e}}let x={parentSessionId:i,parentDir:a};try{await C(s,c,{storeName:d.sessionStoreName,subagent:x,sessionId:y})}catch(e){let t={status:`error`,error:`Failed to create session: ${e instanceof Error?e.message:String(e)}`};return X.error(`subagent session creation failed`,{parentSessionId:i,depth:o+1,error:t.error}),{content:[{type:`text`,text:JSON.stringify(t)}],details:t}}X.info(`subagent session created`,{parentSessionId:i,childSessionId:y,depth:o+1,runId:_,requestedAgentName:h,selectedAgent:b?.name});let S={runId:_,childSessionId:y,parentSessionId:i,task:p,label:m,depth:o+1,status:`running`,startedAt:Date.now(),abortController:v};await d.onProgress?.({type:`subagent_spawn`,childSessionId:y,task:p,label:m,sessionId:i,messageId:d.messageId,depth:o+1});let w=f({dataDir:s,sessionId:y,message:b?zr(b,p):p,channel:c,llm:b?.model?{...l,model:b.model}:l,...d,agentPolicy:{availableAgents:d.agentPolicy?.availableAgents??[],...b?{activeAgent:b}:{}},loopDetection:u,abortSignal:v.signal,sessionPathScope:{subagent:{parentSessionId:i,parentDir:a}},subagentContext:{depth:o+1,parentSessionId:i}}).then(e=>{if(e.error){r.fail(_,e.error);return}r.complete(_,e.text||`(no output)`)}).catch(e=>{let t=e instanceof Error?e.message:String(e);r.fail(_,t)});r.register(S,w),X.info(`subagent run registered`,{runId:_,parentSessionId:i,childSessionId:y,depth:o+1,selectedAgent:b?.name}),await w,X.info(`subagent run settled`,{runId:_,parentSessionId:i,childSessionId:y,status:S.status,durationMs:S.endedAt?S.endedAt-S.startedAt:void 0,hasError:!!S.error}),r.markAnnounced(_),await d.onProgress?.({type:`subagent_complete`,childSessionId:y,task:p,status:S.status,sessionId:i,messageId:d.messageId,depth:o+1});let T=Gd({task:p,label:m,status:S.status,result:S.result,error:S.error});if(S.status===`done`){let e={status:`done`,childSessionId:y,runId:_,result:S.result??``};return X.info(`subagent spawn completed`,{runId:_,parentSessionId:i,childSessionId:y,status:e.status,resultLength:e.result.length}),{content:[{type:`text`,text:T}],details:e}}let E=S.status===`killed`?{status:`killed`,childSessionId:y,runId:_,error:`subagent killed`}:{status:`error`,childSessionId:y,runId:_,error:S.error??`unknown error`};return X.warn(`subagent spawn completed with non-success status`,{runId:_,parentSessionId:i,childSessionId:y,status:E.status,error:E.error}),{content:[{type:`text`,text:T}],isError:!0,details:E}}function Jd(e,t,n,r,i,a,o,s,c,l){let u={registry:e,parentSessionId:t,parentSessionDir:n,depth:r,dataDir:i,channel:a,llm:o,loopDetection:s,inheritedRunParams:c,spawnFn:l};return{name:`subagent_spawn`,label:`Spawn Subagent`,description:`Spawn an isolated subagent session to delegate a task. `+(r===0?"IMPORTANT: You MUST use this tool whenever the user explicitly mentions 'subagent', '@subagent', or asks for subagent-based execution. You MUST also use this tool when the user mentions '@<agent-name>' where <agent-name> matches a custom agent listed in the Custom Agents section — set the `agent` field to that exact name. Do not use it for routine decomposition or inferred parallelism — only when the user or system instructions explicitly require subagent delegation or parallel agent execution. ":`WARNING: You are already running as a subagent (depth ${r}). Spawning further subagents creates deeply nested hierarchies that are expensive and error-prone. Only use this tool if the current task genuinely cannot be completed with available tools directly. Prefer direct tool calls (exec, read_file, write_file, etc.) over spawning another subagent. `)+`Waits for the subagent to finish and returns the final subagent result as this tool call's result.`,parameters:Ud,async execute(e,t){return qd(u,e,t)}}}function Yd(e,t,n,r,i,a,o,s,c,l){let u={registry:e,parentSessionId:t,parentSessionDir:n,depth:r,dataDir:i,channel:a,llm:o,loopDetection:s,inheritedRunParams:c,spawnFn:l};return{name:`batch_subagent_spawn`,label:`Batch Spawn Subagents`,description:`Spawn multiple isolated subagent sessions from one tool call, running at most 5 subagents concurrently. Use this when the user explicitly asks for parallel subagent execution or when several independent subagent tasks should be delegated together. Each task waits for its subagent to finish; the tool returns all final subagent results in input order.`,parameters:Wd,async execute(n,i){let a=i.tasks??[];if(a.length===0){let e={status:`error`,results:[]};return{content:[{type:`text`,text:JSON.stringify({...e,error:`tasks must not be empty`})}],isError:!0,details:e}}X.info(`batch subagent spawn requested`,{parentSessionId:t,depth:r+1,taskCount:a.length,concurrencyLimit:5});let o=Array(a.length),s=0,c=Math.max(0,5-e.countActive(t)),l=Math.min(5,c,a.length);if(l===0){let n=e.checkSpawnAllowed(t,r+1),i=n.allowed?`Maximum concurrent subagents (5) reached for this session`:n.reason;for(let[e,t]of a.entries())o[e]={status:`forbidden`,error:i,index:e,task:t.task.trim(),label:t.label?.trim()}}else{let e=async()=>{for(;s<a.length;){let e=s++,t=a[e];o[e]={...(await qd(u,`${n}-${e+1}`,t)).details,index:e,task:t.task.trim(),label:t.label?.trim()}}};await Promise.all(Array.from({length:l},()=>e()))}let d=o.filter(e=>e.status!==`done`),f=d.length===0?`done`:d.length===o.length?`error`:`partial_error`,p={status:f,results:o},m=[`Batch subagents: ${o.length-d.length}/${o.length} completed.`,...o.map(e=>{let t=e.label?`"${e.label}"`:`#${e.index+1}`;return e.status===`done`?`- ${t}: done\n${Kd(e.result)}`:`- ${t}: ${e.status}\n${e.error}`})].join(`
|
|
87
87
|
|
|
88
88
|
`);return f===`done`?{content:[{type:`text`,text:m}],details:p}:{content:[{type:`text`,text:m}],isError:!0,details:p}}}}const Xd=K.Object({action:K.Union([`list`,`kill`].map(e=>K.Literal(e)),{description:`Action to perform: "list" to show subagents, "kill" to stop one or all`}),target:K.Optional(K.String({description:`For kill: a runId, label, or index from the list. Use "*" or "all" to kill every subagent.`}))});function Zd(e){return e<1e3?`${e}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m${Math.floor(e%6e4/1e3)}s`}function Qd(e,t){let n=parseInt(t,10);return!isNaN(n)&&n>=1&&n<=e.length?e[n-1]:e.find(e=>e.runId.startsWith(t)||e.runId===t)||(e.find(e=>e.label&&e.label.toLowerCase()===t.toLowerCase())??null)}function $d(e,t){return{name:`subagents`,label:`Subagents`,description:`List or kill subagents spawned by this session. Use list to check status, kill to stop one or all.`,parameters:Xd,async execute(n,r){let i=r.action,a=Date.now(),o=e.list(t);if(i===`list`){let t=o.map((t,n)=>{let r=t.status===`running`?`running`:e.isAnnounced(t.runId)?`delivered`:`pending`;return{index:n+1,runId:t.runId,label:t.label??t.task.slice(0,40),task:t.task,status:t.status,deliveryStatus:r,depth:t.depth,runtimeMs:t.endedAt?t.endedAt-t.startedAt:a-t.startedAt,...t.result===void 0?{}:{result:t.result},...t.error===void 0?{}:{error:t.error}}}),n={action:`list`,runs:t,text:(t.length===0?[`(no subagents)`]:t.map(e=>{let t=e.deliveryStatus===`running`?``:`, ${e.deliveryStatus}`,n=e.result===void 0?e.error===void 0?``:`\n error: ${e.error}`:`\n result: ${e.result}`;return`${e.index}. [${e.status}${t}] ${e.label} (${Zd(e.runtimeMs)})${n}`})).join(`
|
|
89
89
|
`)};return{content:[{type:`text`,text:JSON.stringify(n)}],details:n}}if(i===`kill`){let n=r.target?.trim();if(!n||n===`*`||n===`all`){let n=e.killAll(t),r={action:`kill`,killed:n,text:n>0?`Killed ${n} subagent(s).`:`No running subagents to kill.`};return{content:[{type:`text`,text:JSON.stringify(r)}],details:r}}let i=Qd(o,n);if(!i){let e={action:`kill`,killed:0,error:`No subagent found matching "${n}". Use list to see available subagents.`,text:`Error: no subagent matching "${n}"`};return{content:[{type:`text`,text:JSON.stringify(e)}],details:e}}let a=e.kill(i.runId),s=i.label??i.task.slice(0,40),c={action:`kill`,killed:a?1:0,text:a?`Killed subagent "${s}".`:`Subagent "${s}" is already finished.`};return{content:[{type:`text`,text:JSON.stringify(c)}],details:c}}let s={action:i,error:`Unsupported action.`,text:`Error: unsupported action.`};return{content:[{type:`text`,text:JSON.stringify(s)}],details:s}}}}const ef=K.Object({image:K.String({description:`Image path or URL`}),prompt:K.Optional(K.String({description:`Prompt for image analysis`})),model:K.Optional(K.String({description:`Optional model override`})),maxBytesMb:K.Optional(K.Number({description:`Optional size cap in MB`}))});function tf(){return{name:`image`,label:`Image`,description:`Analyze an image with the configured image model. (Not implemented in AIMax yet.)`,parameters:ef,async execute(e,t){let n={implemented:!1,error:`image tool not implemented (awaiting third-party integration).`};return{content:[{type:`text`,text:`Error: ${n.error}`}],details:n}}}}const nf=K.Object({reason:K.String({description:`A brief explanation of why user input is needed through this UI form.`})});function rf(e){let{name:t,label:n,description:r,sessionId:i,inputSchema:a,outputSchema:o,extra:s,validate:c,resume:l}=e;return{name:t,label:n,description:r,parameters:a??nf,async execute(e,n){if(l&&l.toolCallId===e&&l.toolName===t&&l.sessionId===i){let e=Be(o,l.values);if(!e.valid){let t=e.errors;return{content:[{type:`text`,text:JSON.stringify({error:`validation_failed`,errors:t})}],details:{}}}if(c){let e=await c(l.values);if(!e.valid){let t=e.errors;return{content:[{type:`text`,text:JSON.stringify({error:`validation_failed`,errors:t})}],details:{}}}}return{content:[{type:`text`,text:JSON.stringify({submitted:!0,values:l.values})}],details:{}}}let r=new li(e,i,t,e,o,s,n);throw vi(r),r}}}function af(e,t){let n=G.join(e,`workspace`),r=t?.memoryOptions,i=tu(),a=t?.autoSkillsLoadEnabled??!1,o=t?.sessionId,s=t?.channel!==`CRON`&&o?async n=>{await O(e,o,{...n,source:(t.depth??0)>0?`subagent`:`agent`,sessionId:t.runtimeSessionId??t.sessionId},{storeName:t.inheritedRunParams?.sessionStoreName})}:void 0,c=[Bl({sessionId:t?.sessionId,workspaceDir:n,registry:i,scopeKey:n,contextManager:t?.contextManager,hitlResume:t?.hitlResume}),Wl({registry:i,scopeKey:n}),cu(n,t?.contextManager),uu(n,t?.contextManager,s),fu(n,t?.contextManager,s),mu(n),xu(n,{sessionId:t?.sessionId,hitlResume:t?.hitlResume,artifactRecorder:s}),...t?.sessionId?[zd(e,t.sessionId,t.inheritedRunParams?.sessionStoreName),Vd(e,t.sessionId,t.inheritedRunParams?.sessionStoreName,t.eventDispatcher,t.sessionId)]:[],qu(e,r),hd(e,r),Yu(e,r),$u(e,r),sd(e,r),ld(e,r),dd(e,r),pd(e,r),Id(e,t?.pluginSkillDirs??[],t?.skillsLoadPaths??[]),Ld({dataDir:e,pluginDirs:t?.pluginSkillDirs??[],skillsLoadPaths:t?.skillsLoadPaths??[],sessionId:t?.sessionId??`unknown`,reportSkillUsed:t?.reportSkillUsed})];return a&&c.push(fo(e),po(e),mo(e),ho(e)),t&&c.push(Jd(t.registry,t.parentSessionId,t.currentSessionDir,t.depth,e,t.channel,t.llm,t.loopDetection,t.inheritedRunParams??{},t.spawnFn),Yd(t.registry,t.parentSessionId,t.currentSessionDir,t.depth,e,t.channel,t.llm,t.loopDetection,t.inheritedRunParams??{},t.spawnFn),$d(t.registry,t.parentSessionId)),c}function of(e){return e.length===0?``:[`## Auto-Skills`,`Auto-skills are learned from prior completed tasks and are stored separately from curated/user/plugin skills.`,`Auto-skill categories are single-level routing slugs in the current MVP.`,`Prefer curated/user/plugin skills from <available_skills> when both options apply.`,`Use auto-skills only when they clearly match the current task, especially project-specific or previously learned workflows.`,"Match the task to one or more category paths below, call `auto_skill_list({ categoryPath })`, then call `auto_skill_view({ skillId })` for the best match.","If no category is clear but an auto-skill may help, call `auto_skill_search({ query, limit: 5 })`.",`Archived auto-skills are not listed or loaded.`,`<auto_skill_categories>`,[...e].sort((e,t)=>e.path.localeCompare(t.path)).map(e=>e.description?` - ${e.path} | ${e.description}`:` - ${e.path}`).join(`
|