aws-runtime-bridge 1.9.98 → 1.9.101
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/dist/adapter/AcodeSdkAdapter.d.ts +7 -1
- package/dist/adapter/AcodeSdkAdapter.js +5 -5
- package/dist/adapter/ClaudeSdkAdapter.d.ts +4 -0
- package/dist/adapter/ClaudeSdkAdapter.js +2 -2
- package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
- package/dist/adapter/CodexSdkAdapter.js +3 -3
- package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/OpencodeSdkAdapter.js +2 -2
- package/dist/adapter/idle-poll-loop.d.ts +4 -1
- package/dist/adapter/idle-poll-loop.js +1 -1
- package/dist/adapter/types.d.ts +4 -2
- package/dist/browser/browser-bootstrap.d.ts +11 -0
- package/dist/browser/browser-bootstrap.js +4 -0
- package/dist/browser/browser-connect-token.d.ts +10 -0
- package/dist/browser/browser-connect-token.js +2 -0
- package/dist/browser/browser-pool.d.ts +75 -0
- package/dist/browser/browser-pool.js +2 -0
- package/dist/browser/browser-profile-store.d.ts +28 -0
- package/dist/browser/browser-profile-store.js +2 -0
- package/dist/browser/browser-ws-bridge.d.ts +12 -0
- package/dist/browser/browser-ws-bridge.js +6 -0
- package/dist/browser/built-in-browser-tools.d.ts +27 -0
- package/dist/browser/built-in-browser-tools.js +2 -0
- package/dist/browser/element-locator.d.ts +24 -0
- package/dist/browser/element-locator.js +2 -0
- package/dist/browser/element-picker.d.ts +17 -0
- package/dist/browser/element-picker.js +2 -0
- package/dist/browser/input-dispatcher.d.ts +34 -0
- package/dist/browser/input-dispatcher.js +2 -0
- package/dist/browser/listener-store.d.ts +32 -0
- package/dist/browser/listener-store.js +2 -0
- package/dist/browser/page-listener-manager.d.ts +106 -0
- package/dist/browser/page-listener-manager.js +307 -0
- package/dist/browser/page-listener-types.d.ts +90 -0
- package/dist/browser/page-listener-types.js +1 -0
- package/dist/browser/screencast-manager.d.ts +42 -0
- package/dist/browser/screencast-manager.js +2 -0
- package/dist/browser/snapshot-serializer.d.ts +15 -0
- package/dist/browser/snapshot-serializer.js +5 -0
- package/dist/browser/ssrf-guard.d.ts +15 -0
- package/dist/browser/ssrf-guard.js +2 -0
- package/dist/browser/stealth.d.ts +7 -0
- package/dist/browser/stealth.js +173 -0
- package/dist/browser/step-archive.d.ts +52 -0
- package/dist/browser/step-archive.js +2 -0
- package/dist/browser/types.d.ts +192 -0
- package/dist/browser/types.js +2 -0
- package/dist/browser/ws-server.d.ts +67 -0
- package/dist/browser/ws-server.js +2 -0
- package/dist/index.js +1 -1
- package/dist/middleware/auth.d.ts +2 -0
- package/dist/middleware/auth.js +1 -1
- package/dist/remote-desktop/computer-control.d.ts +30 -0
- package/dist/remote-desktop/computer-control.js +2 -0
- package/dist/remote-desktop/coords.d.ts +13 -0
- package/dist/remote-desktop/coords.js +2 -0
- package/dist/remote-desktop/frame-backpressure.d.ts +7 -0
- package/dist/remote-desktop/frame-backpressure.js +2 -0
- package/dist/remote-desktop/index.d.ts +7 -0
- package/dist/remote-desktop/index.js +4 -0
- package/dist/remote-desktop/input-backends/interface.d.ts +17 -0
- package/dist/remote-desktop/input-backends/interface.js +1 -0
- package/dist/remote-desktop/input-backends/key-map.d.ts +2 -0
- package/dist/remote-desktop/input-backends/key-map.js +2 -0
- package/dist/remote-desktop/input-dispatcher.d.ts +11 -0
- package/dist/remote-desktop/input-dispatcher.js +2 -0
- package/dist/remote-desktop/permission-manager.d.ts +7 -0
- package/dist/remote-desktop/permission-manager.js +2 -0
- package/dist/remote-desktop/screen-capture.d.ts +27 -0
- package/dist/remote-desktop/screen-capture.js +2 -0
- package/dist/remote-desktop/session-manager.d.ts +59 -0
- package/dist/remote-desktop/session-manager.js +2 -0
- package/dist/remote-desktop/system-backend.d.ts +65 -0
- package/dist/remote-desktop/system-backend.js +5 -0
- package/dist/remote-desktop/types.d.ts +68 -0
- package/dist/remote-desktop/types.js +1 -0
- package/dist/remote-desktop/ui-automation.d.ts +48 -0
- package/dist/remote-desktop/ui-automation.js +31 -0
- package/dist/remote-desktop/win32-api.d.ts +29 -0
- package/dist/remote-desktop/win32-api.js +2 -0
- package/dist/routes/background-tasks.d.ts +2 -0
- package/dist/routes/background-tasks.js +2 -0
- package/dist/routes/browser-listeners.d.ts +2 -0
- package/dist/routes/browser-listeners.js +2 -0
- package/dist/routes/browser-sessions.d.ts +2 -0
- package/dist/routes/browser-sessions.js +2 -0
- package/dist/routes/pty.js +3 -3
- package/dist/routes/terminal.js +30 -30
- package/dist/services/agent-pty-manager.d.ts +22 -0
- package/dist/services/agent-pty-manager.js +5 -0
- package/dist/services/browser-session-manager.d.ts +55 -0
- package/dist/services/browser-session-manager.js +12 -0
- package/dist/services/cli-commands.d.ts +4 -0
- package/dist/services/cli-commands.js +5 -5
- package/package/acode/dist/await-complete-tool.d.ts +17 -0
- package/package/acode/dist/await-complete-tool.js +21 -0
- package/package/acode/dist/background-command-manager.d.ts +148 -0
- package/package/acode/dist/background-command-manager.js +8 -0
- package/package/acode/dist/background-command-store.d.ts +46 -0
- package/package/acode/dist/background-command-store.js +2 -0
- package/package/acode/dist/background-command-tools.d.ts +5 -0
- package/package/acode/dist/background-command-tools.js +18 -0
- package/package/acode/dist/background-output-ringbuffer.d.ts +23 -0
- package/package/acode/dist/background-output-ringbuffer.js +3 -0
- package/package/acode/dist/built-in-file-tools.d.ts +8 -1
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/compaction.js +6 -6
- package/package/acode/dist/index.d.ts +1 -0
- package/package/acode/dist/index.js +1 -1
- package/package/acode/dist/runtime.d.ts +6 -0
- package/package/acode/dist/runtime.js +27 -27
- package/package/acode/dist/sub-agent-tools.d.ts +0 -1
- package/package/acode/dist/sub-agent-tools.js +11 -28
- package/package/acode/dist/terminal-tool.d.ts +7 -0
- package/package/acode/dist/terminal-tool.js +2 -0
- package/package/acode/dist/terminal-types.d.ts +38 -0
- package/package/acode/dist/terminal-types.js +1 -0
- package/package/acode/dist/types.d.ts +10 -1
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +3 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/logger.js +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +8 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.js +30 -19
- package/package/aws-client-agent-mcp/dist/types.d.ts +25 -0
- package/package.json +6 -2
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import{EventEmitter as De}from"node:events";import F from"node:fs";import Oe from"node:os";import K from"node:path";import{Client as Ue}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as qe}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as Be}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as ze}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{createBuiltInFileTools as Fe}from"./built-in-file-tools.js";import{ASK_USER_QUESTION_TOOL_NAME as je,createAskUserQuestionTool as We}from"./ask-user-question-tool.js";import{createSkillTool as Je}from"./skill-tool.js";import{createTodoWriteTool as Ke,createTodoReadTool as He}from"./todo-tool.js";import{createSubAgentTools as Ge}from"./sub-agent-tools.js";import{cleanupAcodeCmdDist as Qe}from"./builtins/commandArtifacts.js";import{loadAcodeCommands as Ye}from"./commands/commandLoader.js";import{ACodeCommandRegistry as ce}from"./commands/commandRegistry.js";import{calculateCompactionThreshold as Ve,COMPACTION_LLM_PROMPT_TEMPLATE as Xe,conversationSizeKB as j,estimateConversationTokens as H,performCompaction as le,pruneToolOutputs as Ze,summarizeConversation as me}from"./compaction.js";import{loadAcodeConfig as et,loadAcodeSkillGroup as tt}from"./config.js";import{ACodeHookBus as ot,findDeniedHookResult as X}from"./hooks/hookBus.js";import{isMcpPollingToolName as nt,getSemanticToolName as st}from"./mcpToolNames.js";function it(o){return o.type==="text"?{type:"text",text:o.text}:{type:"image_url",image_url:{url:o.image_url.url}}}function rt(o){return{id:o.id,type:"function",function:{name:o.function.name,arguments:o.function.arguments}}}function at(o){const e={role:o.role,content:Array.isArray(o.content)?o.content.map(it):o.content};return o.tool_call_id&&(e.tool_call_id=o.tool_call_id),o.tool_calls&&(e.tool_calls=o.tool_calls.map(rt)),e}function Z(o){return o.map(at)}function ut(){return new Date().toISOString()}function k(o){return!!(o&&typeof o=="object"&&!Array.isArray(o))}function de(o){return k(o)}function N(o){return String(o??"").trim()||void 0}const pe=6e4,he=10*6e4,fe=2,ee=-1,ct=1e3,G=6e4,ge=0,lt=2147483647,mt=new Set(["create_memory","read_memory","update_memory","delete_memory","search_memory","list_memories","get_memory_stats","list_memories_by_file","memory_recurrence","memory_recurrence_complete"]),dt=new Set(["write_file","edit_file","delete_file"]),pt=10*6e4+2e3,ht=1e4,ye=5e3,Ce=10*60*1e3,Ae=10*1024*1024,Te=800*1024,Q=process.env.ACODE_COMPACTION_DEBUG==="1",_e=Q?K.join(Oe.tmpdir(),"acode-compaction-debug.log"):"";function c(...o){Q&&console.log(...o)}const ft=64e3;function te(o){const e=o.contextLimit&&o.contextLimit>0?o.contextLimit:ft,t=o.maxOutput&&o.maxOutput>0?o.maxOutput:8192,n=o.inputLimit&&o.inputLimit>0?o.inputLimit:void 0,i=Ve(e,t,n);return{contextLimit:e,maxOutput:t,inputLimit:n,threshold:i}}async function v(o,e,t,n){if(e<=0)return await o;let i;try{return await new Promise((a,s)=>{i=setTimeout(()=>{n?.(),s(new Error(`${t} timed out after ${e}ms`))},e),o.then(a,s)})}finally{i&&clearTimeout(i)}}async function oe(o,e,t,n=ht){try{await v(e,n,o)}catch(i){t(i instanceof Error?i.message:String(i))}}function q(o,e){if(o===0||o==="0")return 0;const t=typeof o=="number"?o:Number(o);return t===ee?ee:Number.isFinite(t)&&t>0?Math.floor(t):e}function ne(o,e){const t=q(o,e);return t>0?t:e}const we=3;function be(o){return o?Math.ceil(o.length/we):0}function gt(o,e){let t=o.length;for(const n of e){const i=(n.kind==="mcp",n.toolName);if(t+=i.length,n.kind==="mcp")n.description&&(t+=n.description.length),t+=JSON.stringify(n.inputSchema).length;else{const a=n;a.inputSchema&&(t+=JSON.stringify(a.inputSchema).length)}}return Math.ceil(t/we)}function $e(o){if(o.length===0)return 0;const e=JSON.stringify(Ne(o));return be(e)}async function yt(o){await new Promise(e=>setTimeout(e,o))}function Ct(o){return typeof o=="boolean"}function At(o,e,t){if(Ct(t?.supportsImageInput))return t.supportsImageInput;const n=k(e)?e.models:void 0,i=k(n)?n[o]:void 0;if(!k(i))return!1;const a=i.modalities;return!k(a)||!Array.isArray(a.input)?!1:a.input.some(s=>String(s||"").trim().toLowerCase()==="image")}function se(o,e,t,n){if(o!==void 0)return o;if(!e)return;const i=e.models;if(k(i)){const a=i[t];if(k(a)){const s=a[n];if(s!==void 0)return s}}return e[n]}function Tt(o,e){const t=e.provider?.default,n=t?.options,i=o.model||t?.model||e.model||"acode-default",a=N(o.effort)||N(n?.effort)||N(t?.effort)||void 0;return{model:i,baseURL:N(n?.baseURL||n?.baseUrl),apiKey:N(n?.apiKey),effort:a,systemPrompt:o.systemPrompt||e.systemPrompt,stream:n?.stream!==!1,requestTimeoutMs:ne(n?.requestTimeoutMs??n?.timeoutMs,pe),requestTotalTimeoutMs:ne(n?.requestTotalTimeoutMs,he),requestRetryCount:q(n?.requestRetryCount,fe),mcpToolTimeoutMs:ne(n?.mcpToolTimeoutMs,G),mcpPollingToolTimeoutMs:q(n?.mcpPollingToolTimeoutMs,ge),supportsImageInput:At(i,t,n),contextLimit:q(se(n?.contextLimit,t,i,"contextLimit"),0)||void 0,inputLimit:q(se(n?.inputLimit,t,i,"inputLimit"),0)||void 0,maxOutput:q(se(n?.maxOutput,t,i,"maxOutput"),0)||void 0}}function O(o,e){const t=e.replace(/\s+/g," ").trim();t&&o.push({type:"text",text:t})}function _t(o,e){const t=e.trim();return/^data:image\/[a-z0-9.+-]+;base64,/i.test(t)?t:`data:${o||"image/png"};base64,${t}`}function wt(o){return/^data:image\/[a-z0-9.+-]+;base64,/i.test(o.trim())}function bt(o){let e;try{e=new URL(o)}catch{throw new Error(`ACode image URL is invalid: ${o}`)}if(e.protocol!=="http:"&&e.protocol!=="https:")throw new Error(`ACode image URL protocol is not supported: ${e.protocol}`)}async function $t(o){const e=await o.arrayBuffer();if(e.byteLength>Ae)throw new Error(`ACode image is too large to inline: ${e.byteLength} bytes exceeds ${Ae} bytes`);return Buffer.from(e).toString("base64")}async function Rt(o){const e=o.trim();if(wt(e))return e;bt(e);const t=await fetch(e);if(!t.ok)throw new Error(`ACode image fetch failed: ${t.status} ${await t.text()}`);const n=t.headers.get("content-type")||"",i=n.split(";")[0]?.trim().toLowerCase()||"";if(!i.startsWith("image/"))throw new Error(`ACode image URL did not return an image content type: ${n||"unknown"}`);return`data:${i};base64,${await $t(t)}`}function kt(o){const e=N(o.base64Data??o.base64??o.data);return e?_t(N(o.mediaType??o.mimeType)||"image/png",e):N(o.url??o.serverUrl)}function Re(o,e,t,n){return`[Attached file: ${[o?`name=${o}`:void 0,e?`url=${e}`:void 0,t?`mediaType=${t}`:void 0,n?`size=${n}`:void 0].filter(a=>!!a).join(", ")}]`}function Mt(o){const e=/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,t=[];let n=!1,i=0,a=e.exec(o);for(;a!==null;){O(t,o.slice(i,a.index));const s=a[1],r=(a[2]||"").trim();if(s==="\u56FE\u7247"&&r)t.push({type:"image_url",image_url:{url:r}}),n=!0;else if(s==="\u6587\u4EF6"&&r){const[u="",m="",l="",f=""]=r.split("|").map(y=>y.trim());O(t,Re(u,m,l,f))}else O(t,a[0]);i=a.index+a[0].length,a=e.exec(o)}return t.length===0?{content:o,hasImages:!1}:(O(t,o.slice(i)),{content:t,hasImages:n})}function St(o,e){let t=!1;const n=[e.directMessages,e.groupMessages];for(const i of n)if(Array.isArray(i))for(const a of i){if(!k(a))continue;const s=N(a.content);if(!s)continue;const r=N(a.senderName);O(o,r?`Message from ${r}:`:"Message:");const u=ie(s);Array.isArray(u.content)?o.push(...u.content):O(o,u.content),t=t||u.hasImages}return t}function vt(o){let e;try{e=JSON.parse(o)}catch{return}if(!k(e))return;const t=[];let n=St(t,e);const i=N(e.text)||"",a=Array.isArray(e.attachments)?e.attachments:[];O(t,i);for(const s of a){if(!k(s))continue;const r=s;if(String(r.type??r.kind??"").toLowerCase()==="image"){const l=kt(r);l&&(t.push({type:"image_url",image_url:{url:l}}),n=!0);continue}const m=N(r.url??r.serverUrl)||"";O(t,Re(N(r.name)||"",m,N(r.mediaType??r.mimeType)||"",N(r.size)||""))}return t.length===0?{content:o,hasImages:!1}:{content:t,hasImages:n}}function ie(o){return vt(o)??Mt(o)}async function ke(o){if(!Array.isArray(o))return o;const e=[];for(const t of o){if(t.type==="text"){e.push(t);continue}e.push({type:"image_url",image_url:{url:await Rt(t.image_url.url)}})}return e}function xt(o){return typeof o=="string"?o:Array.isArray(o)?o.map(e=>e.type==="text"?e.text:"[Image]").join(" ").trim():""}function Et(o,e){const t=o.permissions??e.permissions??{},n=o.permissions?[]:e.allowedTools??[],i=o.permissions?[]:e.deniedTools??[];return{mode:t.mode??"default",allow:[...t.allow??[],...n].map(a=>a.trim()).filter(Boolean),deny:[...t.deny??[],...i].map(a=>a.trim()).filter(Boolean)}}function Nt(o,e){return o==="*"?!0:o.endsWith("*")?e.startsWith(o.slice(0,-1)):o===e}function It(o){return o.kind==="builtin"?[o.exposedName,o.toolName,`builtin.${o.toolName}`]:[o.exposedName,o.toolName,`${o.serverName}.${o.toolName}`,`mcp.${o.serverName}.${o.toolName}`]}function Me(o,e){return It(e).some(t=>Nt(o,t))}function Se(o,e,t){if(e.length>0&&!e.some(n=>Me(n,o)))throw new Error(t)}function re(o,e,t){if(e.mode!=="bypassPermissions"){if(e.deny.some(n=>Me(n,o)))throw new Error(`ACode tool denied by permission rule: ${o.exposedName}`);Se(o,e.allow,`ACode tool is not in allowed permission rules: ${o.exposedName}`),Se(o,t??[],`ACode slash command does not allow tool: ${o.exposedName}`)}}function Lt(o,e,t){try{return re(o,e,t),!0}catch{return!1}}function Y(o){const e=o.replace(/\/+$/g,"");return/\/chat\/completions$/i.test(e)?e:`${e}/chat/completions`}function Pt(o){try{const e=new URL(o);e.search="",e.hash="";const t=new URL(Y(e.toString()));return`${t.origin}${t.pathname}`}catch{return Y(o).replace(/([?&](?:api[_-]?key|token|authorization)=)[^&]+/gi,"$1[redacted]")}}function Dt(o){const e=[...o].reverse().find(n=>n.role==="user"),t=xt(e?.content??null).trim();if(t)return t.length>300?`${t.slice(0,300)}...`:t}function ve(o){try{const e=JSON.parse(o);return de(e)?e:{}}catch{return{}}}function Ot(o,e,t){if(new Set([je,"await_sub_agents"]).has(o.toolName))return 0;if(o.toolName!=="Bash")return t;const i=e.timeout_ms??e.timeoutMs,a=typeof i=="number"?i:typeof i=="string"?Number(i):NaN;return!Number.isFinite(a)||a<=0?Math.max(t,pt):Math.min(Math.floor(a),10*6e4)+2e3}function Ut(o,e){const t=o.trim();return`ACode \u5DF2\u63A5\u6536\u4EFB\u52A1\u3002\u5F53\u524D\u5DF2\u52A0\u8F7D ${e.configMcpCount} \u4E2A MCP \u914D\u7F6E\u3001${e.exposedTools.length} \u4E2A MCP Tool \u4E0E ${e.skills.length} \u4E2A Skill\u3002${t?`\u8F93\u5165\u6458\u8981\uFF1A${t.slice(0,200)}`:""}`}function P(o){if(!k(o))return String(o??"");const e=o.content;if(Array.isArray(e)){const t=e.map(n=>k(n)?typeof n.text=="string"?n.text:JSON.stringify(n):"").filter(Boolean);if(t.length>0)return t.join(`
|
|
2
|
-
`)}return JSON.stringify(
|
|
3
|
-
`)}function
|
|
4
|
-
`)}function
|
|
1
|
+
import{EventEmitter as Fe}from"node:events";import J from"node:fs";import je from"node:os";import V from"node:path";import{Client as We}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as Je}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as Ke}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as Qe}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{createBuiltInFileTools as He}from"./built-in-file-tools.js";import{ASK_USER_QUESTION_TOOL_NAME as Ge,createAskUserQuestionTool as Ye}from"./ask-user-question-tool.js";import{createSkillTool as Ve}from"./skill-tool.js";import{createTodoWriteTool as Xe,createTodoReadTool as Ze}from"./todo-tool.js";import{createSubAgentTools as et}from"./sub-agent-tools.js";import{createAwaitCompleteTool as tt}from"./await-complete-tool.js";import{cleanupAcodeCmdDist as ot}from"./builtins/commandArtifacts.js";import{backgroundCommandManager as K}from"./background-command-manager.js";import{createTerminalTool as nt}from"./terminal-tool.js";import{loadAcodeCommands as st}from"./commands/commandLoader.js";import{ACodeCommandRegistry as pe}from"./commands/commandRegistry.js";import{calculateCompactionThreshold as it,COMPACTION_LLM_PROMPT_TEMPLATE as rt,conversationSizeKB as Q,estimateConversationTokens as X,performCompaction as he,pruneToolOutputs as at,summarizeConversation as fe}from"./compaction.js";import{loadAcodeConfig as ut,loadAcodeSkillGroup as ct}from"./config.js";import{ACodeHookBus as lt,findDeniedHookResult as se}from"./hooks/hookBus.js";import{isMcpPollingToolName as mt,getSemanticToolName as ge}from"./mcpToolNames.js";function dt(n){return n.type==="text"?{type:"text",text:n.text}:{type:"image_url",image_url:{url:n.image_url.url}}}function pt(n){return{id:n.id,type:"function",function:{name:n.function.name,arguments:n.function.arguments}}}function ht(n){const e={role:n.role,content:Array.isArray(n.content)?n.content.map(dt):n.content};return n.tool_call_id&&(e.tool_call_id=n.tool_call_id),n.tool_calls&&(e.tool_calls=n.tool_calls.map(pt)),e}function ie(n){return n.map(ht)}function ft(){return new Date().toISOString()}function v(n){return!!(n&&typeof n=="object"&&!Array.isArray(n))}function ye(n){return v(n)}function I(n){return String(n??"").trim()||void 0}const Z=6e4,Ae=10*6e4,Ce=2e4,Te=3e4,_e=3,re=-1,gt=1e3,yt=3e4,ee=6e4,we=0,At=2147483647,Ct=new Set(["create_memory","read_memory","update_memory","delete_memory","search_memory","list_memories","get_memory_stats","list_memories_by_file","memory_recurrence","memory_recurrence_complete"]),Tt=new Set(["write_file","edit_file","delete_file"]),_t=10*6e4+2e3,wt=1e4,be=5e3,$e=10*60*1e3,Me=10*1024*1024,Re=800*1024,te=process.env.ACODE_COMPACTION_DEBUG==="1",ke=te?V.join(je.tmpdir(),"acode-compaction-debug.log"):"";function m(...n){te&&console.log(...n)}const bt=64e3;function ae(n){const e=n.contextLimit&&n.contextLimit>0?n.contextLimit:bt,t=n.maxOutput&&n.maxOutput>0?n.maxOutput:8192,o=n.inputLimit&&n.inputLimit>0?n.inputLimit:void 0,s=it(e,t,o);return{contextLimit:e,maxOutput:t,inputLimit:o,threshold:s}}async function x(n,e,t,o){if(e<=0)return await n;let s;try{return await new Promise((a,i)=>{s=setTimeout(()=>{o?.(),i(new Error(`${t} timed out after ${e}ms`))},e),n.then(a,i)})}finally{s&&clearTimeout(s)}}async function H(n,e,t,o=wt){try{await x(e,o,n)}catch(s){t(s instanceof Error?s.message:String(s))}}function F(n,e){if(n===0||n==="0")return 0;const t=typeof n=="number"?n:Number(n);return t===re?re:Number.isFinite(t)&&t>0?Math.floor(t):e}function q(n,e){const t=F(n,e);return t>0?t:e}const Se=3;function ve(n){return n?Math.ceil(n.length/Se):0}function $t(n,e){let t=n.length;for(const o of e){const s=(o.kind==="mcp",o.toolName);if(t+=s.length,o.kind==="mcp")o.description&&(t+=o.description.length),t+=JSON.stringify(o.inputSchema).length;else{const a=o;a.inputSchema&&(t+=JSON.stringify(a.inputSchema).length)}}return Math.ceil(t/Se)}function Ee(n){if(n.length===0)return 0;const e=JSON.stringify(Ue(n));return ve(e)}async function Mt(n){await new Promise(e=>setTimeout(e,n))}function Rt(n){return typeof n=="boolean"}function kt(n,e,t){if(Rt(t?.supportsImageInput))return t.supportsImageInput;const o=v(e)?e.models:void 0,s=v(o)?o[n]:void 0;if(!v(s))return!1;const a=s.modalities;return!v(a)||!Array.isArray(a.input)?!1:a.input.some(i=>String(i||"").trim().toLowerCase()==="image")}function ue(n,e,t,o){if(n!==void 0)return n;if(!e)return;const s=e.models;if(v(s)){const a=s[t];if(v(a)){const i=a[o];if(i!==void 0)return i}}return e[o]}function St(n,e){const t=e.provider?.default,o=t?.options,s=n.model||t?.model||e.model||"acode-default",a=I(n.effort)||I(o?.effort)||I(t?.effort)||void 0;return{model:s,baseURL:I(o?.baseURL||o?.baseUrl),apiKey:I(o?.apiKey),effort:a,systemPrompt:n.systemPrompt||e.systemPrompt,stream:o?.stream!==!1,requestTimeoutMs:q(o?.requestTimeoutMs??o?.timeoutMs,Z),requestTotalTimeoutMs:q(o?.requestTotalTimeoutMs,Ae),requestRetryCount:F(o?.requestRetryCount,_e),requestFirstByteTimeoutMs:Math.min(q(o?.requestFirstByteTimeoutMs,Ce),q(o?.requestTimeoutMs??o?.timeoutMs,Z)),requestStreamIdleTimeoutMs:Math.min(q(o?.requestStreamIdleTimeoutMs,Te),q(o?.requestTimeoutMs??o?.timeoutMs,Z)),mcpToolTimeoutMs:q(o?.mcpToolTimeoutMs,ee),mcpPollingToolTimeoutMs:F(o?.mcpPollingToolTimeoutMs,we),supportsImageInput:kt(s,t,o),contextLimit:F(ue(o?.contextLimit,t,s,"contextLimit"),0)||void 0,inputLimit:F(ue(o?.inputLimit,t,s,"inputLimit"),0)||void 0,maxOutput:F(ue(o?.maxOutput,t,s,"maxOutput"),0)||void 0}}function U(n,e){const t=e.replace(/\s+/g," ").trim();t&&n.push({type:"text",text:t})}function vt(n,e){const t=e.trim();return/^data:image\/[a-z0-9.+-]+;base64,/i.test(t)?t:`data:${n||"image/png"};base64,${t}`}function Et(n){return/^data:image\/[a-z0-9.+-]+;base64,/i.test(n.trim())}function xt(n){let e;try{e=new URL(n)}catch{throw new Error(`ACode image URL is invalid: ${n}`)}if(e.protocol!=="http:"&&e.protocol!=="https:")throw new Error(`ACode image URL protocol is not supported: ${e.protocol}`)}async function Nt(n){const e=await n.arrayBuffer();if(e.byteLength>Me)throw new Error(`ACode image is too large to inline: ${e.byteLength} bytes exceeds ${Me} bytes`);return Buffer.from(e).toString("base64")}async function It(n){const e=n.trim();if(Et(e))return e;xt(e);const t=await fetch(e);if(!t.ok)throw new Error(`ACode image fetch failed: ${t.status} ${await t.text()}`);const o=t.headers.get("content-type")||"",s=o.split(";")[0]?.trim().toLowerCase()||"";if(!s.startsWith("image/"))throw new Error(`ACode image URL did not return an image content type: ${o||"unknown"}`);return`data:${s};base64,${await Nt(t)}`}function Dt(n){const e=I(n.base64Data??n.base64??n.data);return e?vt(I(n.mediaType??n.mimeType)||"image/png",e):I(n.url??n.serverUrl)}function xe(n,e,t,o){return`[Attached file: ${[n?`name=${n}`:void 0,e?`url=${e}`:void 0,t?`mediaType=${t}`:void 0,o?`size=${o}`:void 0].filter(a=>!!a).join(", ")}]`}function Pt(n){const e=/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,t=[];let o=!1,s=0,a=e.exec(n);for(;a!==null;){U(t,n.slice(s,a.index));const i=a[1],u=(a[2]||"").trim();if(i==="\u56FE\u7247"&&u)t.push({type:"image_url",image_url:{url:u}}),o=!0;else if(i==="\u6587\u4EF6"&&u){const[r="",c="",l="",g=""]=u.split("|").map(y=>y.trim());U(t,xe(r,c,l,g))}else U(t,a[0]);s=a.index+a[0].length,a=e.exec(n)}return t.length===0?{content:n,hasImages:!1}:(U(t,n.slice(s)),{content:t,hasImages:o})}function Lt(n,e){let t=!1;const o=[e.directMessages,e.groupMessages];for(const s of o)if(Array.isArray(s))for(const a of s){if(!v(a))continue;const i=I(a.content);if(!i)continue;const u=I(a.senderName);U(n,u?`Message from ${u}:`:"Message:");const r=ce(i);Array.isArray(r.content)?n.push(...r.content):U(n,r.content),t=t||r.hasImages}return t}function Ot(n){let e;try{e=JSON.parse(n)}catch{return}if(!v(e))return;const t=[];let o=Lt(t,e);const s=I(e.text)||"",a=Array.isArray(e.attachments)?e.attachments:[];U(t,s);for(const i of a){if(!v(i))continue;const u=i;if(String(u.type??u.kind??"").toLowerCase()==="image"){const l=Dt(u);l&&(t.push({type:"image_url",image_url:{url:l}}),o=!0);continue}const c=I(u.url??u.serverUrl)||"";U(t,xe(I(u.name)||"",c,I(u.mediaType??u.mimeType)||"",I(u.size)||""))}return t.length===0?{content:n,hasImages:!1}:{content:t,hasImages:o}}function ce(n){return Ot(n)??Pt(n)}async function Ne(n){if(!Array.isArray(n))return n;const e=[];for(const t of n){if(t.type==="text"){e.push(t);continue}e.push({type:"image_url",image_url:{url:await It(t.image_url.url)}})}return e}function Ut(n){return typeof n=="string"?n:Array.isArray(n)?n.map(e=>e.type==="text"?e.text:"[Image]").join(" ").trim():""}function Bt(n,e){const t=n.permissions??e.permissions??{},o=n.permissions?[]:e.allowedTools??[],s=n.permissions?[]:e.deniedTools??[];return{mode:t.mode??"default",allow:[...t.allow??[],...o].map(a=>a.trim()).filter(Boolean),deny:[...t.deny??[],...s].map(a=>a.trim()).filter(Boolean)}}function qt(n,e){return n==="*"?!0:n.endsWith("*")?e.startsWith(n.slice(0,-1)):n===e}function zt(n){return n.kind==="builtin"?[n.exposedName,n.toolName,`builtin.${n.toolName}`]:[n.exposedName,n.toolName,`${n.serverName}.${n.toolName}`,`mcp.${n.serverName}.${n.toolName}`]}function Ie(n,e){return zt(e).some(t=>qt(n,t))}function De(n,e,t){if(e.length>0&&!e.some(o=>Ie(o,n)))throw new Error(t)}function le(n,e,t){if(e.mode!=="bypassPermissions"){if(e.deny.some(o=>Ie(o,n)))throw new Error(`ACode tool denied by permission rule: ${n.exposedName}`);De(n,e.allow,`ACode tool is not in allowed permission rules: ${n.exposedName}`),De(n,t??[],`ACode slash command does not allow tool: ${n.exposedName}`)}}function Ft(n,e,t){try{return le(n,e,t),!0}catch{return!1}}function oe(n){const e=n.replace(/\/+$/g,"");return/\/chat\/completions$/i.test(e)?e:`${e}/chat/completions`}function jt(n){try{const e=new URL(n);e.search="",e.hash="";const t=new URL(oe(e.toString()));return`${t.origin}${t.pathname}`}catch{return oe(n).replace(/([?&](?:api[_-]?key|token|authorization)=)[^&]+/gi,"$1[redacted]")}}function Wt(n){const e=[...n].reverse().find(o=>o.role==="user"),t=Ut(e?.content??null).trim();if(t)return t.length>300?`${t.slice(0,300)}...`:t}function Pe(n){try{const e=JSON.parse(n);return ye(e)?e:{}}catch{return{}}}function Jt(n,e,t){if(new Set([Ge,"await_complete"]).has(n.toolName))return 0;if(n.toolName!=="Bash")return t;const s=e.timeout_ms??e.timeoutMs,a=typeof s=="number"?s:typeof s=="string"?Number(s):NaN;return!Number.isFinite(a)||a<=0?Math.max(t,_t):Math.min(Math.floor(a),10*6e4)+2e3}function Kt(n,e){const t=n.trim();return`ACode \u5DF2\u63A5\u6536\u4EFB\u52A1\u3002\u5F53\u524D\u5DF2\u52A0\u8F7D ${e.configMcpCount} \u4E2A MCP \u914D\u7F6E\u3001${e.exposedTools.length} \u4E2A MCP Tool \u4E0E ${e.skills.length} \u4E2A Skill\u3002${t?`\u8F93\u5165\u6458\u8981\uFF1A${t.slice(0,200)}`:""}`}function P(n){if(!v(n))return String(n??"");const e=n.content;if(Array.isArray(e)){const t=e.map(o=>v(o)?typeof o.text=="string"?o.text:JSON.stringify(o):"").filter(Boolean);if(t.length>0)return t.join(`
|
|
2
|
+
`)}return JSON.stringify(n)}function G(n){return n instanceof Error?n.message:String(n)}function Qt(n){let e=16;if(typeof n.content=="string")e+=n.content.length*2;else if(Array.isArray(n.content))for(const t of n.content)typeof t=="object"&&t!==null&&(e+=JSON.stringify(t).length);return n.tool_calls&&(e+=JSON.stringify(n.tool_calls).length),n.tool_call_id&&(e+=n.tool_call_id.length),e}async function Ht(n,e,t,o,s){let a=0;for(const u of n)a+=Qt(u);if(a<=e)return 0;const i=await he(n,t,o,{llmSummarizer:s});return i.strategy!=="none"?i.prunedToolMessages+i.summarizedMessages:fe(n,{llmSummarizer:s,contextLimit:t})}function Le(n){const e=G(n).toLowerCase();return e.includes("context_length_exceeded")||e.includes("context length")||e.includes("maximum context")||e.includes("max context")||e.includes("token limit")||e.includes("tokens exceed")||e.includes("too many tokens")||e.includes("input is too long")||e.includes("prompt is too long")||e.includes("request too large")||e.includes("413")}function Gt(n){const e=G(n).toLowerCase();return Le(n)?!1:e.includes("fetch failed")||e.includes("timed out")||e.includes("timeout")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("etimedout")||e.includes("enotfound")||e.includes("socket hang up")||e.includes("network error")||/\b(408|429|500|502|503|504|520|521|522|523|524)\b/.test(e)}function Yt(n){if(typeof n!="object"||n===null)return!1;const e=Reflect.get(n,"code"),t=G(n).toLowerCase();return e===-32001||t.includes("request timed out")}function Vt(n){if(typeof n=="object"&&n!==null){const e=Reflect.get(n,"code");if(typeof e=="string"&&e)return e;const t=Reflect.get(n,"name");if(typeof t=="string"&&t)return t}return"tool_error"}function Xt(n,e){return JSON.stringify({ok:!1,tool:n.exposedName,error:{type:Vt(e),message:G(e)}})}function Oe(n){const e=JSON.stringify(n);return e.length>500?`${e.slice(0,500)}\u2026`:e}function Zt(n){const e=[n?.reasoning_content,n?.reasoning_text,n?.reasoning];for(const t of e){if(typeof t=="string"&&t)return t;if(v(t)){const o=t.text??t.content;if(typeof o=="string"&&o)return o}}return""}function eo(n){return n.length===0?"":["Skills are available for this session.","Use the `skill` tool to load specialized skill instructions when a user task matches one of the available skills listed in the tool description.","Do not attempt to follow skill instructions from memory \u2014 always invoke the `skill` tool first to load the full content."].join(" ")}function to(n){return n.length===0?"":["Available slash commands:",...n.map(e=>`- /${e.name}${e.description?`: ${e.description}`:""}`),"When the user invokes a slash command, ACode expands it before model execution."].join(`
|
|
3
|
+
`)}function oo(n){if(!n||typeof n!="object")return"";const e=n,t=[],o=e.displayName,s=e.roleName,a=e.instanceName,i=e.projectName,u=e.workspacePath,r=e.runtimeMode,c=e.describe;return typeof o=="string"&&o.trim()&&t.push(`Display Name: ${o.trim()}`),typeof s=="string"&&s.trim()&&t.push(`Role: ${s.trim()}`),typeof a=="string"&&a.trim()&&t.push(`Instance: ${a.trim()}`),typeof i=="string"&&i.trim()&&t.push(`Project: ${i.trim()}`),typeof u=="string"&&u.trim()&&t.push(`Workspace: ${u.trim()}`),typeof r=="string"&&r.trim()&&t.push(`Runtime Mode: ${r.trim()}`),typeof c=="string"&&c.trim()&&t.push(`Description: ${c.trim()}`),t.length===0?"":["[User Profile]",...t].join(`
|
|
4
|
+
`)}function Ue(n){return n.map(e=>({type:"function",function:{name:e.exposedName,description:e.description||e.toolName,parameters:e.inputSchema}}))}function no(n,e){return`${n}__${e}`.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,64)||"mcp_tool"}function so(n){const e={"Content-Type":"application/json"};return n.apiKey&&(e.Authorization=`Bearer ${n.apiKey}`),e}function io(n){return Object.fromEntries(Object.entries(n).map(([e,t])=>[e,ro(e)?ao(t):t]))}function ro(n){const e=n.trim().toLowerCase();return e==="authorization"||e==="api-key"||e==="x-api-key"||e==="openai-api-key"}function ao(n){return n.trim().toLowerCase().startsWith("bearer ")?"Bearer ***":"***"}function uo(n){return n.split(/\r?\n/).filter(e=>e.startsWith("data:")).map(e=>e.slice(5).trim()).filter(Boolean)}function co(n,e){const t=Number.isFinite(e.index)?Number(e.index):0,o=n.get(t)??{id:e.id||`call-${t}`,type:"function",function:{name:"",arguments:""}};e.id&&(o.id=e.id),e.function?.name&&(o.function.name+=e.function.name),e.function?.arguments&&(o.function.arguments+=e.function.arguments),n.set(t,o)}function lo(n){return[...n.entries()].sort(([e],[t])=>e-t).map(([,e])=>e).filter(e=>e.function.name.trim().length>0)}class j extends Fe{constructor(e){super(),this.config=e,this.initialConversation=[],this.state={started:!1,terminated:!1,configMcpCount:0,skills:[],provider:{model:"acode-default",stream:!1,requestTimeoutMs:Z,requestTotalTimeoutMs:Ae,requestRetryCount:_e,requestFirstByteTimeoutMs:Ce,requestStreamIdleTimeoutMs:Te,mcpToolTimeoutMs:ee,mcpPollingToolTimeoutMs:we,supportsImageInput:!1},permissions:{mode:"default",allow:[],deny:[]},mcpConnections:[],ownsMcpConnections:!0,exposedTools:[],commands:[],commandRegistry:new pe([]),conversation:[],accumulatedInputTokens:0,accumulatedOutputTokens:0},this.abortController=null,this.pendingMemorySubAgents=new Map,this.memoryDelegateCooldownUntil=new Map,this.submitQueue=Promise.resolve(),this.activeTurn=!1,this.abortRequested=!1,this.pendingAwaitedSubIds=new Set,this.pendingAwaitedBgTaskIds=new Set,this.sessionCompleteEmitted=!1,this.contextVersion=0,this.stopWaiters=new Set,this.compactionDebugTimer=null,this.skillTool=null,this.skillWatchers=[],this.skillRefreshTimer=null,this.questionWaiters=new Map,this.hookBus=new lt({sessionId:e.sessionId,onError:(t,o)=>{this.emitAcodeEvent("error",{message:`ACode hook failed: ${t.name}: ${o instanceof Error?o.message:String(o)}`})}});for(const t of e.hooks??[])this.hookBus.register(t)}getAvailableTools(){return this.state.exposedTools.map(e=>e.exposedName)}emitAcodeEvent(e,t){const o={type:e,sessionId:this.config.sessionId,timestamp:ft(),data:t};this.emit("event",o)}emitCompactionPhase(e,t,o,s){this.emitAcodeEvent("context_compaction",{action:"phase",compactionId:e,parentId:e,phase:t,phaseLabel:o,phaseDetail:s})}handleCompactionPhase(e,t){switch(t.phase){case"prune_start":this.emitCompactionPhase(e,"prune","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA",`\u6B63\u5728\u88C1\u526A ${t.messageCount??0} \u6761\u6D88\u606F\u4E2D\u7684\u5DE5\u5177\u8F93\u51FA...`);break;case"prune_end":this.emitCompactionPhase(e,"prune_done","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA",`\u88C1\u526A\u4E86 ${t.prunedCount??0} \u6761\u5DE5\u5177\u8F93\u51FA, \u91CA\u653E ${t.freedTokens??0} tokens`);break;case"summarize_start":this.emitCompactionPhase(e,"summarize","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD",`\u6B63\u5728\u6458\u8981 ${t.messageCount??0} \u6761\u65E9\u671F\u5BF9\u8BDD...`);break;case"summarize_end":this.emitCompactionPhase(e,"summarize_done","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD",`\u6458\u8981\u5316\u4E86 ${t.summarizedCount??0} \u6761\u6D88\u606F${t.usedLLM?" (LLM \u6458\u8981)":" (\u89C4\u5219\u6458\u8981)"}`);break}}async start(){this.emitAcodeEvent("startup_phase",{phase:"loading_config"});const e=await ut(this.config.configPath);this.emitAcodeEvent("startup_phase",{phase:"loading_skills"});const{skills:t,skillGroups:o,watchedDirs:s}=await this.loadAllSkills(),a=St(this.config,e);m(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 resolveProviderConfig \u7ED3\u679C: config.model=${this.config.model??"(undefined)"}, resolvedModel=${a.model}, baseURL=${a.baseURL??"(none)"}, apiKey=${a.apiKey?"[set]":"(none)"}, configPath=${this.config.configPath??"(none)"}`);const i=Bt(this.config,e),u=this.config.sharedMcpConnections?this.filterSharedMcpConnectionsForSubAgent(this.config.sharedMcpConnections):await this.connectMcpServers(e.mcpServers??{},a.mcpToolTimeoutMs),r=!this.config.sharedMcpConnections;this.emitAcodeEvent("startup_phase",{phase:"fetching_profile"});const c=await this.fetchProfilePrompt(u),l=this.config.agentId||"unknown";ot(l),K.reconcileOrphans(l);const g=He(this.config.workingDirectory,l,this.config.onFileChange,{manager:K,emitCompleted:p=>{this.emitAcodeEvent("background_command_completed",p)}}),y=Ye(this.buildAskUserQuestionDeps(),()=>this.contextVersion),b=Ve(t);this.skillTool=b;const d=Xe(l),$=Ze(l),h=this.config.subAgentManager?et(this.buildSubAgentToolDeps(this.config.subAgentManager)):[],f=tt(this.buildAwaitCompleteDeps()),C=this.config.terminalManager?nt(l,{terminalManager:this.config.terminalManager}):null,_=[...g,y,b,d,$,...h,f,...C?[C]:[],...u.flatMap(p=>p.tools),...this.config.extraBuiltInTools??[]],k=this.config.subagentType==="explore"?_.filter(p=>!Tt.has(p.exposedName)):_,A=this.resolveCommandDirs(e);this.emitAcodeEvent("startup_phase",{phase:"loading_commands"});const M=await st(A),N=new pe(M),T=eo(t),S=to(M),R=[a.systemPrompt,T,S].map(p=>p?.trim()).filter(p=>!!p).join(`
|
|
5
5
|
|
|
6
|
-
`),
|
|
6
|
+
`),w=p=>p?.trim()?[{role:"system",content:p.trim()}]:[],E=[this.config.rolePrompt,c].map(p=>p?.trim()).filter(p=>!!p).join(`
|
|
7
7
|
|
|
8
|
-
`),
|
|
8
|
+
`),L=[...w(this.config.globalPrompt),...w(E),...w(this.config.memory),...R?[{role:"system",content:R}]:[]],O=L.map(p=>p.content).filter(Boolean).join(`
|
|
9
9
|
|
|
10
|
-
`);this.initialConversation=
|
|
11
|
-
`,"utf-8").catch(()=>{})}catch{}},5e3)}stopCompactionDebugLog(){this.compactionDebugTimer&&(clearInterval(this.compactionDebugTimer),this.compactionDebugTimer=null)}async submit(e){const t=this.contextVersion;c(`[ACodeRuntime] \u{1F4EC} submit() queued: contextVersion=${t}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, terminated=${this.state.terminated}, message.length=${e.length}`);const n=this.submitQueue.then(()=>(c(`[ACodeRuntime] \u25B6\uFE0F executeSubmit dequeued: contextVersion=${t}`),this.executeSubmit(e,t)));return this.submitQueue=n.catch(()=>{c("[ACodeRuntime] \u{1F4EC} submit() queued item rejected (catch swallowed)")}),c("[ACodeRuntime] \u{1F4EC} submit() returning queued promise"),n}async resetContext(){if(!this.state.started||this.state.terminated)throw new Error("ACode runtime is not active");this.contextVersion+=1,this.abortRequested=this.activeTurn,this.abortController?.abort(),this.abortController=null,this.state.conversation=Z(this.initialConversation),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}isTurnSuperseded(e){return e!==this.contextVersion}async executeSubmit(e,t){const n=Date.now();if(c("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),c("[ACodeRuntime] \u25B6\uFE0F executeSubmit STARTED"),c(`[ACodeRuntime] Message: <redacted, length=${e.length}>`),c(`[ACodeRuntime] \u{1F522} Context version: ${t}`),c("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),!this.state.started||this.state.terminated)throw console.error(`[ACodeRuntime] \u274C Runtime not active (started: ${this.state.started}, terminated: ${this.state.terminated})`),new Error("ACode runtime is not active");this.activeTurn=!0,this.abortRequested=!1;const i=e.trim();let a=!1;try{c("[ACodeRuntime] \u{1F50D} Dispatching UserPromptSubmit hook...");const s=Date.now(),r=await this.hookBus.dispatch("UserPromptSubmit",{prompt:i}),u=Date.now()-s;if(c(`[ACodeRuntime] \u2705 UserPromptSubmit hook completed in ${u}ms, results: ${r.length}`),this.isTurnSuperseded(t)){c("[ACodeRuntime] \u26A0\uFE0F Turn superseded after hook, aborting");return}const m=X(r);if(m){console.error(`[ACodeRuntime] \u274C Prompt denied by hook: ${m.message}`),this.emitAcodeEvent("error",{message:m.message||"ACode prompt was denied by hook"}),this.emitAcodeEvent("turn_complete",{failed:!0}),a=!0,c("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (failed=true) due to hook deny");return}c("[ACodeRuntime] \u{1F50D} Expanding command if any...");const l=this.state.commandRegistry.expand(i),f=l?.prompt.trim()||i,y=l?.command.allowedTools;if(l&&(c(`[ACodeRuntime] \u{1F4CB} Slash command detected: ${l.command.name}`),this.emitAcodeEvent("command_status",{action:"slash_command",command:l.command.name,arguments:l.argumentsText,sourcePath:l.command.sourcePath})),!this.state.provider.baseURL||!this.state.provider.apiKey){c("[ACodeRuntime] \u26A0\uFE0F No provider configured, using fallback response");const M=Ut(f,this.state);this.emitAcodeEvent("assistant_delta",{text:M}),this.emitAcodeEvent("turn_complete",{usage:{inputTokens:f.length,outputTokens:M.length}}),a=!0,c("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (fallback mode)");return}c("[ACodeRuntime] \u{1F4CE} Parsing attachment message...");const w=ie(f);if(w.hasImages&&!this.state.provider.supportsImageInput)throw console.error("[ACodeRuntime] \u274C Image input not supported by current provider"),new Error("ACode provider/model is not configured for image input. Enable provider.default.models[model].modalities.input including 'image' or options.supportsImageInput=true.");c("[ACodeRuntime] \u{1F5BC}\uFE0F Materializing image content if any...");const g=await ke(w.content);if(this.isTurnSuperseded(t)){c("[ACodeRuntime] \uFE0F Turn superseded after materializing content, aborting");return}c("[ACodeRuntime] \u{1F4AC} Adding user message to conversation"),this.state.conversation.push({role:"user",content:g}),c(`[ACodeRuntime] Conversation size: ${this.state.conversation.length} messages`),c("[ACodeRuntime] Starting runModelTurn...");const b=Date.now(),h=await this.runModelTurn(y,t),d=Date.now()-b;if(c(`[ACodeRuntime] \u2705 runModelTurn completed in ${d}ms`),c(`[ACodeRuntime] \u{1F4DD} Result: text=${h.text?h.text.slice(0,80)+(h.text.length>80?"...":""):"(empty)"}, finishReason=${h.finishReason||"(none)"}`),this.isTurnSuperseded(t)){c("[ACodeRuntime] \uFE0F Turn superseded after runModelTurn, aborting");return}h.text&&!this.state.provider.stream&&(c("[ACodeRuntime] \u{1F4E4} Emitting assistant_delta (non-streaming mode)"),this.emitAcodeEvent("assistant_delta",{text:h.text})),c("[ACodeRuntime] \u{1F4E4} Emitting turn_complete..."),this.emitAcodeEvent("turn_complete",{usage:h.usage??{inputTokens:f.length,outputTokens:h.totalOutputTextLength??h.text.length},...h.responseBody?{responseBody:h.responseBody}:{},...h.finishReason?{finishReason:h.finishReason}:{}}),c(`[ACodeRuntime] \u{1F4B0} Current context usage: input=${this.state.accumulatedInputTokens}, output=${this.state.accumulatedOutputTokens}`+(h.usage?"":" (estimated, no provider usage)")),a=!0;const _=Date.now()-n;c("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),c(`[ACodeRuntime] \u2705 executeSubmit COMPLETED in ${_}ms`),c("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}catch(s){const r=Date.now()-n;if(console.error(`[ACodeRuntime] \u274C executeSubmit FAILED after ${r}ms:`,s instanceof Error?s.message:String(s)),console.error("[ACodeRuntime] \u{1F50D} Error stack:",s instanceof Error?s.stack:"(no stack)"),this.isTurnSuperseded(t)){c("[ACodeRuntime] \uFE0F Turn superseded in error handler, skipping recovery");return}if(this.abortRequested){c("[ACodeRuntime] \u26A0\uFE0F Abort requested, emitting aborted turn_complete"),this.emitAcodeEvent("turn_complete",{aborted:!0}),a=!0;return}c("[ACodeRuntime] Emitting error and failed turn_complete..."),this.emitAcodeEvent("error",{message:s instanceof Error?s.message:String(s)}),this.emitAcodeEvent("turn_complete",{failed:!0}),a=!0}finally{const s=Date.now()-n;c(`[ACodeRuntime] \u{1F51A} executeSubmit finally block entered after ${s}ms`),c(`[ACodeRuntime] \u{1F50D} turnCompleted=${a}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, contextVersion=${t}, currentContextVersion=${this.contextVersion}`),this.activeTurn=!1,this.abortRequested=!1,!a&&!this.isTurnSuperseded(t)&&(console.error(`[ACodeRuntime] \u{1F6A8} CRITICAL: executeSubmit finally block reached without turn_complete event! Duration: ${s}ms. This indicates a code path that should have emitted turn_complete but didn't. Forcing failed turn_complete to prevent state stuck.`),this.emitAcodeEvent("error",{message:"ACode turn completed without proper completion event (internal error)"}),this.emitAcodeEvent("turn_complete",{failed:!0}),c("[ACodeRuntime] Emergency turn_complete (failed=true) emitted"))}}async abort(){const e=this.abortController!==null,t=this.activeTurn;this.abortRequested=this.activeTurn,this.abortController?(c(`[ACodeRuntime] \u26D4 abort() calling abortController.abort() (activeTurn=${t})`),this.abortController.abort()):console.warn(`[ACodeRuntime] \u26D4 abort() called but abortController is null! activeTurn=${t}, abortRequested will be set to ${t}. This means abort() CANNOT cancel any running fetch/stream \u2014 if a built-in tool is executing, it will NOT be interrupted.`),this.abortController=null,this.rejectAllQuestionWaiters("aborted"),this.cancelPendingAwaitedSubAgents(),this.notifyRuntimeStop()}buildAskUserQuestionDeps(){return{onQuestion:(e,t)=>{this.emitAcodeEvent("question_request",{toolCallId:e,questions:t})},waitForAnswer:(e,t)=>new Promise((n,i)=>{this.questionWaiters.set(e,{resolve:n,reject:i,contextVersion:t})})}}buildSubAgentToolDeps(e){const t=this.config.agentId??"unknown",n=this.config.sessionId,i=this.config.workingDirectory,a=this.config;return{spawnSubAgent:async s=>{const r=await e.spawn({parentAgentId:t,parentSessionId:n,subagentType:s.subagentType,description:s.description,prompt:s.prompt,workingDirectory:i,parentConfig:{...a,sharedMcpConnections:this.state?.mcpConnections}});return await e.start(r),{subId:r}},listSubAgents:async()=>{const s=e.listByParent(t),r=[],u=[];for(const m of s){const l={subId:m.subId,subagentType:m.subagentType,description:m.description,status:m.status,startedAt:m.startedAt,endedAt:m.endedAt,durationMs:m.durationMs};m.status==="pending"||m.status==="running"?r.push(l):u.push(l)}return u.sort((m,l)=>(l.endedAt??0)-(m.endedAt??0)),{running:r,history:u}},getSubAgentStatus:async s=>{const r=e.getSubAgent(s);return r?{subId:r.subId,subagentType:r.subagentType,description:r.description,status:r.status,startedAt:r.startedAt,endedAt:r.endedAt,durationMs:r.durationMs,prompt:r.prompt,result:r.result,errorMessage:r.errorMessage,contextSnapshot:r.contextSnapshot}:null},awaitSubAgents:async(s,r)=>{const u=new Set;for(const m of s)this.pendingAwaitedSubIds.add(m),u.add(m);try{return await e.awaitCompletion(s,r)}finally{for(const m of u)this.pendingAwaitedSubIds.delete(m)}},abortSubAgent:s=>e.abort(s)}}submitQuestionAnswer(e,t){const n=this.questionWaiters.get(e);return n?(this.questionWaiters.delete(e),this.isTurnSuperseded(n.contextVersion)?(n.reject(new Error("turn superseded before user answered")),!1):(n.resolve(t),!0)):!1}rejectAllQuestionWaiters(e){if(this.questionWaiters.size!==0){for(const[,t]of this.questionWaiters)t.reject(new Error(`ask_user_question ${e}`));this.questionWaiters.clear()}}cancelPendingAwaitedSubAgents(){if(this.pendingAwaitedSubIds.size===0)return;const e=this.config.subAgentManager;if(!e)return;const t=Array.from(this.pendingAwaitedSubIds);c(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited sub-agent(s): ${t.join(", ")}`);for(const n of t)e.abort(n).catch(i=>{c(`[ACodeRuntime] \u26A0\uFE0F manager.abort(${n}) threw: ${i instanceof Error?i.message:String(i)}`)})}async stop(){if(!this.state.terminated&&(this.state.terminated=!0,this.notifyRuntimeStop(),this.abortRequested=this.activeTurn,this.abortController?.abort(),this.abortController=null,this.rejectAllQuestionWaiters("session terminated"),this.cancelPendingAwaitedSubAgents(),await oe("ACode active turn shutdown",this.submitQueue,e=>{this.emitAcodeEvent("error",{message:e})}),await this.disconnectMcpServers(),await oe("ACode Stop hooks",this.hookBus.dispatch("Stop",{reason:"session_stop"}),e=>{this.emitAcodeEvent("error",{message:e})}),this.state.terminated=!0,this.sessionCompleteEmitted||(this.sessionCompleteEmitted=!0,this.emitAcodeEvent("session_complete",{exitCode:0})),this.stopCompactionDebugLog(),this.stopSkillWatchers(),Q))try{F.promises.appendFile(_e,`[${new Date().toISOString()}] runtime stopped | ---
|
|
12
|
-
`,"utf-8").catch(()=>{})}catch{}}resolveCommandDirs(e){const t=[...this.config.commandDirs??[],...e.commandDirs??[],...e.commands?.directories??[]];return[...new Set(t.map(
|
|
10
|
+
`);this.initialConversation=ie(L),this.state={started:!0,terminated:!1,configMcpCount:Object.keys(e.mcpServers??{}).length,skills:t,provider:a,permissions:i,mcpConnections:u,ownsMcpConnections:r,exposedTools:k,commands:M,commandRegistry:N,conversation:ie(L),accumulatedInputTokens:0,accumulatedOutputTokens:0},this.emitAcodeEvent("startup_phase",{phase:"session_start_hook"}),await this.hookBus.dispatch("SessionStart",{workingDirectory:this.config.workingDirectory,model:a.model,commandCount:M.length});const D=ae(a);this.emitAcodeEvent("session_started",{workingDirectory:this.config.workingDirectory,model:a.model,commandCount:M.length,estimatedContextTokens:$t(O,k),contextLimit:D.contextLimit,maxOutput:D.maxOutput,...D.inputLimit!==void 0?{inputLimit:D.inputLimit}:{},compactionThreshold:D.threshold}),this.emitAcodeEvent("mcp_status",{configPath:this.config.configPath,installedCount:this.state.configMcpCount,servers:Object.keys(e.mcpServers??{}),connectedCount:u.length,builtInToolCount:g.length,toolCount:k.length,permissionMode:i.mode,allowedToolRules:i.allow,deniedToolRules:i.deny,tools:k.map(p=>({name:p.exposedName,source:p.kind==="mcp"?`${p.serverName}.${p.toolName}`:`builtin.${p.toolName}`,description:p.description||""}))}),this.emitAcodeEvent("skill_status",{skillsDir:this.config.skillsDir,installedCount:t.length,skills:t.map(p=>({name:p.name,description:p.description,directory:p.directory})),skillGroups:o.map(p=>({dir:p.dir,exists:p.exists,skills:p.skills.map(z=>({name:z.name,description:z.description,directory:z.directory}))}))}),this.emitAcodeEvent("command_status",{action:"commands_loaded",installedCommandCount:M.length,commandDirs:A,commands:M.map(p=>({name:p.name,description:p.description}))}),this.config.initialPrompt&&await this.submit(this.config.initialPrompt),this.startCompactionDebugLog(),this.startSkillWatchers(s)}async loadAllSkills(){const e=this.config.skillsDir??"",t=V.join(this.config.workingDirectory,".acode","skills"),o=V.join(this.config.workingDirectory,".agentswork","skills"),s=new Set,a=[],i=[];for(const c of[e,t,o]){if(!c)continue;const l=V.resolve(c);if(!s.has(l)){s.add(l),a.push(await ct(c));try{await J.promises.access(l),i.push(l)}catch{}}}const u=new Map;for(const c of a)for(const l of c.skills)u.set(l.name,l);return{skills:[...u.values()],skillGroups:a,watchedDirs:i}}startSkillWatchers(e){for(const t of e){let o=null;try{o=J.watch(t,{recursive:!0},()=>{this.scheduleSkillRefresh()})}catch{try{o=J.watch(t,()=>{this.scheduleSkillRefresh()})}catch{continue}}o&&(o.on("error",()=>{}),this.skillWatchers.push(o))}}scheduleSkillRefresh(){this.skillRefreshTimer&&clearTimeout(this.skillRefreshTimer),this.skillRefreshTimer=setTimeout(()=>{this.skillRefreshTimer=null,this.refreshSkills()},j.SKILL_REFRESH_DEBOUNCE_MS)}async refreshSkills(){if(!(!this.state.started||this.state.terminated))try{const{skills:e,skillGroups:t}=await this.loadAllSkills();this.skillTool&&this.skillTool.refresh(e),this.state.skills=e,this.emitAcodeEvent("skill_status",{skillsDir:this.config.skillsDir,installedCount:e.length,skills:e.map(o=>({name:o.name,description:o.description,directory:o.directory})),skillGroups:t.map(o=>({dir:o.dir,exists:o.exists,skills:o.skills.map(s=>({name:s.name,description:s.description,directory:s.directory}))}))}),m(`[skill-watch] Skills refreshed: ${e.length} skills (${e.map(o=>o.name).join(", ")||"none"})`,{sessionId:this.config.sessionId})}catch(e){console.error("[skill-watch] Failed to refresh skills:",e instanceof Error?e.message:e)}}stopSkillWatchers(){this.skillRefreshTimer&&(clearTimeout(this.skillRefreshTimer),this.skillRefreshTimer=null);for(const e of this.skillWatchers)try{e.close()}catch{}this.skillWatchers=[]}startCompactionDebugLog(){if(!te||this.compactionDebugTimer)return;const e=this.state.provider,{contextLimit:t,maxOutput:o,inputLimit:s,threshold:a}=ae(e);this.compactionDebugTimer=setInterval(()=>{try{const i=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,u=X(this.state.conversation)+Ee(this.state.exposedTools),r=Math.max(i,u),c=Q(this.state.conversation),l=this.state.started&&!this.state.terminated,g=[`[${new Date().toISOString()}]`,`started=${this.state.started}`,`terminated=${this.state.terminated}`,`activeTurn=${this.activeTurn}`,`conversationSize=${this.state.conversation.length}msgs`,`sizeKB=${c}KB`,`estimation=${u} tokens`,`actualInput=${this.state.accumulatedInputTokens}`,`actualOutput=${this.state.accumulatedOutputTokens}`,`actualUsed=${i}`,`contextLimit=${t}`,`inputLimit=${s??"n/a"}`,`maxOutput=${o}`,`triggerThreshold=${a}`,`remainingToTrigger=${Math.max(0,a-i)}`,`isRunning=${l}`,`shouldCompact=${l?r>=a:!1}`,"---"].join(" | ");J.promises.appendFile(ke,g+`
|
|
11
|
+
`,"utf-8").catch(()=>{})}catch{}},5e3)}stopCompactionDebugLog(){this.compactionDebugTimer&&(clearInterval(this.compactionDebugTimer),this.compactionDebugTimer=null)}async submit(e){const t=this.contextVersion;m(`[ACodeRuntime] \u{1F4EC} submit() queued: contextVersion=${t}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, terminated=${this.state.terminated}, message.length=${e.length}`);const o=this.submitQueue.then(()=>(m(`[ACodeRuntime] \u25B6\uFE0F executeSubmit dequeued: contextVersion=${t}`),this.executeSubmit(e,t)));return this.submitQueue=o.catch(()=>{m("[ACodeRuntime] \u{1F4EC} submit() queued item rejected (catch swallowed)")}),m("[ACodeRuntime] \u{1F4EC} submit() returning queued promise"),o}async resetContext(){if(!this.state.started||this.state.terminated)throw new Error("ACode runtime is not active");this.contextVersion+=1,this.abortRequested=this.activeTurn,this.abortController?.abort(),this.abortController=null,this.state.conversation=ie(this.initialConversation),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}isTurnSuperseded(e){return e!==this.contextVersion}async executeSubmit(e,t){const o=Date.now();if(m("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),m("[ACodeRuntime] \u25B6\uFE0F executeSubmit STARTED"),m(`[ACodeRuntime] Message: <redacted, length=${e.length}>`),m(`[ACodeRuntime] \u{1F522} Context version: ${t}`),m("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),!this.state.started||this.state.terminated)throw console.error(`[ACodeRuntime] \u274C Runtime not active (started: ${this.state.started}, terminated: ${this.state.terminated})`),new Error("ACode runtime is not active");this.activeTurn=!0,this.abortRequested=!1;const s=e.trim();let a=!1;try{m("[ACodeRuntime] \u{1F50D} Dispatching UserPromptSubmit hook...");const i=Date.now(),u=await this.hookBus.dispatch("UserPromptSubmit",{prompt:s}),r=Date.now()-i;if(m(`[ACodeRuntime] \u2705 UserPromptSubmit hook completed in ${r}ms, results: ${u.length}`),this.isTurnSuperseded(t)){m("[ACodeRuntime] \u26A0\uFE0F Turn superseded after hook, aborting");return}const c=se(u);if(c){console.error(`[ACodeRuntime] \u274C Prompt denied by hook: ${c.message}`),this.emitAcodeEvent("error",{message:c.message||"ACode prompt was denied by hook"}),this.emitAcodeEvent("turn_complete",{failed:!0}),a=!0,m("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (failed=true) due to hook deny");return}m("[ACodeRuntime] \u{1F50D} Expanding command if any...");const l=this.state.commandRegistry.expand(s),g=l?.prompt.trim()||s,y=l?.command.allowedTools;if(l&&(m(`[ACodeRuntime] \u{1F4CB} Slash command detected: ${l.command.name}`),this.emitAcodeEvent("command_status",{action:"slash_command",command:l.command.name,arguments:l.argumentsText,sourcePath:l.command.sourcePath})),!this.state.provider.baseURL||!this.state.provider.apiKey){m("[ACodeRuntime] \u26A0\uFE0F No provider configured, using fallback response");const _=Kt(g,this.state);this.emitAcodeEvent("assistant_delta",{text:_}),this.emitAcodeEvent("turn_complete",{usage:{inputTokens:g.length,outputTokens:_.length}}),a=!0,m("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (fallback mode)");return}m("[ACodeRuntime] \u{1F4CE} Parsing attachment message...");const b=ce(g);if(b.hasImages&&!this.state.provider.supportsImageInput)throw console.error("[ACodeRuntime] \u274C Image input not supported by current provider"),new Error("ACode provider/model is not configured for image input. Enable provider.default.models[model].modalities.input including 'image' or options.supportsImageInput=true.");m("[ACodeRuntime] \u{1F5BC}\uFE0F Materializing image content if any...");const d=await Ne(b.content);if(this.isTurnSuperseded(t)){m("[ACodeRuntime] \uFE0F Turn superseded after materializing content, aborting");return}m("[ACodeRuntime] \u{1F4AC} Adding user message to conversation"),this.state.conversation.push({role:"user",content:d}),m(`[ACodeRuntime] Conversation size: ${this.state.conversation.length} messages`),m("[ACodeRuntime] Starting runModelTurn...");const $=Date.now(),h=await this.runModelTurn(y,t),f=Date.now()-$;if(m(`[ACodeRuntime] \u2705 runModelTurn completed in ${f}ms`),m(`[ACodeRuntime] \u{1F4DD} Result: text=${h.text?h.text.slice(0,80)+(h.text.length>80?"...":""):"(empty)"}, finishReason=${h.finishReason||"(none)"}`),this.isTurnSuperseded(t)){m("[ACodeRuntime] \uFE0F Turn superseded after runModelTurn, aborting");return}h.text&&!this.state.provider.stream&&(m("[ACodeRuntime] \u{1F4E4} Emitting assistant_delta (non-streaming mode)"),this.emitAcodeEvent("assistant_delta",{text:h.text})),m("[ACodeRuntime] \u{1F4E4} Emitting turn_complete..."),this.emitAcodeEvent("turn_complete",{usage:h.usage??{inputTokens:g.length,outputTokens:h.totalOutputTextLength??h.text.length},...h.responseBody?{responseBody:h.responseBody}:{},...h.finishReason?{finishReason:h.finishReason}:{}}),m(`[ACodeRuntime] \u{1F4B0} Current context usage: input=${this.state.accumulatedInputTokens}, output=${this.state.accumulatedOutputTokens}`+(h.usage?"":" (estimated, no provider usage)")),a=!0;const C=Date.now()-o;m("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),m(`[ACodeRuntime] \u2705 executeSubmit COMPLETED in ${C}ms`),m("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}catch(i){const u=Date.now()-o;if(console.error(`[ACodeRuntime] \u274C executeSubmit FAILED after ${u}ms:`,i instanceof Error?i.message:String(i)),console.error("[ACodeRuntime] \u{1F50D} Error stack:",i instanceof Error?i.stack:"(no stack)"),this.isTurnSuperseded(t)){m("[ACodeRuntime] \uFE0F Turn superseded in error handler, skipping recovery");return}if(this.abortRequested){m("[ACodeRuntime] \u26A0\uFE0F Abort requested, emitting aborted turn_complete"),this.emitAcodeEvent("turn_complete",{aborted:!0}),a=!0;return}m("[ACodeRuntime] Emitting error and failed turn_complete..."),this.emitAcodeEvent("error",{message:i instanceof Error?i.message:String(i)}),this.emitAcodeEvent("turn_complete",{failed:!0}),a=!0}finally{const i=Date.now()-o;m(`[ACodeRuntime] \u{1F51A} executeSubmit finally block entered after ${i}ms`),m(`[ACodeRuntime] \u{1F50D} turnCompleted=${a}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, contextVersion=${t}, currentContextVersion=${this.contextVersion}`),this.activeTurn=!1,this.abortRequested=!1,!a&&!this.isTurnSuperseded(t)&&(console.error(`[ACodeRuntime] \u{1F6A8} CRITICAL: executeSubmit finally block reached without turn_complete event! Duration: ${i}ms. This indicates a code path that should have emitted turn_complete but didn't. Forcing failed turn_complete to prevent state stuck.`),this.emitAcodeEvent("error",{message:"ACode turn completed without proper completion event (internal error)"}),this.emitAcodeEvent("turn_complete",{failed:!0}),m("[ACodeRuntime] Emergency turn_complete (failed=true) emitted"))}}async abort(){const e=this.abortController!==null,t=this.activeTurn;this.abortRequested=this.activeTurn,this.abortController?(m(`[ACodeRuntime] \u26D4 abort() calling abortController.abort() (activeTurn=${t})`),this.abortController.abort()):console.warn(`[ACodeRuntime] \u26D4 abort() called but abortController is null! activeTurn=${t}, abortRequested will be set to ${t}. This means abort() CANNOT cancel any running fetch/stream \u2014 if a built-in tool is executing, it will NOT be interrupted.`),this.abortController=null,this.rejectAllQuestionWaiters("aborted"),this.cancelPendingAwaitedSubAgents(),this.cancelPendingAwaitedBgTasks(),this.notifyRuntimeStop()}buildAskUserQuestionDeps(){return{onQuestion:(e,t)=>{this.emitAcodeEvent("question_request",{toolCallId:e,questions:t})},waitForAnswer:(e,t)=>new Promise((o,s)=>{this.questionWaiters.set(e,{resolve:o,reject:s,contextVersion:t})})}}buildSubAgentToolDeps(e){const t=this.config.agentId??"unknown",o=this.config.sessionId,s=this.config.workingDirectory,a=this.config;return{spawnSubAgent:async i=>{const u=await e.spawn({parentAgentId:t,parentSessionId:o,subagentType:i.subagentType,description:i.description,prompt:i.prompt,workingDirectory:s,parentConfig:{...a,sharedMcpConnections:this.state?.mcpConnections}});return await e.start(u),{subId:u}},listSubAgents:async()=>{const i=e.listByParent(t),u=[],r=[];for(const c of i){const l={subId:c.subId,subagentType:c.subagentType,description:c.description,status:c.status,startedAt:c.startedAt,endedAt:c.endedAt,durationMs:c.durationMs};c.status==="pending"||c.status==="running"?u.push(l):r.push(l)}return r.sort((c,l)=>(l.endedAt??0)-(c.endedAt??0)),{running:u,history:r}},getSubAgentStatus:async i=>{const u=e.getSubAgent(i);return u?{subId:u.subId,subagentType:u.subagentType,description:u.description,status:u.status,startedAt:u.startedAt,endedAt:u.endedAt,durationMs:u.durationMs,prompt:u.prompt,result:u.result,errorMessage:u.errorMessage,contextSnapshot:u.contextSnapshot}:null},awaitSubAgents:async(i,u)=>{const r=new Set;for(const c of i)this.pendingAwaitedSubIds.add(c),r.add(c);try{return await e.awaitCompletion(i,u)}finally{for(const c of r)this.pendingAwaitedSubIds.delete(c)}},abortSubAgent:i=>e.abort(i)}}buildAwaitCompleteDeps(){const e=this.config.agentId??"unknown",t=this.config.subAgentManager;return{agentId:e,awaitSubAgents:t?(o,s)=>{for(const a of o)this.pendingAwaitedSubIds.add(a);try{return this.buildSubAgentToolDeps(t).awaitSubAgents(o,s)}finally{for(const a of o)this.pendingAwaitedSubIds.delete(a)}}:null,awaitBgCommands:(o,s)=>{for(const a of o)this.pendingAwaitedBgTaskIds.add(a);try{return K.awaitCompletion(e,o,s)}finally{for(const a of o)this.pendingAwaitedBgTaskIds.delete(a)}}}}submitQuestionAnswer(e,t){const o=this.questionWaiters.get(e);return o?(this.questionWaiters.delete(e),this.isTurnSuperseded(o.contextVersion)?(o.reject(new Error("turn superseded before user answered")),!1):(o.resolve(t),!0)):!1}rejectAllQuestionWaiters(e){if(this.questionWaiters.size!==0){for(const[,t]of this.questionWaiters)t.reject(new Error(`ask_user_question ${e}`));this.questionWaiters.clear()}}cancelPendingAwaitedSubAgents(){if(this.pendingAwaitedSubIds.size===0)return;const e=this.config.subAgentManager;if(!e)return;const t=Array.from(this.pendingAwaitedSubIds);m(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited sub-agent(s): ${t.join(", ")}`);for(const o of t)e.abort(o).catch(s=>{m(`[ACodeRuntime] \u26A0\uFE0F manager.abort(${o}) threw: ${s instanceof Error?s.message:String(s)}`)})}cancelPendingAwaitedBgTasks(){if(this.pendingAwaitedBgTaskIds.size===0)return;const e=this.config.agentId??"unknown",t=Array.from(this.pendingAwaitedBgTaskIds);m(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited background command(s): ${t.join(", ")}`),K.interruptAwaits(e,t)}async stop(){if(this.state.terminated)return;this.state.terminated=!0,this.notifyRuntimeStop(),this.abortRequested=this.activeTurn,this.abortController?.abort(),this.abortController=null,this.rejectAllQuestionWaiters("session terminated"),this.cancelPendingAwaitedSubAgents(),this.cancelPendingAwaitedBgTasks(),await H("ACode active turn shutdown",this.submitQueue,t=>{this.emitAcodeEvent("error",{message:t})}),await this.disconnectMcpServers();const e=this.config.agentId||"unknown";if(await H("ACode background commands shutdown",K.disposeAgent(e),t=>{this.emitAcodeEvent("error",{message:t})}),H("ACode agent PTY sessions shutdown",Promise.resolve(this.config.terminalManager?.killByAgent?.(e)),t=>{this.emitAcodeEvent("error",{message:t})}),await H("ACode Stop hooks",this.hookBus.dispatch("Stop",{reason:"session_stop"}),t=>{this.emitAcodeEvent("error",{message:t})}),this.state.terminated=!0,this.sessionCompleteEmitted||(this.sessionCompleteEmitted=!0,this.emitAcodeEvent("session_complete",{exitCode:0})),this.stopCompactionDebugLog(),this.stopSkillWatchers(),te)try{J.promises.appendFile(ke,`[${new Date().toISOString()}] runtime stopped | ---
|
|
12
|
+
`,"utf-8").catch(()=>{})}catch{}}resolveCommandDirs(e){const t=[...this.config.commandDirs??[],...e.commandDirs??[],...e.commands?.directories??[]];return[...new Set(t.map(o=>o.trim()).filter(Boolean))]}async runModelTurn(e,t=this.contextVersion){let o="",s,a,i,u="",r=0;m(`[ACodeRuntime] \u25B6\uFE0F runModelTurn started (contextVersion: ${t})`);const c=50;for(let l=0;l<c;l+=1){if(m(`[ACodeRuntime] \u{1F504} Iteration ${l+1} starting...`),this.isTurnSuperseded(t))return m(`[ACodeRuntime] \u26A0\uFE0F Turn superseded at iteration ${l+1}, aborting`),{text:"",totalOutputTextLength:u.length};const g=Date.now(),y=await this.requestChatCompletion(e),b=Date.now()-g;if(m(`[ACodeRuntime] \u{1F916} AI request completed in ${b}ms, choices: ${y.choices?.length||0}`),this.isTurnSuperseded(t))return m(`[ACodeRuntime] \u26A0\uFE0F Turn superseded after AI response at iteration ${l+1}`),{text:"",totalOutputTextLength:u.length};if(this.state.terminated)throw m(`[ACodeRuntime] Runtime terminated at iteration ${l+1}`),new Error("ACode runtime was stopped during the active turn");const d=y.choices?.[0];a=JSON.stringify(y,null,2),i=typeof d?.finish_reason=="string"?d.finish_reason:void 0;const $=d?.message,h=typeof $?.content=="string"?$.content:"",f=Array.isArray($?.tool_calls)?$.tool_calls:[];if(m(`[ACodeRuntime] AI response: content=${h?h.slice(0,100)+(h.length>100?"...":""):"(empty)"}, toolCalls=${f.length}, finishReason=${i||"(none)"}`),y.usage){const A=y.usage.prompt_tokens??y.usage.input_tokens,M=y.usage.completion_tokens??y.usage.output_tokens;typeof A=="number"&&typeof M=="number"&&(s={inputTokens:A,outputTokens:M},r+=A,this.state.accumulatedInputTokens=A,this.state.accumulatedOutputTokens=M,m(`[ACodeRuntime] \u{1F4B0} Token usage: input=${A}, output=${M} (turn accumulated cost: input=${r})`))}if(this.state.conversation.push({role:"assistant",content:h||null,tool_calls:f.length>0?f:void 0}),h&&(o=h,u+=h,m(`[ACodeRuntime] \u2728 Captured assistant text: ${h.slice(0,80)}...`)),f.length===0)return m(`[ACodeRuntime] \u2705 No tool calls at iteration ${l+1}, completing turn`),{text:o,usage:s,responseBody:a,finishReason:i,totalOutputTextLength:u.length};const C=f.map(A=>A.function.name).join(", ");m(`[ACodeRuntime] \u{1F527} Executing ${f.length} tool(s) at iteration ${l+1}: ${C}`);const _=Date.now();await this.handleToolCalls(f,e,t);const k=Date.now()-_;if(m(`[ACodeRuntime] \u2699\uFE0F Tool execution completed in ${k}ms at iteration ${l+1}`),this.isTurnSuperseded(t))return m(`[ACodeRuntime] \u26A0\uFE0F Turn superseded after tool execution at iteration ${l+1}`),{text:"",totalOutputTextLength:u.length};m(`[ACodeRuntime] \u{1F504} Preparing iteration ${l+2}...`)}return console.error(`[ACodeRuntime] \u{1F6A8} CRITICAL: Reached safety limit of ${c} iterations! This indicates a potential infinite loop. Forcing turn completion.`),{text:o||`ACode \u5DF2\u8FBE\u5230\u5B89\u5168\u8FED\u4EE3\u4E0A\u9650\uFF08${c}\u6B21\uFF09\uFF0C\u5F3A\u5236\u7ED3\u675F\u672C\u8F6E\u5BF9\u8BDD\u3002`,usage:s,responseBody:a,finishReason:i||"safety_iteration_limit_reached",totalOutputTextLength:u.length}}async summarizeConversationWithLLM(e){const t=this.state.provider,o=t.baseURL;if(!o)throw new Error("ACode provider baseURL is not configured for LLM summarization");const s={"Content-Type":"application/json"};t.apiKey&&(s.Authorization=`Bearer ${t.apiKey}`);const a={model:t.model,stream:!1,messages:[{role:"system",content:"You are a helpful AI assistant tasked with summarizing conversations. When asked to summarize, provide a detailed but concise summary of the conversation. Focus on information that would be helpful for continuing the conversation, especially what was in progress and what needs to happen next. Do not respond to any questions in the conversation, only output the summary."},{role:"user",content:`Below is an earlier conversation (${e.messageCount} messages) that needs to be summarized to free context space (current context limit: ${e.contextLimit} tokens).
|
|
13
13
|
|
|
14
14
|
--- Conversation Start ---
|
|
15
15
|
${e.conversationText}
|
|
16
16
|
--- Conversation End ---
|
|
17
17
|
|
|
18
|
-
`+Xe}]},s=new AbortController;this.abortController=s;let r=!1;try{return await v((async()=>{const u=await v(fetch(Y(n),{method:"POST",headers:i,body:JSON.stringify(a),signal:s.signal}),t.requestTimeoutMs,"ACode LLM summarization",()=>{r=!0,s.abort()});if(!u.ok){const f=await v(u.text(),t.requestTimeoutMs,"ACode LLM summarization error response body",()=>{r=!0,s.abort()}),y=f.length>500?`${f.slice(0,500)}...(truncated, total ${f.length} chars)`:f;throw new Error(`ACode LLM summarization request failed: ${u.status} ${y}`)}const l=(await v(u.json(),t.requestTimeoutMs,"ACode LLM summarization response body",()=>{r=!0,s.abort()})).choices?.[0]?.message?.content;if(!l||l.trim().length===0)throw new Error("ACode LLM summarization returned empty content");return l})(),t.requestTotalTimeoutMs,"ACode LLM summarization total",()=>{s.abort()})}catch(u){throw u instanceof Error&&u.name==="AbortError"?r?new Error(`ACode LLM summarization timed out after ${t.requestTimeoutMs}ms`):new Error("ACode LLM summarization aborted"):u}finally{this.abortController===s&&(this.abortController=null)}}async requestChatCompletion(e){const t=this.state.provider,n=t.baseURL;if(!n)throw new Error("ACode provider baseURL is not configured");const{contextLimit:i,maxOutput:a,inputLimit:s,threshold:r}=te(t),u=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,m=H(this.state.conversation)+$e(this.state.exposedTools),l=Math.max(u,m),f=l>=r;if(c(`[ACodeRuntime] \u{1F50D} Compaction check: actualUsed=${u}, estimation=${m}, effectiveUsed=${l}, contextLimit=${i}, inputLimit=${s??"n/a"}, maxOutput=${a}, triggerThreshold=${r}, shouldCompact=${f}`),f){const C=j(this.state.conversation),T=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:T,sizeKB:C,estimatedTokens:m,actualInputTokens:this.state.accumulatedInputTokens,actualOutputTokens:this.state.accumulatedOutputTokens,messageCount:this.state.conversation.length,model:t.model,trigger:u>=r?"actual_usage":"estimated_overflow"}),this.emitCompactionPhase(T,"detect","\u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6709\u6548\u7528\u91CF: ${l} tokens, \u9608\u503C: ${r}, \u89E6\u53D1: ${u>=r?"\u5B9E\u9645\u7528\u91CF":"\u4F30\u7B97\u6EA2\u51FA"}`);const x=await le(this.state.conversation,i,a,{llmSummarizer:E=>this.summarizeConversationWithLLM(E),onPhase:E=>this.handleCompactionPhase(T,E),actualUsedTokens:l}),R=j(this.state.conversation);this.emitAcodeEvent("context_compaction",{action:"end",compactionId:T,sizeBeforeKB:C,sizeAfterKB:R,freedKB:Math.round((C-R)*10)/10,strategy:x.strategy,freedTokens:x.freedTokens,tokensBefore:x.tokensBefore,tokensAfter:x.tokensAfter,prunedToolMessages:x.prunedToolMessages,summarizedMessages:x.summarizedMessages,messageCountBefore:x.messageCountBefore,messageCountAfter:x.messageCountAfter}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}const y=await Bt(this.state.conversation,Te,i,a,C=>this.summarizeConversationWithLLM(C));y>0&&(this.emitAcodeEvent("warning",{message:`Conversation truncated: removed ${y} older messages to fit within ${Te} byte request size limit`}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0);const w=this.state.exposedTools.filter(C=>Lt(C,this.state.permissions,e)),g=()=>{const C={model:t.model,messages:this.state.conversation,stream:t.stream};return t.effort&&(C.reasoning_effort=t.effort),t.stream&&(C.stream_options={include_usage:!0}),w.length>0&&(C.tools=Ne(w),C.tool_choice="auto"),C},b="POST",h=Pt(n),d=Yt(t),_=Vt(d),M=C=>{const T=JSON.stringify(C,null,2);c(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 emitAiRequest: \u53D1\u9001\u8BF7\u6C42 model=${t.model}, endpoint=${h}, messageCount=${this.state.conversation.length}`),this.emitAcodeEvent("ai_request",{model:t.model,endpoint:h,requestMethod:b,requestUrl:h,requestHeaders:_,stream:t.stream,messageCount:this.state.conversation.length,toolCount:w.length,lastUserMessagePreview:Dt(this.state.conversation),estimatedContextTokens:be(T),requestBody:T})};let $=g();M($);const A=t.requestRetryCount===ee,S=A?1/0:t.requestRetryCount+1;let I=!1;for(let C=1;A||C<=S;C+=1){const T=new AbortController;this.abortController=T;let x=!1;try{return await v((async()=>{const R=await v(fetch(Y(n),{method:b,headers:d,body:JSON.stringify($),signal:T.signal}),t.requestTimeoutMs,"ACode provider request",()=>{x=!0,T.abort()});if(!R.ok){const p=await v(R.text(),t.requestTimeoutMs,"ACode provider error response body",()=>{x=!0,T.abort()}),D=p.length>500?`${p.slice(0,500)}...(truncated, total ${p.length} chars)`:p;throw new Error(`ACode provider request failed: ${R.status} ${D}`)}const E=R.headers?.get?.("content-type")||"";if(t.stream&&E.toLowerCase().includes("text/event-stream"))return await this.readChatCompletionStream(R,t.requestTimeoutMs,T);const L=await v(R.json(),t.requestTimeoutMs,"ACode provider response body",()=>{x=!0,T.abort()});return k(L)?L:(this.emitAcodeEvent("warning",{message:`ACode provider returned invalid response format (expected object, got ${typeof L}); treating as empty response`}),{})})(),t.requestTotalTimeoutMs,"ACode provider request total",()=>{T.abort()})}catch(R){let E;if(R instanceof Error&&R.name==="AbortError"?E=x?new Error(`ACode provider request timed out after ${t.requestTimeoutMs}ms`):new Error("ACode provider request aborted"):E=R instanceof Error?R:new Error(String(R)),!I&&!this.abortRequested&&!this.state.terminated&&xe(E)){const p=j(this.state.conversation),D=H(this.state.conversation),V=this.state.conversation.length,U=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:U,sizeKB:p,estimatedTokens:D,messageCount:V,model:t.model,trigger:"provider_overflow_error"}),this.emitCompactionPhase(U,"detect","Provider \u8FD4\u56DE\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6D88\u606F: ${V}\u6761, \u5927\u5C0F: ${p}KB`),this.emitCompactionPhase(U,"prune","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA","\u6B63\u5728\u88C1\u526A...");const z=Ze(this.state.conversation,i);this.emitCompactionPhase(U,"prune_done","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA",`\u88C1\u526A\u4E86 ${z.prunedCount} \u6761\u5DE5\u5177\u8F93\u51FA, \u91CA\u653E ${z.freedTokens} tokens`),this.emitCompactionPhase(U,"summarize","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD","\u6B63\u5728\u6458\u8981...");const J=await me(this.state.conversation,{llmSummarizer:Pe=>this.summarizeConversationWithLLM(Pe),contextLimit:i});this.emitCompactionPhase(U,"summarize_done","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD",`\u6458\u8981\u5316\u4E86 ${J} \u6761\u6D88\u606F`);const ae=j(this.state.conversation),Ie=H(this.state.conversation),Le=this.state.conversation.length;I=!0;const ue=z.prunedCount+J;if(this.emitAcodeEvent("context_compaction",{action:"end",compactionId:U,sizeBeforeKB:p,sizeAfterKB:ae,freedKB:Math.round((p-ae)*10)/10,tokensBefore:D,tokensAfter:Ie,messageCountBefore:V,messageCountAfter:Le,strategy:J>0?"summarize":"prune",freedTokens:z.freedTokens,prunedToolMessages:z.prunedCount,summarizedMessages:J,trigger:"provider_overflow_error"}),ue===0)throw E;this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0,this.emitAcodeEvent("warning",{message:`ACode provider context limit exceeded; summarized ${ue} older messages and rebuilt the request instead of retrying the same oversized payload`}),$=g(),M($),C-=1;continue}if(!((A||C<S)&&!this.abortRequested&&!this.state.terminated&&zt(E)))throw E;this.emitAcodeEvent("error",{message:`ACode provider request attempt ${C}${A?"":`/${S}`} failed; retrying: ${E.message}`,nonFatal:!0}),await yt(ct*C)}finally{this.abortController===T&&(this.abortController=null)}}throw new Error("ACode provider request failed after all retries")}async readChatCompletionStream(e,t,n){if(!e.body)throw new Error("ACode provider stream response has no body");const i=e.body.getReader(),a=new TextDecoder,s=new Map;let r="",u="",m;const l=f=>{for(const y of eo(f)){if(y==="[DONE]")continue;const w=JSON.parse(y);if(!k(w))continue;const g=w.usage;g&&(m=g);const h=w.choices?.[0]?.delta,d=Jt(h);d&&this.emitAcodeEvent("thinking_delta",{text:d});const _=typeof h?.content=="string"?h.content:"";_&&(r+=_,this.emitAcodeEvent("assistant_delta",{text:_}));const M=Array.isArray(h?.tool_calls)?h.tool_calls:[];for(const $ of M)to(s,$)}};for(;;){const{done:f,value:y}=await v(i.read(),t,"ACode provider stream idle",()=>n?.abort());if(f)break;u+=a.decode(y,{stream:!0});const w=u.split(/\r?\n\r?\n/);u=w.pop()??"";for(const g of w)l(g)}return u+=a.decode(),u.trim()&&l(u),{choices:[{message:{content:r||null,tool_calls:oo(s)}}],...m?{usage:m}:{}}}async handleToolCalls(e,t,n=this.contextVersion){c(`[ACodeRuntime] handleToolCalls started with ${e.length} tool(s)`);for(const i of e){if(this.isTurnSuperseded(n)){c("[ACodeRuntime] \uFE0F Turn superseded, skipping remaining tools");return}const a=i.function.name;c(`[ACodeRuntime] \u{1F50D} Looking up tool: ${a}`);let s=this.state.exposedTools.find(r=>r.exposedName===a);if(s||(s=this.state.exposedTools.find(r=>r.toolName===a),s&&c(`[ACodeRuntime] \u21A9\uFE0F \u88F8\u540D\u56DE\u9000\u5339\u914D: ${a} -> ${s.exposedName}`)),!s){console.error(`[ACodeRuntime] \u274C Tool not found: ${a}, available tools: ${this.state.exposedTools.map(r=>r.exposedName).join(", ")}`),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:`ACode MCP tool not found: ${a}`});continue}c(`[ACodeRuntime] Found tool: ${s.toolName} (kind: ${s.kind}, source: ${s.kind==="mcp"?s.serverName:"builtin"})`);try{if(s.kind==="builtin"){const d=ve(i.function.arguments);c(`[ACodeRuntime] Built-in tool arguments: ${JSON.stringify(d).slice(0,200)}`),re(s,this.state.permissions,t);const _=await this.hookBus.dispatch("PreToolUse",{source:"builtin",toolName:s.toolName,exposedName:s.exposedName,arguments:d});if(this.isTurnSuperseded(n))return;const M=X(_);if(M)throw console.error(`[ACodeRuntime] \u274C Tool denied by hook: ${s.exposedName}: ${M.message}`),new Error(M.message||`ACode tool denied by hook: ${s.exposedName}`);c(`[ACodeRuntime] Emitting mcp_status call_tool for ${s.exposedName}`),this.emitAcodeEvent("mcp_status",{action:"call_tool",server:"builtin",tool:s.toolName,exposedName:s.exposedName,toolUseId:i.id,arguments:d,argumentsPreview:Ee(d)});const $=Date.now(),A=Ot(s,d,this.state.provider.mcpToolTimeoutMs);c(`[ACodeRuntime] \u25B6\uFE0F Executing built-in tool: ${s.exposedName} (timeout: ${A}ms, abortRequested: ${this.abortRequested})`),A<=0&&console.warn(`[ACodeRuntime] \u26A0\uFE0F Built-in tool ${s.exposedName} has NO timeout (timeoutMs=${A})! If this tool hangs, executeSubmit will NEVER resolve, blocking the submit queue permanently.`);const S=await v(s.execute(d,{onOutput:T=>{this.emitAcodeEvent("command_output",{server:"builtin",tool:s.toolName,exposedName:s.exposedName,toolUseId:i.id,stream:T.stream,text:T.text,sequence:T.sequence,cwd:T.cwd,commandLineCount:T.commandLineCount,...T.commandFilePath?{commandFilePath:T.commandFilePath}:{}})},toolCallId:i.id}),A,`ACode built-in tool ${s.toolName}`),I=Date.now()-$;if(c(`[ACodeRuntime] \u2705 Built-in tool ${s.exposedName} completed in ${I}ms`),this.isTurnSuperseded(n)||(await this.hookBus.dispatch("PostToolUse",{source:"builtin",toolName:s.toolName,exposedName:s.exposedName,result:P(S)}),this.isTurnSuperseded(n)))return;const C=P(S);c(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result for ${s.exposedName}, result length: ${C.length} chars`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:"builtin",tool:s.toolName,result:C}),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:C}),await this.appendSyntheticMultimodalUserMessage(C,i.id,n);continue}const r=this.state.mcpConnections.find(d=>d.serverName===s.serverName);if(!r){console.error(`[ACodeRuntime] \u274C MCP server not connected: ${s.serverName}, connected servers: ${this.state.mcpConnections.map(d=>d.serverName).join(", ")}`),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:`ACode MCP server not connected: ${s.serverName}`});continue}const u=ve(i.function.arguments);c(`[ACodeRuntime] MCP tool arguments: ${JSON.stringify(u).slice(0,200)}`),re(s,this.state.permissions,t);const m=await this.hookBus.dispatch("PreToolUse",{source:"mcp",serverName:s.serverName,toolName:s.toolName,exposedName:s.exposedName,arguments:u});if(this.isTurnSuperseded(n))return;const l=X(m);if(l)throw console.error(`[ACodeRuntime] \u274C MCP tool denied by hook: ${s.exposedName}: ${l.message}`),new Error(l.message||`ACode tool denied by hook: ${s.exposedName}`);c(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status call_tool for MCP ${s.exposedName}`),this.emitAcodeEvent("mcp_status",{action:"call_tool",server:s.serverName,tool:s.toolName,exposedName:s.exposedName,toolUseId:i.id,arguments:u,argumentsPreview:Ee(u)});const f=nt(s.toolName),y=f?this.state.provider.mcpPollingToolTimeoutMs:this.state.provider.mcpToolTimeoutMs,w=Date.now();c(`[ACodeRuntime] \u25B6\uFE0F Executing MCP tool: ${s.exposedName} (timeout: ${y}ms, polling: ${f})`);const g=f&&st(s.toolName)==="poll_message"?await this.callPollMessageWithSubAgentRace(r,s,u,y):await this.callMcpToolWithTimeout(r,s,u,y,f),b=Date.now()-w;if(c(`[ACodeRuntime] \u2705 MCP tool ${s.exposedName} completed in ${b}ms`),this.isTurnSuperseded(n)||(await this.hookBus.dispatch("PostToolUse",{source:"mcp",serverName:s.serverName,toolName:s.toolName,exposedName:s.exposedName,result:P(g)}),this.isTurnSuperseded(n)))return;const h=P(g);c(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result for MCP ${s.exposedName}, result length: ${h.length} chars`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:s.serverName,tool:s.toolName,result:h}),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:h}),await this.appendSyntheticMultimodalUserMessage(h,i.id,n)}catch(r){const u=r instanceof Error&&r.message.includes("timed out after"),m=r instanceof Error&&r.name==="AbortError";if(console.error(`[ACodeRuntime] \u274C Tool execution failed: ${i.function.name}`,`isTimeout=${u}, isAbortError=${m}`,r instanceof Error?r.message:String(r)),this.isTurnSuperseded(n)){c("[ACodeRuntime] \uFE0F Turn superseded after tool error, skipping");return}if(this.abortRequested||this.state.terminated)throw c(`[ACodeRuntime] \u26A0\uFE0F Rethrowing error due to abort/termination (abortRequested=${this.abortRequested}, terminated=${this.state.terminated})`),c(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result (failed, aborted) for ${s.exposedName} before rethrow to close timeline entry`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:s.kind==="mcp"?s.serverName:"builtin",tool:s.toolName,result:`[aborted] ${r instanceof Error?r.message:String(r)}`,failed:!0,aborted:!0}),r instanceof Error?r:new Error(String(r));c(`[ACodeRuntime] Calling appendToolFailureResult for ${s.exposedName} (isTimeout=${u})`),this.appendToolFailureResult(i,s,r)}}c(`[ACodeRuntime] handleToolCalls completed for all ${e.length} tool(s)`)}async callMcpToolWithTimeout(e,t,n,i,a){const s=i>0?i:lt,u=!!this.config.sharedMcpConnections?{...n,_aws_sub_agent:!0}:n;for(;;){const m=this.createRuntimeStopWaiter(`ACode MCP tool ${t.serverName}/${t.toolName}`);try{return await v(Promise.race([e.client.callTool({name:t.toolName,arguments:u},void 0,{timeout:s}),m.promise]),i,`ACode MCP tool ${t.serverName}/${t.toolName}`)}catch(l){if(!a||i>0||!Ft(l))throw l;this.emitAcodeEvent("warning",{message:`ACode MCP polling tool ${t.serverName}/${t.toolName} reached the MCP SDK timeout window and will continue polling.`})}finally{m.cancel()}}}static formatSubAgentCompletionAsPollResult(e){const t=e.map(n=>{const i=n.error?`Sub-agent ${n.subId} [${n.status}]: ${n.description}
|
|
19
|
-
Error: ${
|
|
20
|
-
Output: ${
|
|
21
|
-
Error: ${
|
|
22
|
-
Output: ${
|
|
23
|
-
`);return
|
|
24
|
-
${
|
|
18
|
+
`+rt}]},i=new AbortController;this.abortController=i;let u=!1;try{return await x((async()=>{const r=await x(fetch(oe(o),{method:"POST",headers:s,body:JSON.stringify(a),signal:i.signal}),t.requestTimeoutMs,"ACode LLM summarization",()=>{u=!0,i.abort()});if(!r.ok){const g=await x(r.text(),t.requestTimeoutMs,"ACode LLM summarization error response body",()=>{u=!0,i.abort()}),y=g.length>500?`${g.slice(0,500)}...(truncated, total ${g.length} chars)`:g;throw new Error(`ACode LLM summarization request failed: ${r.status} ${y}`)}const l=(await x(r.json(),t.requestTimeoutMs,"ACode LLM summarization response body",()=>{u=!0,i.abort()})).choices?.[0]?.message?.content;if(!l||l.trim().length===0)throw new Error("ACode LLM summarization returned empty content");return l})(),t.requestTotalTimeoutMs,"ACode LLM summarization total",()=>{i.abort()})}catch(r){throw r instanceof Error&&r.name==="AbortError"?u?new Error(`ACode LLM summarization timed out after ${t.requestTimeoutMs}ms`):new Error("ACode LLM summarization aborted"):r}finally{this.abortController===i&&(this.abortController=null)}}async requestChatCompletion(e){const t=this.state.provider,o=t.baseURL;if(!o)throw new Error("ACode provider baseURL is not configured");const{contextLimit:s,maxOutput:a,inputLimit:i,threshold:u}=ae(t),r=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,c=X(this.state.conversation)+Ee(this.state.exposedTools),l=Math.max(r,c),g=l>=u;if(m(`[ACodeRuntime] \u{1F50D} Compaction check: actualUsed=${r}, estimation=${c}, effectiveUsed=${l}, contextLimit=${s}, inputLimit=${i??"n/a"}, maxOutput=${a}, triggerThreshold=${u}, shouldCompact=${g}`),g){const T=Q(this.state.conversation),S=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:S,sizeKB:T,estimatedTokens:c,actualInputTokens:this.state.accumulatedInputTokens,actualOutputTokens:this.state.accumulatedOutputTokens,messageCount:this.state.conversation.length,model:t.model,trigger:r>=u?"actual_usage":"estimated_overflow"}),this.emitCompactionPhase(S,"detect","\u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6709\u6548\u7528\u91CF: ${l} tokens, \u9608\u503C: ${u}, \u89E6\u53D1: ${r>=u?"\u5B9E\u9645\u7528\u91CF":"\u4F30\u7B97\u6EA2\u51FA"}`);const R=await he(this.state.conversation,s,a,{llmSummarizer:E=>this.summarizeConversationWithLLM(E),onPhase:E=>this.handleCompactionPhase(S,E),actualUsedTokens:l}),w=Q(this.state.conversation);this.emitAcodeEvent("context_compaction",{action:"end",compactionId:S,sizeBeforeKB:T,sizeAfterKB:w,freedKB:Math.round((T-w)*10)/10,strategy:R.strategy,freedTokens:R.freedTokens,tokensBefore:R.tokensBefore,tokensAfter:R.tokensAfter,prunedToolMessages:R.prunedToolMessages,summarizedMessages:R.summarizedMessages,messageCountBefore:R.messageCountBefore,messageCountAfter:R.messageCountAfter}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}const y=await Ht(this.state.conversation,Re,s,a,T=>this.summarizeConversationWithLLM(T));y>0&&(this.emitAcodeEvent("warning",{message:`Conversation truncated: removed ${y} older messages to fit within ${Re} byte request size limit`}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0);const b=this.state.exposedTools.filter(T=>Ft(T,this.state.permissions,e)),d=()=>{const T={model:t.model,messages:this.state.conversation,stream:t.stream};return t.effort&&(T.reasoning_effort=t.effort),t.stream&&(T.stream_options={include_usage:!0}),b.length>0&&(T.tools=Ue(b),T.tool_choice="auto"),T},$="POST",h=jt(o),f=so(t),C=io(f),_=T=>{const S=JSON.stringify(T,null,2);m(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 emitAiRequest: \u53D1\u9001\u8BF7\u6C42 model=${t.model}, endpoint=${h}, messageCount=${this.state.conversation.length}`),this.emitAcodeEvent("ai_request",{model:t.model,endpoint:h,requestMethod:$,requestUrl:h,requestHeaders:C,stream:t.stream,messageCount:this.state.conversation.length,toolCount:b.length,lastUserMessagePreview:Wt(this.state.conversation),estimatedContextTokens:ve(S),requestBody:S})};let k=d();_(k);const A=t.requestRetryCount===re,M=A?1/0:t.requestRetryCount+1;let N=!1;for(let T=1;A||T<=M;T+=1){this.state.terminated||(this.abortRequested=!1),T>1&&_(k);const S=new AbortController;this.abortController=S;let R=!1;try{return await x((async()=>{const w=await x(fetch(oe(o),{method:$,headers:f,body:JSON.stringify(k),signal:S.signal}),t.requestFirstByteTimeoutMs,"ACode provider request",()=>{R=!0,S.abort()});if(!w.ok){const O=await x(w.text(),t.requestStreamIdleTimeoutMs,"ACode provider error response body",()=>{R=!0,S.abort()}),D=O.length>500?`${O.slice(0,500)}...(truncated, total ${O.length} chars)`:O;throw new Error(`ACode provider request failed: ${w.status} ${D}`)}const E=w.headers?.get?.("content-type")||"";if(t.stream&&E.toLowerCase().includes("text/event-stream"))return await this.readChatCompletionStream(w,t.requestStreamIdleTimeoutMs,S,t.requestFirstByteTimeoutMs);const L=await x(w.json(),t.requestStreamIdleTimeoutMs,"ACode provider response body",()=>{R=!0,S.abort()});return v(L)?L:(this.emitAcodeEvent("warning",{message:`ACode provider returned invalid response format (expected object, got ${typeof L}); treating as empty response`}),{})})(),t.requestTotalTimeoutMs,"ACode provider request total",()=>{S.abort()})}catch(w){let E;if(w instanceof Error&&w.name==="AbortError"?R?E=new Error(`ACode provider request timed out (firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):this.state.terminated?E=new Error("ACode provider request aborted by user"):E=new Error(`ACode provider request timed out (watchdog abort, firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):E=w instanceof Error?w:new Error(String(w)),!N&&!this.abortRequested&&!this.state.terminated&&Le(E)){const p=Q(this.state.conversation),z=X(this.state.conversation),ne=this.state.conversation.length,B=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:B,sizeKB:p,estimatedTokens:z,messageCount:ne,model:t.model,trigger:"provider_overflow_error"}),this.emitCompactionPhase(B,"detect","Provider \u8FD4\u56DE\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6D88\u606F: ${ne}\u6761, \u5927\u5C0F: ${p}KB`),this.emitCompactionPhase(B,"prune","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA","\u6B63\u5728\u88C1\u526A...");const W=at(this.state.conversation,s);this.emitCompactionPhase(B,"prune_done","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA",`\u88C1\u526A\u4E86 ${W.prunedCount} \u6761\u5DE5\u5177\u8F93\u51FA, \u91CA\u653E ${W.freedTokens} tokens`),this.emitCompactionPhase(B,"summarize","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD","\u6B63\u5728\u6458\u8981...");const Y=await fe(this.state.conversation,{llmSummarizer:ze=>this.summarizeConversationWithLLM(ze),contextLimit:s});this.emitCompactionPhase(B,"summarize_done","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD",`\u6458\u8981\u5316\u4E86 ${Y} \u6761\u6D88\u606F`);const me=Q(this.state.conversation),Be=X(this.state.conversation),qe=this.state.conversation.length;N=!0;const de=W.prunedCount+Y;if(this.emitAcodeEvent("context_compaction",{action:"end",compactionId:B,sizeBeforeKB:p,sizeAfterKB:me,freedKB:Math.round((p-me)*10)/10,tokensBefore:z,tokensAfter:Be,messageCountBefore:ne,messageCountAfter:qe,strategy:Y>0?"summarize":"prune",freedTokens:W.freedTokens,prunedToolMessages:W.prunedCount,summarizedMessages:Y,trigger:"provider_overflow_error"}),de===0)throw E;this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0,this.emitAcodeEvent("warning",{message:`ACode provider context limit exceeded; summarized ${de} older messages and rebuilt the request instead of retrying the same oversized payload`}),k=d(),_(k),T-=1;continue}if(!((A||T<M)&&!this.abortRequested&&!this.state.terminated&&Gt(E)))throw E;this.emitAcodeEvent("error",{message:`ACode provider request attempt ${T}${A?"":`/${M}`} failed; retrying: ${E.message}`,nonFatal:!0});const O=Math.min(yt,gt*Math.pow(2,T-1)),D=Math.random()*1e3;await Mt(O+D)}finally{this.abortController===S&&(this.abortController=null)}}throw new Error("ACode provider request failed after all retries")}async readChatCompletionStream(e,t,o,s){if(!e.body)throw new Error("ACode provider stream response has no body");const a=e.body.getReader(),i=new TextDecoder,u=new Map;let r="",c="",l;const g=b=>{for(const d of uo(b)){if(d==="[DONE]")continue;const $=JSON.parse(d);if(!v($))continue;const h=$.usage;h&&(l=h);const C=$.choices?.[0]?.delta,_=Zt(C);_&&this.emitAcodeEvent("thinking_delta",{text:_});const k=typeof C?.content=="string"?C.content:"";k&&(r+=k,this.emitAcodeEvent("assistant_delta",{text:k}));const A=Array.isArray(C?.tool_calls)?C.tool_calls:[];for(const M of A)co(u,M)}};let y=!0;for(;;){const b=y&&s?s:t,{done:d,value:$}=await x(a.read(),b,y?"ACode provider stream first byte":"ACode provider stream idle",()=>o?.abort());if(y=!1,d)break;c+=i.decode($,{stream:!0});const h=c.split(/\r?\n\r?\n/);c=h.pop()??"";for(const f of h)g(f)}return c+=i.decode(),c.trim()&&g(c),{choices:[{message:{content:r||null,tool_calls:lo(u)}}],...l?{usage:l}:{}}}async handleToolCalls(e,t,o=this.contextVersion){m(`[ACodeRuntime] handleToolCalls started with ${e.length} tool(s)`);const s=i=>ge(i.function.name)==="poll_message",a=[...e.filter(i=>!s(i)),...e.filter(i=>s(i))];e.length>1&&a.some((i,u)=>i!==e[u])&&m(`[ACodeRuntime] \u2195\uFE0F Reordered tool calls (poll_message \u2192 end): ${a.map(i=>i.function.name).join(", ")}`);for(const i of a){if(this.isTurnSuperseded(o)){m("[ACodeRuntime] \uFE0F Turn superseded, skipping remaining tools");return}const u=i.function.name;m(`[ACodeRuntime] \u{1F50D} Looking up tool: ${u}`);let r=this.state.exposedTools.find(c=>c.exposedName===u);if(r||(r=this.state.exposedTools.find(c=>c.toolName===u),r&&m(`[ACodeRuntime] \u21A9\uFE0F \u88F8\u540D\u56DE\u9000\u5339\u914D: ${u} -> ${r.exposedName}`)),!r){console.error(`[ACodeRuntime] \u274C Tool not found: ${u}, available tools: ${this.state.exposedTools.map(c=>c.exposedName).join(", ")}`),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:`ACode MCP tool not found: ${u}`});continue}m(`[ACodeRuntime] Found tool: ${r.toolName} (kind: ${r.kind}, source: ${r.kind==="mcp"?r.serverName:"builtin"})`);try{if(r.kind==="builtin"){const _=Pe(i.function.arguments);m(`[ACodeRuntime] Built-in tool arguments: ${JSON.stringify(_).slice(0,200)}`),le(r,this.state.permissions,t);const k=await this.hookBus.dispatch("PreToolUse",{source:"builtin",toolName:r.toolName,exposedName:r.exposedName,arguments:_});if(this.isTurnSuperseded(o))return;const A=se(k);if(A)throw console.error(`[ACodeRuntime] \u274C Tool denied by hook: ${r.exposedName}: ${A.message}`),new Error(A.message||`ACode tool denied by hook: ${r.exposedName}`);m(`[ACodeRuntime] Emitting mcp_status call_tool for ${r.exposedName}`),this.emitAcodeEvent("mcp_status",{action:"call_tool",server:"builtin",tool:r.toolName,exposedName:r.exposedName,toolUseId:i.id,arguments:_,argumentsPreview:Oe(_)});const M=Date.now(),N=Jt(r,_,this.state.provider.mcpToolTimeoutMs);m(`[ACodeRuntime] \u25B6\uFE0F Executing built-in tool: ${r.exposedName} (timeout: ${N}ms, abortRequested: ${this.abortRequested})`),N<=0&&console.warn(`[ACodeRuntime] \u26A0\uFE0F Built-in tool ${r.exposedName} has NO timeout (timeoutMs=${N})! If this tool hangs, executeSubmit will NEVER resolve, blocking the submit queue permanently.`);const T=await x(r.execute(_,{onOutput:w=>{this.emitAcodeEvent("command_output",{server:"builtin",tool:r.toolName,exposedName:r.exposedName,toolUseId:i.id,stream:w.stream,text:w.text,sequence:w.sequence,cwd:w.cwd,commandLineCount:w.commandLineCount,...w.commandFilePath?{commandFilePath:w.commandFilePath}:{}})},toolCallId:i.id}),N,`ACode built-in tool ${r.toolName}`),S=Date.now()-M;if(m(`[ACodeRuntime] \u2705 Built-in tool ${r.exposedName} completed in ${S}ms`),this.isTurnSuperseded(o)||(await this.hookBus.dispatch("PostToolUse",{source:"builtin",toolName:r.toolName,exposedName:r.exposedName,result:P(T)}),this.isTurnSuperseded(o)))return;const R=P(T);m(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result for ${r.exposedName}, result length: ${R.length} chars`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:"builtin",tool:r.toolName,result:R}),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:R}),await this.appendSyntheticMultimodalUserMessage(R,i.id,o);continue}const c=this.state.mcpConnections.find(_=>_.serverName===r.serverName);if(!c){console.error(`[ACodeRuntime] \u274C MCP server not connected: ${r.serverName}, connected servers: ${this.state.mcpConnections.map(_=>_.serverName).join(", ")}`),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:`ACode MCP server not connected: ${r.serverName}`});continue}const l=Pe(i.function.arguments);m(`[ACodeRuntime] MCP tool arguments: ${JSON.stringify(l).slice(0,200)}`),le(r,this.state.permissions,t);const g=await this.hookBus.dispatch("PreToolUse",{source:"mcp",serverName:r.serverName,toolName:r.toolName,exposedName:r.exposedName,arguments:l});if(this.isTurnSuperseded(o))return;const y=se(g);if(y)throw console.error(`[ACodeRuntime] \u274C MCP tool denied by hook: ${r.exposedName}: ${y.message}`),new Error(y.message||`ACode tool denied by hook: ${r.exposedName}`);m(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status call_tool for MCP ${r.exposedName}`),this.emitAcodeEvent("mcp_status",{action:"call_tool",server:r.serverName,tool:r.toolName,exposedName:r.exposedName,toolUseId:i.id,arguments:l,argumentsPreview:Oe(l)});const b=mt(r.toolName),d=b?this.state.provider.mcpPollingToolTimeoutMs:this.state.provider.mcpToolTimeoutMs,$=Date.now();m(`[ACodeRuntime] \u25B6\uFE0F Executing MCP tool: ${r.exposedName} (timeout: ${d}ms, polling: ${b})`);const h=b&&ge(r.toolName)==="poll_message"?await this.callPollMessageWithSubAgentRace(c,r,l,d):await this.callMcpToolWithTimeout(c,r,l,d,b),f=Date.now()-$;if(m(`[ACodeRuntime] \u2705 MCP tool ${r.exposedName} completed in ${f}ms`),this.isTurnSuperseded(o)||(await this.hookBus.dispatch("PostToolUse",{source:"mcp",serverName:r.serverName,toolName:r.toolName,exposedName:r.exposedName,result:P(h)}),this.isTurnSuperseded(o)))return;const C=P(h);m(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result for MCP ${r.exposedName}, result length: ${C.length} chars`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:r.serverName,tool:r.toolName,result:C}),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:C}),await this.appendSyntheticMultimodalUserMessage(C,i.id,o)}catch(c){const l=c instanceof Error&&c.message.includes("timed out after"),g=c instanceof Error&&c.name==="AbortError";if(console.error(`[ACodeRuntime] \u274C Tool execution failed: ${i.function.name}`,`isTimeout=${l}, isAbortError=${g}`,c instanceof Error?c.message:String(c)),this.isTurnSuperseded(o)){m("[ACodeRuntime] \uFE0F Turn superseded after tool error, skipping");return}if(this.abortRequested||this.state.terminated)throw m(`[ACodeRuntime] \u26A0\uFE0F Rethrowing error due to abort/termination (abortRequested=${this.abortRequested}, terminated=${this.state.terminated})`),m(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result (failed, aborted) for ${r.exposedName} before rethrow to close timeline entry`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:r.kind==="mcp"?r.serverName:"builtin",tool:r.toolName,result:`[aborted] ${c instanceof Error?c.message:String(c)}`,failed:!0,aborted:!0}),c instanceof Error?c:new Error(String(c));m(`[ACodeRuntime] Calling appendToolFailureResult for ${r.exposedName} (isTimeout=${l})`),this.appendToolFailureResult(i,r,c)}}m(`[ACodeRuntime] handleToolCalls completed for all ${e.length} tool(s)`)}async callMcpToolWithTimeout(e,t,o,s,a){const i=s>0?s:At,r=!!this.config.sharedMcpConnections?{...o,_aws_sub_agent:!0}:o;for(;;){const c=this.createRuntimeStopWaiter(`ACode MCP tool ${t.serverName}/${t.toolName}`);try{return await x(Promise.race([e.client.callTool({name:t.toolName,arguments:r},void 0,{timeout:i}),c.promise]),s,`ACode MCP tool ${t.serverName}/${t.toolName}`)}catch(l){if(!a||s>0||!Yt(l))throw l;this.emitAcodeEvent("warning",{message:`ACode MCP polling tool ${t.serverName}/${t.toolName} reached the MCP SDK timeout window and will continue polling.`})}finally{c.cancel()}}}static formatSubAgentCompletionAsPollResult(e){const t=e.map(o=>{const s=o.error?`Sub-agent ${o.subId} [${o.status}]: ${o.description}
|
|
19
|
+
Error: ${o.error}`:`Sub-agent ${o.subId} [${o.status}]: ${o.description}
|
|
20
|
+
Output: ${o.output.length>500?o.output.slice(0,500)+"... (truncated)":o.output}`;return{msgId:`subagent-completion-${o.subId}-${Date.now()}`,senderId:"ACode-Runtime",senderName:"\u7CFB\u7EDF",content:s,requireReply:!1,prompt:`Sub-agent ${o.subId} (${o.description}) has reached terminal state: ${o.status}. Review its output and decide next steps.`,timestamp:new Date().toISOString()}});return{content:[{type:"text",text:JSON.stringify({directMessages:t,groupMessages:[],fromBuffer:!1,systemMessages:[]},null,2)}]}}static mergeSubAgentCompletionsIntoMcpResult(e,t){if(t.length===0)return e;const o=P(e);let s;try{s=JSON.parse(o)}catch{return e}const i=[...t.map(u=>{const r=u.error?`Sub-agent ${u.subId} [${u.status}]: ${u.description}
|
|
21
|
+
Error: ${u.error}`:`Sub-agent ${u.subId} [${u.status}]: ${u.description}
|
|
22
|
+
Output: ${u.output.length>500?u.output.slice(0,500)+"... (truncated)":u.output}`;return{msgId:`subagent-completion-${u.subId}-${Date.now()}`,senderId:"ACode-Runtime",senderName:"\u7CFB\u7EDF",content:r,requireReply:!1,prompt:`Sub-agent ${u.subId} (${u.description}) has reached terminal state: ${u.status}. Review its output and decide next steps.`,timestamp:new Date().toISOString()}}),...s.directMessages??[]];return{content:[{type:"text",text:JSON.stringify({...s,directMessages:i},null,2)}]}}async recheckMemoryDelegate(e,t,o,s){const a=this.state.mcpConnections.find(i=>i.serverName==="aws-client-agent-mcp");if(!a)return m("[ACodeRuntime] recheckMemoryDelegate: aws-client-agent-mcp connection not found, treating as done"),{done:!0};try{return e==="memory_file_change"?await this.recheckMemoryFileChange(a,t):e==="memory_expiration"?await this.recheckMemoryExpiration(a,t):await this.recheckMemoryCleanup(a,t)}catch(i){return m(`[ACodeRuntime] recheckMemoryDelegate failed (type=${e}, turn=${s}): ${i instanceof Error?i.message:String(i)}, treating as NOT done (retry via recheck loop)`),{done:!1,continueMessage:`\u7ECF\u68C0\u67E5\uFF0C\u65E0\u6CD5\u786E\u8BA4\u4EE5\u4E0B memory \u662F\u5426\u5DF2\u5904\u7406\uFF08\u6821\u9A8C\u5F02\u5E38\uFF1A${i instanceof Error?i.message:String(i)}\uFF09\u3002\u8BF7\u91CD\u65B0\u6267\u884C\u9A8C\u8BC1\u6B65\u9AA4\uFF08read_memory / get_memory_stats\uFF09\u786E\u8BA4\u771F\u5B9E\u72B6\u6001\u540E\u518D\u7EE7\u7EED\u3002`}}}async readMemoryViaMcp(e,t){try{const o=await x(e.client.callTool({name:"read_memory",arguments:{uri:t,_aws_sub_agent:!0}},void 0,{timeout:3e4}),3e4,`recheck read_memory ${t}`),s=P(o),a=JSON.parse(s);return a==null||typeof a!="object"||Array.isArray(a)?null:a}catch(o){throw o}}async recheckMemoryFileChange(e,t){const o=[];if(await Promise.all(t.map(async a=>{const i=await this.readMemoryViaMcp(e,a);i&&i.memory_status==="updating"&&o.push(a)})),o.length===0)return m(`[ACodeRuntime] recheck memory_file_change: all ${t.length} URIs done (memory_status=normal or deleted)`),{done:!0};const s=o.map(a=>`- ${a}`).join(`
|
|
23
|
+
`);return m(`[ACodeRuntime] recheck memory_file_change: ${o.length}/${t.length} URIs still updating`),{done:!1,continueMessage:`\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5BF9\u4EE5\u4E0B memory \u7684\u66F4\u65B0\uFF0C\u8BF7\u7EE7\u7EED\uFF1A
|
|
24
|
+
${s}
|
|
25
25
|
|
|
26
|
-
\u8FD9\u4E9B memory \u7684 memory_status \u4ECD\u4E3A "updating"\u3002\u8BF7\u91CD\u65B0 read_memory \u67E5\u770B\u5185\u5BB9\uFF0C\u67E5\u770B\u7ED1\u5B9A\u6587\u4EF6\u6700\u65B0\u5185\u5BB9\uFF0C\u5E76\u8C03\u7528 update_memory \u5B8C\u6210\u66F4\u65B0\u3002`}}async recheckMemoryExpiration(e,t){const
|
|
27
|
-
`);return
|
|
26
|
+
\u8FD9\u4E9B memory \u7684 memory_status \u4ECD\u4E3A "updating"\u3002\u8BF7\u91CD\u65B0 read_memory \u67E5\u770B\u5185\u5BB9\uFF0C\u67E5\u770B\u7ED1\u5B9A\u6587\u4EF6\u6700\u65B0\u5185\u5BB9\uFF0C\u5E76\u8C03\u7528 update_memory \u5B8C\u6210\u66F4\u65B0\u3002`}}async recheckMemoryExpiration(e,t){const o=[],s=Date.now();if(await Promise.all(t.map(async i=>{const u=await this.readMemoryViaMcp(e,i);if(!u)return;const r=u.expiresAt??u.expires_at,c=u.memory_status==="recalling",l=typeof r=="string"&&new Date(r).getTime()<s;(c||l)&&o.push(i)})),o.length===0)return m(`[ACodeRuntime] recheck memory_expiration: all ${t.length} URIs done (renewed, cleaned, or no longer expired)`),{done:!0};const a=o.map(i=>`- ${i}`).join(`
|
|
27
|
+
`);return m(`[ACodeRuntime] recheck memory_expiration: ${o.length}/${t.length} URIs still expired or recalling`),{done:!1,continueMessage:`\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5BF9\u4EE5\u4E0B memory \u7684\u5904\u7406\uFF0C\u8BF7\u7EE7\u7EED\uFF1A
|
|
28
28
|
${a}
|
|
29
29
|
|
|
30
|
-
\u8FD9\u4E9B memory \u4ECD\u5904\u4E8E\u8FC7\u671F\u6216\u56DE\u5FC6\u4E2D\u72B6\u6001\u3002\u8BF7\u8C03\u7528 memory_recurrence \u83B7\u53D6\u5185\u5BB9\uFF0C\u5BF9\u9700\u8981\u4FDD\u7559\u7684\u8C03\u7528 update_memory \u7EED\u671F\uFF0C\u5BF9\u65E0\u4EF7\u503C\u7684\u8C03\u7528 memory_recurrence_complete \u6E05\u7406\u3002`}}async recheckMemoryCleanup(e,t){let
|
|
31
|
-
`);return
|
|
32
|
-
${
|
|
30
|
+
\u8FD9\u4E9B memory \u4ECD\u5904\u4E8E\u8FC7\u671F\u6216\u56DE\u5FC6\u4E2D\u72B6\u6001\u3002\u8BF7\u8C03\u7528 memory_recurrence \u83B7\u53D6\u5185\u5BB9\uFF0C\u5BF9\u9700\u8981\u4FDD\u7559\u7684\u8C03\u7528 update_memory \u7EED\u671F\uFF0C\u5BF9\u65E0\u4EF7\u503C\u7684\u8C03\u7528 memory_recurrence_complete \u6E05\u7406\u3002`}}async recheckMemoryCleanup(e,t){let o;try{const u=await x(e.client.callTool({name:"get_memory_stats",arguments:{_aws_sub_agent:!0}},void 0,{timeout:3e4}),3e4,"recheck get_memory_stats"),r=P(u);o=JSON.parse(r)}catch{return{done:!1,continueMessage:"get_memory_stats \u67E5\u8BE2\u5931\u8D25\uFF0C\u65E0\u6CD5\u786E\u8BA4\u5BB9\u91CF\u662F\u5426\u5DF2\u8FBE\u6807\uFF0C\u8BF7\u91CD\u65B0\u9A8C\u8BC1\u540E\u518D\u7EE7\u7EED\u3002"}}const s=o.by_type??{},a=[];for(const u of t){const r=u.indexOf("/");if(r<0)continue;const c=u.slice(0,r),l=u.slice(r+1),y=s[c]?.by_domain?.[l];y?.exceeded&&a.push(`${c}/${l} (\u5F53\u524D ${y.count??"?"} \u6761\uFF0C\u5EFA\u8BAE\u4E0A\u9650 ${y.limit??"?"})`)}if(a.length===0)return m(`[ACodeRuntime] recheck memory_cleanup: all ${t.length} type/domain pairs within limits`),{done:!0};const i=a.map(u=>`- ${u}`).join(`
|
|
31
|
+
`);return m(`[ACodeRuntime] recheck memory_cleanup: ${a.length}/${t.length} type/domain pairs still exceeded`),{done:!1,continueMessage:`\u7ECF\u68C0\u67E5\uFF0C\u4EE5\u4E0B\u7C7B\u578B/\u57DF\u5C1A\u672A\u6574\u7406\u5B8C\u6210\uFF0C\u8BF7\u7EE7\u7EED\uFF1A
|
|
32
|
+
${i}
|
|
33
33
|
|
|
34
|
-
\u8BF7\u8C03\u7528 list_memories \u67E5\u770B\u8D85\u9650\u8BB0\u5FC6\uFF0C\u5220\u9664\u4E0D\u518D\u9700\u8981\u7684 recently_memory \u6216\u5BF9 agent_memory \u8C03\u7528 update_memory \u7EED\u671F\u3002`}}buildMemoryDelegatePrompt(e){const t=e.uris.map(
|
|
34
|
+
\u8BF7\u8C03\u7528 list_memories \u67E5\u770B\u8D85\u9650\u8BB0\u5FC6\uFF0C\u5220\u9664\u4E0D\u518D\u9700\u8981\u7684 recently_memory \u6216\u5BF9 agent_memory \u8C03\u7528 update_memory \u7EED\u671F\u3002`}}buildMemoryDelegatePrompt(e){const t=e.uris.map(o=>`- ${o}`).join(`
|
|
35
35
|
`);return e.type==="memory_expiration"?`\u4F60\u662F\u4E00\u6761\u4E13\u95E8\u5904\u7406 memory \u8FC7\u671F\u6574\u7406\u7684\u5B50 agent\u3002
|
|
36
36
|
|
|
37
37
|
\u5F53\u524D\u6709\u4EE5\u4E0B ${e.uris.length} \u6761\u5373\u5C06\u9057\u5FD8\u7684\u8BB0\u5FC6\u9700\u8981\u6574\u7406\uFF1A
|
|
@@ -75,11 +75,11 @@ ${t}
|
|
|
75
75
|
\u5B8C\u6210\u540E\u7CFB\u7EDF\u4F1A\u901A\u8FC7\u67E5\u8BE2\u670D\u52A1\u7AEF\u771F\u5B9E\u72B6\u6001\u8FDB\u884C\u4E8C\u6B21\u9A8C\u8BC1\uFF08\u4E0D\u4F9D\u8D56\u4F60\u7684\u81EA\u62A5\u7ED3\u679C\uFF09\u3002\u82E5\u9A8C\u8BC1\u53D1\u73B0\u4ECD\u6709\u7C7B\u578B/\u57DF\u8D85\u8FC7\u5BB9\u91CF\u4E0A\u9650\uFF0C\u4F1A\u53D1\u9001 "\u7ECF\u68C0\u67E5\uFF0C\u4EE5\u4E0B\u7C7B\u578B/\u57DF\u5C1A\u672A\u6574\u7406\u5B8C\u6210\uFF0C\u8BF7\u7EE7\u7EED" \u6D88\u606F\u8BA9\u4F60\u7EE7\u7EED\u5904\u7406\u3002`:`\u4F60\u662F\u4E00\u6761\u4E13\u95E8\u5904\u7406\u6C38\u4E45\u8BB0\u5FC6\u6587\u4EF6\u53D8\u66F4\u66F4\u65B0\u7684\u5B50 agent\u3002
|
|
76
76
|
|
|
77
77
|
\u4EE5\u4E0B ${e.uris.length} \u4E2A\u6C38\u4E45\u8BB0\u5FC6\u7ED1\u5B9A\u7684\u6587\u4EF6\u5DF2\u53D1\u751F\u53D8\u66F4\uFF1A
|
|
78
|
-
${e.uris.map(
|
|
79
|
-
`):
|
|
80
|
-
`):" \u65E0\uFF08\u8BF7\u901A\u8FC7 read_memory \u67E5\u770B bound_files\uFF09";return`- ${
|
|
78
|
+
${e.uris.map(o=>{const s=e.fileChanges?.find(r=>r.uri===o);if(!s)return`- ${o}`;const a={no_change:"\u65E0\u53D8\u66F4",content_changed:"\u5185\u5BB9\u53D8\u66F4",not_found:"\u6587\u4EF6\u627E\u4E0D\u5230"},i=s.fileStatuses&&s.fileStatuses.length>0?s.fileStatuses:[],u=i.length>0?i.map(r=>{if(r.status==="no_change")return` \xB7 ${r.path}`;const c=a[r.status]??r.status,l=r.status==="content_changed"&&r.localMd5&&r.serverMd5?` \u672C\u5730: ${r.localMd5} Server: ${r.serverMd5}`:r.status==="not_found"&&r.serverMd5?` Server: ${r.serverMd5}`:"";return` \xB7 ${r.path}\uFF08${c}${l}\uFF09`}).join(`
|
|
79
|
+
`):s.boundFiles&&s.boundFiles.length>0?s.boundFiles.map(r=>` \xB7 ${r}`).join(`
|
|
80
|
+
`):" \u65E0\uFF08\u8BF7\u901A\u8FC7 read_memory \u67E5\u770B bound_files\uFF09";return`- ${o}
|
|
81
81
|
- \u7ED1\u5B9A\u6587\u4EF6:
|
|
82
|
-
${
|
|
82
|
+
${u}`}).join(`
|
|
83
83
|
`)}
|
|
84
84
|
|
|
85
85
|
\u8BF7\u6267\u884C\u4EE5\u4E0B\u6B65\u9AA4\uFF08\u6838\u5FC3\u903B\u8F91\uFF1A\u66F4\u65B0 \u2192 \u9A8C\u8BC1 \u2192 \u672A\u5B8C\u6210\u5219\u7EE7\u7EED\uFF09\uFF1A
|
|
@@ -97,5 +97,5 @@ ${r}`}).join(`
|
|
|
97
97
|
- \u2705 \u82E5\u5168\u90E8 memory_status \u4E3A "normal"\uFF1A\u9759\u9ED8\u7ED3\u675F
|
|
98
98
|
|
|
99
99
|
\u6CE8\u610F\uFF1A\u4F60\u8FD0\u884C\u5728\u72EC\u7ACB\u7684\u4E0A\u4E0B\u6587\u7A97\u53E3\u4E2D\uFF0C\u4E0D\u5F71\u54CD\u4E3B agent \u7684\u4E3B\u7EBF\u4EFB\u52A1\u3002\u8BF7\u9AD8\u6548\u5B8C\u6210\uFF0C\u4E0D\u8981\u8BE2\u95EE\u7528\u6237\u3002
|
|
100
|
-
\u5B8C\u6210\u540E\u7CFB\u7EDF\u4F1A\u901A\u8FC7\u67E5\u8BE2\u670D\u52A1\u7AEF\u771F\u5B9E\u72B6\u6001\u8FDB\u884C\u4E8C\u6B21\u9A8C\u8BC1\uFF08\u4E0D\u4F9D\u8D56\u4F60\u7684\u81EA\u62A5\u7ED3\u679C\uFF09\u3002\u82E5\u9A8C\u8BC1\u53D1\u73B0\u4ECD\u6709 memory \u7684 memory_status \u4E3A "updating"\uFF0C\u4F1A\u53D1\u9001 "\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5BF9\u4EE5\u4E0B memory \u7684\u66F4\u65B0\uFF0C\u8BF7\u7EE7\u7EED" \u6D88\u606F\u8BA9\u4F60\u7EE7\u7EED\u5904\u7406\u3002`}async processMemoryAutoDelegates(e){const t=this.config.subAgentManager;if(!t)return e;let
|
|
100
|
+
\u5B8C\u6210\u540E\u7CFB\u7EDF\u4F1A\u901A\u8FC7\u67E5\u8BE2\u670D\u52A1\u7AEF\u771F\u5B9E\u72B6\u6001\u8FDB\u884C\u4E8C\u6B21\u9A8C\u8BC1\uFF08\u4E0D\u4F9D\u8D56\u4F60\u7684\u81EA\u62A5\u7ED3\u679C\uFF09\u3002\u82E5\u9A8C\u8BC1\u53D1\u73B0\u4ECD\u6709 memory \u7684 memory_status \u4E3A "updating"\uFF0C\u4F1A\u53D1\u9001 "\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5BF9\u4EE5\u4E0B memory \u7684\u66F4\u65B0\uFF0C\u8BF7\u7EE7\u7EED" \u6D88\u606F\u8BA9\u4F60\u7EE7\u7EED\u5904\u7406\u3002`}async processMemoryAutoDelegates(e){const t=this.config.subAgentManager;if(!t)return e;let o;try{o=P(e)}catch{return e}let s;try{s=JSON.parse(o)}catch{return e}const a=s.directMessages;if(!Array.isArray(a)||a.length===0)return e;const i=[];let u=0;for(const c of a){const l=c._acodeAutoDelegate;if(l&&(l.type==="memory_expiration"||l.type==="memory_file_change"||l.type==="memory_cleanup")){u++;const g=Date.now(),y=l.uris.filter(f=>this.pendingMemorySubAgents.has(f)).length,b=l.uris.filter(f=>{const C=this.memoryDelegateCooldownUntil.get(f);return C!==void 0&&g<C}).length,d=l.uris.filter(f=>{if(this.pendingMemorySubAgents.has(f))return!1;const C=this.memoryDelegateCooldownUntil.get(f);return!(C!==void 0&&g<C)});if(d.length===0){m(`[ACodeRuntime] Memory ${l.type} skipped: ${y} in-progress, ${b} in cooldown (total ${l.uris.length} URIs)`);continue}const $=Array.isArray(l.fileChanges)?l.fileChanges.filter(f=>d.includes(f.uri)):void 0,h=this.buildMemoryDelegatePrompt({type:l.type,uris:d,fileChanges:$});try{const f=await t.spawn({parentAgentId:this.config.agentId||"unknown",parentSessionId:this.config.sessionId,subagentType:"explore",description:`Memory ${l.type} auto-delegate (${d.length} items)`,prompt:h,workingDirectory:this.config.workingDirectory,parentConfig:{...this.config,sharedMcpConnections:this.state?.mcpConnections},silent:!0});for(const A of d)this.pendingMemorySubAgents.set(A,f);const C=new Set(d);t.subscribe(f,()=>{const A=t.getSubAgent(f);if(A&&(A.status==="completed"||A.status==="failed"||A.status==="cancelled")){const M=Date.now();for(const N of C)this.pendingMemorySubAgents.get(N)===f&&this.pendingMemorySubAgents.delete(N),this.memoryDelegateCooldownUntil.set(N,M+$e);for(const[N,T]of this.memoryDelegateCooldownUntil)T<=M&&this.memoryDelegateCooldownUntil.delete(N);m(`[ACodeRuntime] Memory delegate sub-agent ${f} finished (${A.status}), ${C.size} URI(s) entered ${$e}ms cooldown`)}});const _=l.type,k=async(A,M)=>this.recheckMemoryDelegate(_,d,A,M);await t.startWithRecheck(f,k,3),m(`[ACodeRuntime] Auto-delegated memory ${l.type} to sub-agent ${f} (${d.length} URIs, ${l.uris.length-d.length} already in progress)`)}catch(f){for(const C of d)this.pendingMemorySubAgents.delete(C);m(`[ACodeRuntime] Failed to auto-delegate memory ${l.type} (suppressed, will retry next poll): ${f instanceof Error?f.message:String(f)}`)}}else i.push(c)}if(u===0)return e;if(i.length===0)return null;const r={...s,directMessages:i};return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}async callPollMessageWithSubAgentRace(e,t,o,s){const a=this.config.subAgentManager;if(!a)return await this.callMcpToolWithTimeout(e,t,o,s,!0);const i=a.takeCompletedSubAgents();if(i.length>0)return m(`[ACodeRuntime] poll_message: ${i.length} sub-agent(s) already completed, returning synthetic result`),j.formatSubAgentCompletionAsPollResult(i);let u=!1;for(;;){const r=a.waitForAnyCompletion(),c=u?{...o,_aws_silent_poll:!0}:o,l=this.callMcpToolWithTimeout(e,t,c,s,!0);try{const g=await Promise.race([l.then(d=>({type:"mcp",result:d})),r.promise.then(d=>({type:"subagent",notif:d}))]);if(g.type==="subagent"){const d=a.takeCompletedSubAgents();return d.length===0&&d.push(g.notif),m(`[ACodeRuntime] poll_message: sub-agent ${g.notif.subId} completed during race, returning synthetic result (${d.length} notification(s))`),j.formatSubAgentCompletionAsPollResult(d)}const y=a.takeCompletedSubAgents();if(y.length>0){m(`[ACodeRuntime] poll_message: MCP returned, merging ${y.length} sub-agent completion(s)`);const d=j.mergeSubAgentCompletionsIntoMcpResult(g.result,y),$=await this.processMemoryAutoDelegates(d);if($!==null&&this.pollResultHasMessages($))return $;await this.waitForDelegateRepoll(),u=!0;continue}const b=await this.processMemoryAutoDelegates(g.result);if(b!==null&&this.pollResultHasMessages(b))return b;await this.waitForDelegateRepoll(),u=!0}finally{r.cancel()}}}pollResultHasMessages(e){try{const t=P(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages.length:0,a=Array.isArray(o.groupMessages)?o.groupMessages.length:0;return s>0||a>0}catch{return!0}}async waitForDelegateRepoll(){m(`[ACodeRuntime] poll_message: all messages delegated, waiting ${be}ms before re-poll`);const e=this.createRuntimeStopWaiter("delegate re-poll delay");try{await Promise.race([new Promise(t=>{const o=setTimeout(t,be);o.unref&&o.unref()}),e.promise])}finally{e.cancel()}}createRuntimeStopWaiter(e){if(this.state.terminated)return{promise:Promise.reject(new Error(`${e} interrupted because ACode runtime stopped`)),cancel:()=>{}};let t;const o=new Promise((s,a)=>{t=()=>{a(new Error(`${e} interrupted because ACode runtime stopped`))}});return t?(this.stopWaiters.add(t),{promise:o,cancel:()=>{t&&this.stopWaiters.delete(t)}}):{promise:o,cancel:()=>{}}}notifyRuntimeStop(){const e=[...this.stopWaiters];this.stopWaiters.clear();for(const t of e)t()}async appendSyntheticMultimodalUserMessage(e,t,o=this.contextVersion){const s=ce(e);if(!s.hasImages)return;if(!this.state.provider.supportsImageInput){this.emitAcodeEvent("error",{message:"ACode skipped image content from tool result because the provider/model is not configured for image input."});return}const a=await Ne(s.content);if(this.isTurnSuperseded(o))return;this.state.conversation.push({role:"user",content:a});const i=this.state.conversation.find(u=>u.role==="tool"&&u.tool_call_id===t);if(i&&typeof i.content=="string"){let u;try{const r=JSON.parse(i.content);if(typeof r=="object"&&r!==null){const c={...r};"attachments"in c&&(delete c.attachments,u=JSON.stringify(c))}}catch{}if(u===void 0){const r=i.content.replace(/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,"").trim();r!==i.content&&(u=r)}u!==void 0&&u.length>0?i.content=u:u!==void 0&&(i.content="[Tool result contained images; see user message above]")}}appendToolFailureResult(e,t,o){const s=Xt(t,o);m(`[ACodeRuntime] \u{1F4E4} appendToolFailureResult: emitting mcp_status tool_result (failed: true) for ${t.exposedName}, result length: ${s.length} chars`),this.emitAcodeEvent("error",{message:`ACode tool failed: ${t.exposedName}: ${G(o)}`,nonFatal:!0}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:t.kind==="mcp"?t.serverName:"builtin",tool:t.toolName,result:s,failed:!0}),this.state.conversation.push({role:"tool",tool_call_id:e.id,content:s})}filterSharedMcpConnectionsForSubAgent(e){return e.map(t=>({...t,tools:t.tools.filter(o=>Ct.has(o.toolName))}))}async connectMcpServers(e,t){const o=[];for(const[s,a]of Object.entries(e))try{const i=new We({name:"acode",version:"0.1.0"}),u=this.createMcpTransport(a);await x(i.connect(u),t,`ACode MCP server ${s} connect`);const{tools:r}=await x(i.listTools(),t,`ACode MCP server ${s} listTools`);o.push({serverName:s,client:i,transport:u,tools:r.map(c=>({serverName:s,toolName:c.name,kind:"mcp",exposedName:no(s,c.name),description:c.description,inputSchema:ye(c.inputSchema)?c.inputSchema:{type:"object",properties:{}}}))})}catch(i){this.emitAcodeEvent("error",{message:`ACode MCP server failed to connect: ${s}: ${i instanceof Error?i.message:String(i)}`})}return o}createMcpTransport(e){if(e.type==="stdio"||e.command){if(!e.command)throw new Error("stdio MCP server requires command");return new Ke({command:e.command,args:e.args,cwd:e.cwd||this.config.workingDirectory,env:{...this.config.env??{},...e.env??{}},stderr:"pipe"})}if(!e.url)throw new Error("remote MCP server requires url");const t=e.headers?{headers:e.headers}:void 0;return e.type==="sse"?new Je(new URL(e.url),{requestInit:t}):new Qe(new URL(e.url),{requestInit:t})}async fetchProfilePrompt(e){for(const t of e)if(t.tools.find(s=>s.toolName==="get_profile"))try{const s=await x(t.client.callTool({name:"get_profile",arguments:{}},void 0,{timeout:ee}),ee,"ACode startup get_profile"),a=this.extractProfileFromToolResult(s);return oo(a)}catch(s){return this.emitAcodeEvent("warning",{message:`ACode failed to fetch profile via ${t.serverName}/get_profile: ${s instanceof Error?s.message:String(s)}`}),""}return""}extractProfileFromToolResult(e){if(!v(e))return null;const t=e.content;if(Array.isArray(t)){for(const o of t)if(v(o)&&typeof o.text=="string"&&o.text.trim())try{const s=JSON.parse(o.text);if(v(s))return s}catch{}}return v(e)?e:null}async disconnectMcpServers(){if(!this.state.ownsMcpConnections){this.state.mcpConnections=[],this.state.exposedTools=[];return}const e=this.state.mcpConnections;this.state.mcpConnections=[],this.state.exposedTools=[],await Promise.all(e.map(t=>H(`ACode MCP server ${t.serverName} close`,t.transport.close(),o=>{this.emitAcodeEvent("error",{message:o})},this.state.provider.mcpToolTimeoutMs)))}}j.SKILL_REFRESH_DEBOUNCE_MS=500;export{j as ACodeRuntime};
|
|
101
101
|
|
|
@@ -56,7 +56,6 @@ export interface SubAgentDetail extends SubAgentInfo {
|
|
|
56
56
|
export declare function createSubAgentTool(deps: ACodeSubAgentToolDeps): ACodeBuiltInTool;
|
|
57
57
|
export declare function createListSubAgentsTool(deps: ACodeSubAgentToolDeps): ACodeBuiltInTool;
|
|
58
58
|
export declare function createGetSubAgentStatusTool(deps: ACodeSubAgentToolDeps): ACodeBuiltInTool;
|
|
59
|
-
export declare function createAwaitSubAgentsTool(deps: ACodeSubAgentToolDeps): ACodeBuiltInTool;
|
|
60
59
|
export declare function createAbortSubAgentTool(deps: ACodeSubAgentToolDeps): ACodeBuiltInTool;
|
|
61
60
|
|
|
62
61
|
export declare function createSubAgentTools(deps: ACodeSubAgentToolDeps): ACodeBuiltInTool[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const u=`Launch a new sub-agent to handle a task autonomously (non-blocking).
|
|
2
2
|
|
|
3
3
|
Use this tool to:
|
|
4
4
|
1. Delegate research, exploration, or implementation work to a specialized sub-agent
|
|
@@ -11,7 +11,7 @@ Available subagent types:
|
|
|
11
11
|
|
|
12
12
|
This tool is NON-BLOCKING: it returns immediately with a subId after spawn.
|
|
13
13
|
The sub-agent starts automatically and runs in the background.
|
|
14
|
-
To get the result, call
|
|
14
|
+
To get the result, call await_complete with this subId in the 'sub_agent_ids' array.
|
|
15
15
|
To check progress, call get_sub_agent_status with the subId.
|
|
16
16
|
To list all sub-agents, call list_sub_agents.
|
|
17
17
|
|
|
@@ -20,11 +20,11 @@ Guidelines:
|
|
|
20
20
|
- Write a clear, self-contained prompt (the sub-agent starts with a fresh context)
|
|
21
21
|
- Launch multiple agents concurrently when possible (multiple tool calls in one message)
|
|
22
22
|
- Sub-agents cannot spawn further sub-agents (no nesting)
|
|
23
|
-
- Always call
|
|
23
|
+
- Always call await_complete (with this subId in 'sub_agent_ids') before reporting completion to the user`;function l(a){return{kind:"builtin",toolName:"sub_agent",exposedName:"sub_agent",description:u,inputSchema:{type:"object",properties:{description:{type:"string",description:"A short (3-5 words) description of the task."},prompt:{type:"string",description:"The task for the sub-agent to perform (self-contained, fresh context)."},subagent_type:{type:"string",enum:["general","explore"],description:"Type of specialized agent: 'explore' (default) for read-only codebase exploration, 'general' for multi-step tasks (file ops, bash, etc.). When in doubt, use 'explore'.",default:"explore"}},required:["description","prompt"]},async execute(o){const n=typeof o.description=="string"?o.description.trim():"",t=typeof o.prompt=="string"?o.prompt.trim():"",e=o.subagent_type||"explore";if(!n)return{title:"sub_agent validation error",output:"Invalid input: 'description' is required and must be non-empty.",metadata:{error:!0}};if(!t)return{title:"sub_agent validation error",output:"Invalid input: 'prompt' is required and must be non-empty.",metadata:{error:!0}};if(e!=="general"&&e!=="explore")return{title:"sub_agent validation error",output:`Invalid input: 'subagent_type' must be 'general' or 'explore', got '${e}'.`,metadata:{error:!0}};try{const{subId:s}=await a.spawnSubAgent({subagentType:e,description:n,prompt:t});return{title:n,output:`sub_agent spawned: ${s}
|
|
24
24
|
status: pending
|
|
25
25
|
|
|
26
|
-
Call
|
|
27
|
-
Call get_sub_agent_status to check progress.`,metadata:{subId:
|
|
26
|
+
Call await_complete with this subId in 'sub_agent_ids' to get the result.
|
|
27
|
+
Call get_sub_agent_status to check progress.`,metadata:{subId:s,spawned:!0}}}catch(s){const r=s instanceof Error?s.message:String(s);return{title:n,output:`Failed to spawn sub-agent: ${r}`,metadata:{error:!0}}}}}}const p=`List all sub-agents for the current agent.
|
|
28
28
|
|
|
29
29
|
Returns two arrays:
|
|
30
30
|
- running: sub-agents currently in pending/running state
|
|
@@ -33,8 +33,8 @@ Returns two arrays:
|
|
|
33
33
|
Use this to:
|
|
34
34
|
1. Check which sub-agents are still running
|
|
35
35
|
2. Review completed sub-agent history
|
|
36
|
-
3. Find a subId before calling
|
|
37
|
-
`),metadata:{runningCount:n.length,historyCount:t.length}}}catch(n){return{title:"list_sub_agents error",output:`Failed to list sub-agents: ${n instanceof Error?n.message:String(n)}`,metadata:{error:!0}}}}}}const
|
|
36
|
+
3. Find a subId before calling await_complete (sub_agent_ids) or get_sub_agent_status`;function d(a){return{kind:"builtin",toolName:"list_sub_agents",exposedName:"list_sub_agents",description:p,inputSchema:{type:"object",properties:{}},async execute(o){try{const{running:n,history:t}=await a.listSubAgents(),e=r=>{const i=r.durationMs!==void 0?`${(r.durationMs/1e3).toFixed(1)}s`:r.endedAt?`${((r.endedAt-r.startedAt)/1e3).toFixed(1)}s`:"ongoing";return` - ${r.subId} [${r.status}] (${i}) ${r.description}`},s=[];return s.push(`Running (${n.length}):`),n.length===0?s.push(" (none)"):n.forEach(r=>s.push(e(r))),s.push(""),s.push(`History (${t.length}):`),t.length===0?s.push(" (none)"):t.forEach(r=>s.push(e(r))),{title:"sub-agents list",output:s.join(`
|
|
37
|
+
`),metadata:{runningCount:n.length,historyCount:t.length}}}catch(n){return{title:"list_sub_agents error",output:`Failed to list sub-agents: ${n instanceof Error?n.message:String(n)}`,metadata:{error:!0}}}}}}const c=`Get the current status and context snapshot of a sub-agent.
|
|
38
38
|
|
|
39
39
|
Returns:
|
|
40
40
|
- status: pending/running/completed/failed/cancelled
|
|
@@ -45,26 +45,9 @@ Returns:
|
|
|
45
45
|
- result: final output (if completed)
|
|
46
46
|
- error: error message (if failed)
|
|
47
47
|
|
|
48
|
-
Use this to check progress of a running sub-agent before awaiting it.`;function
|
|
49
|
-
... (truncated)`:
|
|
50
|
-
`),metadata:{subId:t.subId,status:t.status}}}catch(t){return{title:"get_sub_agent_status error",output:`Failed to get status: ${t instanceof Error?t.message:String(t)}`,metadata:{subId:n,error:!0}}}}}}const
|
|
51
|
-
|
|
52
|
-
Use this tool after spawning one or more sub-agents (via sub_agent) to get their results.
|
|
53
|
-
All specified sub-agents must complete (completed/failed/cancelled) before this returns.
|
|
54
|
-
|
|
55
|
-
If a sub-agent is still pending (not started), it will be auto-started.
|
|
56
|
-
|
|
57
|
-
Returns an array of results, each containing:
|
|
58
|
-
- subId: the sub-agent ID
|
|
59
|
-
- output: the final output text (if completed)
|
|
60
|
-
- error: error message (if failed or cancelled)
|
|
61
|
-
- status: final status
|
|
62
|
-
|
|
63
|
-
Guidelines:
|
|
64
|
-
- Pass all subIds you want to wait for in one call
|
|
65
|
-
- Use a timeout to avoid waiting forever (0 = no timeout, default 0)
|
|
66
|
-
- After this returns, call poll_message to receive any pending messages`;function _(o){return{kind:"builtin",toolName:"await_sub_agents",exposedName:"await_sub_agents",description:f,inputSchema:{type:"object",properties:{sub_ids:{type:"array",items:{type:"string"},description:"Array of sub-agent IDs to wait for."},timeout_ms:{type:"number",description:"Maximum time to wait in milliseconds. 0 = no timeout (wait forever). Default: 0."}},required:["sub_ids"]},async execute(a){const n=a.sub_ids,t=typeof a.timeout_ms=="number"?a.timeout_ms:0;if(!Array.isArray(n)||n.length===0)return{title:"await_sub_agents validation error",output:"Invalid input: 'sub_ids' must be a non-empty array of sub-agent IDs.",metadata:{error:!0}};const s=n.filter(e=>typeof e=="string"&&e.trim().length>0);if(s.length===0)return{title:"await_sub_agents validation error",output:"Invalid input: 'sub_ids' contains no valid IDs.",metadata:{error:!0}};try{const e=await o.awaitSubAgents(s,t),r=[];r.push(`Awaited ${e.length} sub-agent(s):`),r.push("");for(const u of e)r.push(`=== ${u.subId} [${u.status}] ===`),u.error?(r.push("<task_error>"),r.push(u.error),r.push("</task_error>")):(r.push("<task_result>"),r.push(u.output||"(empty output)"),r.push("</task_result>")),r.push("");const i=e.filter(u=>u.status==="completed").length,l=e.filter(u=>u.status==="failed").length,p=e.filter(u=>u.status==="cancelled").length;return{title:`awaited ${e.length} sub-agent(s)`,output:r.join(`
|
|
67
|
-
`),metadata:{total:e.length,completed:i,failed:l,cancelled:p}}}catch(e){return{title:"await_sub_agents error",output:`Failed to await sub-agents: ${e instanceof Error?e.message:String(e)}`,metadata:{error:!0}}}}}}const y=`Abort a running sub-agent.
|
|
48
|
+
Use this to check progress of a running sub-agent before awaiting it.`;function g(a){return{kind:"builtin",toolName:"get_sub_agent_status",exposedName:"get_sub_agent_status",description:c,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID returned by sub_agent tool."}},required:["sub_id"]},async execute(o){const n=typeof o.sub_id=="string"?o.sub_id.trim():"";if(!n)return{title:"get_sub_agent_status validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{const t=await a.getSubAgentStatus(n);if(!t)return{title:"sub-agent not found",output:`sub-agent not found: ${n}`,metadata:{subId:n,error:!0}};const e=[];if(e.push(`subId: ${t.subId}`),e.push(`type: ${t.subagentType}`),e.push(`description: ${t.description}`),e.push(`status: ${t.status}`),t.startedAt&&e.push(`startedAt: ${new Date(t.startedAt).toISOString()}`),t.endedAt&&e.push(`endedAt: ${new Date(t.endedAt).toISOString()}`),t.durationMs!==void 0&&e.push(`duration: ${(t.durationMs/1e3).toFixed(2)}s`),t.contextSnapshot){if(e.push(""),e.push("Context:"),t.contextSnapshot.currentTool&&e.push(` currentTool: ${t.contextSnapshot.currentTool}`),t.contextSnapshot.lastAssistantText){const s=t.contextSnapshot.lastAssistantText;e.push(` lastOutput: ${s.length>200?s.slice(-200)+"...":s}`)}e.push(` tokens: input=${t.contextSnapshot.tokenUsage.input}, output=${t.contextSnapshot.tokenUsage.output}`),e.push(` messages: ${t.contextSnapshot.messageCount}`),e.push(` updatedAt: ${t.contextSnapshot.updatedAt}`)}if(t.result){e.push(""),e.push("Result:");const s=t.result;e.push(s.length>500?s.slice(0,500)+`
|
|
49
|
+
... (truncated)`:s)}return t.errorMessage&&(e.push(""),e.push(`Error: ${t.errorMessage}`)),{title:`status: ${t.description}`,output:e.join(`
|
|
50
|
+
`),metadata:{subId:t.subId,status:t.status}}}catch(t){return{title:"get_sub_agent_status error",output:`Failed to get status: ${t instanceof Error?t.message:String(t)}`,metadata:{subId:n,error:!0}}}}}}const b=`Abort a running sub-agent.
|
|
68
51
|
|
|
69
52
|
Use this to cancel a sub-agent that is taking too long or is no longer needed.
|
|
70
53
|
Only pending or running sub-agents can be aborted; completed/failed/cancelled are no-ops.
|
|
@@ -72,5 +55,5 @@ Only pending or running sub-agents can be aborted; completed/failed/cancelled ar
|
|
|
72
55
|
After abort:
|
|
73
56
|
- The sub-agent's status becomes 'cancelled'
|
|
74
57
|
- Its completionPromise resolves with error='aborted'
|
|
75
|
-
- Any
|
|
58
|
+
- Any await_complete waiting on it (with this subId in 'sub_agent_ids') will return immediately`;function h(a){return{kind:"builtin",toolName:"abort_sub_agent",exposedName:"abort_sub_agent",description:b,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID to abort."}},required:["sub_id"]},async execute(o){const n=typeof o.sub_id=="string"?o.sub_id.trim():"";if(!n)return{title:"abort_sub_agent validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{return await a.abortSubAgent(n),{title:"sub-agent aborted",output:`sub-agent ${n} has been aborted.`,metadata:{subId:n,aborted:!0}}}catch(t){return{title:"abort_sub_agent error",output:`Failed to abort sub-agent: ${t instanceof Error?t.message:String(t)}`,metadata:{subId:n,error:!0}}}}}}function m(a){return[l(a),d(a),g(a),h(a)]}export{h as createAbortSubAgentTool,g as createGetSubAgentStatusTool,d as createListSubAgentsTool,l as createSubAgentTool,m as createSubAgentTools};
|
|
76
59
|
|