aws-runtime-bridge 1.9.130 → 1.9.131

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.
Files changed (35) hide show
  1. package/dist/browser/browser-frame-encode.d.ts +16 -0
  2. package/dist/browser/browser-frame-encode.js +2 -0
  3. package/dist/browser/browser-pool.js +1 -1
  4. package/dist/browser/screencast-differ.d.ts +35 -0
  5. package/dist/browser/screencast-differ.js +2 -0
  6. package/dist/browser/screencast-manager.d.ts +32 -0
  7. package/dist/browser/screencast-manager.js +1 -1
  8. package/dist/browser/types.d.ts +48 -1
  9. package/dist/browser/types.js +1 -1
  10. package/dist/browser/ws-server.d.ts +1 -1
  11. package/dist/browser/ws-server.js +1 -1
  12. package/dist/routes/background-tasks.js +7 -1
  13. package/dist/routes/instance-tool-status.d.ts +4 -0
  14. package/dist/routes/instance-tool-status.js +2 -0
  15. package/dist/routes/instance.d.ts +0 -2
  16. package/dist/routes/instance.js +1 -1
  17. package/dist/services/acode-bg-manager.d.ts +36 -0
  18. package/dist/services/acode-bg-manager.js +2 -0
  19. package/dist/services/browser-session-manager.js +1 -1
  20. package/package/acode/dist/await-complete-tool.js +4 -4
  21. package/package/acode/dist/background-command-manager.d.ts +39 -0
  22. package/package/acode/dist/background-command-manager.js +5 -5
  23. package/package/acode/dist/background-command-tools.js +1 -1
  24. package/package/acode/dist/built-in-file-tools.js +2 -2
  25. package/package/acode/dist/builtins/shellCommandResult.d.ts +3 -0
  26. package/package/acode/dist/builtins/shellCommandResult.js +1 -1
  27. package/package/acode/dist/builtins/shellCommandRunner.d.ts +2 -0
  28. package/package/acode/dist/builtins/shellCommandRunner.js +1 -1
  29. package/package/acode/dist/runtime.js +7 -7
  30. package/package/acode/dist/sub-agent-tools.js +30 -26
  31. package/package/acode/dist/sub-agent-types.d.ts +1 -1
  32. package/package/acode/dist/tool-allocation.d.ts +4 -4
  33. package/package/acode/dist/tool-allocation.js +1 -1
  34. package/package/aws-client-agent-mcp/dist/mcp-server.js +1 -1
  35. package/package.json +3 -3
@@ -1,21 +1,21 @@
1
- import{EventEmitter as Ve}from"node:events";import G from"node:fs";import Xe from"node:os";import te from"node:path";import{Client as Ze}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as et}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as tt}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as ot}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{ToolListChangedNotificationSchema as nt}from"@modelcontextprotocol/sdk/types.js";import{createBuiltInFileTools as st}from"./built-in-file-tools.js";import{ASK_USER_QUESTION_TOOL_NAME as it,createAskUserQuestionTool as rt}from"./ask-user-question-tool.js";import{createSkillTool as at}from"./skill-tool.js";import{createTodoWriteTool as lt,createTodoReadTool as ct}from"./todo-tool.js";import{createSubAgentTools as ut}from"./sub-agent-tools.js";import{createAwaitCompleteTool as mt}from"./await-complete-tool.js";import{cleanupAcodeCmdDist as dt}from"./builtins/commandArtifacts.js";import{backgroundCommandManager as Q}from"./background-command-manager.js";import{createTerminalTool as ht}from"./terminal-tool.js";import{loadAcodeCommands as pt}from"./commands/commandLoader.js";import{ACodeCommandRegistry as ye}from"./commands/commandRegistry.js";import{calculateCompactionThreshold as ft,COMPACTION_LLM_PROMPT_TEMPLATE as gt,conversationSizeKB as Y,estimateConversationTokens as oe,performCompaction as Ae,pruneToolOutputs as Tt,summarizeConversation as Ce}from"./compaction.js";import{loadAcodeConfig as yt,loadAcodeSkillGroup as At}from"./config.js";import{ACodeHookBus as Ct,findDeniedHookResult as ce}from"./hooks/hookBus.js";import{isMcpPollingToolName as _t,isMcpBlockingToolName as bt,getSemanticToolName as _e}from"./mcpToolNames.js";import{runtimeMeetingDebugLog as D}from"./meeting-debug-log.js";import{buildToolCatalog as be,matchesToolAllocation as we,mergeAllocatableTools as ne,PRESET_EXPLORE as $e,rebindDefaultAgentId as ke,resolveToolAllocation as wt,SUB_AGENT_ALLOWED_MCP_TOOLS as $t}from"./tool-allocation.js";function kt(n){if(typeof n!="object"||n===null)return!1;const e=n;return e.kind==="builtin"&&typeof e.toolName=="string"&&typeof e.exposedName=="string"&&typeof e.description=="string"&&typeof e.execute=="function"&&typeof e.inputSchema=="object"&&e.inputSchema!==null}function St(n){return n.type==="text"?{type:"text",text:n.text}:{type:"image_url",image_url:{url:n.image_url.url}}}function Mt(n){return{id:n.id,type:"function",function:{name:n.function.name,arguments:n.function.arguments}}}function Rt(n){const e={role:n.role,content:Array.isArray(n.content)?n.content.map(St):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(Mt)),e}function ue(n){return n.map(Rt)}function vt(n,e){const t=U(n.prompt_cache_hit_tokens),o=U(n.prompt_cache_miss_tokens);if(t!==void 0||o!==void 0)return{cacheHitTokens:t??0,cacheMissTokens:o??0};const s=U(n.cache_read_input_tokens),l=U(n.cache_creation_input_tokens);if(s!==void 0||l!==void 0){const c=U(n.input_tokens)??0;return{cacheHitTokens:s??0,cacheMissTokens:(l??0)+c}}const i=U(n.cache_hit_tokens),a=U(n.cache_miss_tokens);if(i!==void 0||a!==void 0)return{cacheHitTokens:i??0,cacheMissTokens:a??0};const r=U(n.prompt_tokens_details?.cached_tokens);if(r!==void 0){const c=e!==void 0?Math.max(0,e-r):0;return{cacheHitTokens:r,cacheMissTokens:c}}}function U(n){const e=typeof n=="number"?n:typeof n=="string"&&n.trim()?Number(n):NaN;if(!(!Number.isFinite(e)||e<0))return e}function xt(n,e){if(!n)return e;const t=o=>{const s=e[o],l=n[o];return o==="prompt_tokens_details"?{...l,...s}:s??l};return{prompt_tokens:t("prompt_tokens"),completion_tokens:t("completion_tokens"),input_tokens:t("input_tokens"),output_tokens:t("output_tokens"),prompt_cache_hit_tokens:t("prompt_cache_hit_tokens"),prompt_cache_miss_tokens:t("prompt_cache_miss_tokens"),cache_read_input_tokens:t("cache_read_input_tokens"),cache_creation_input_tokens:t("cache_creation_input_tokens"),cache_hit_tokens:t("cache_hit_tokens"),cache_miss_tokens:t("cache_miss_tokens"),prompt_tokens_details:t("prompt_tokens_details")}}function Et(){return new Date().toISOString()}function x(n){return!!(n&&typeof n=="object"&&!Array.isArray(n))}function Se(n){return x(n)}function Me(n,e){return e.map(t=>({serverName:n,toolName:t.name,kind:"mcp",exposedName:Ao(n,t.name),description:t.description,inputSchema:Se(t.inputSchema)?t.inputSchema:{type:"object",properties:{}}}))}function I(n){return String(n??"").trim()||void 0}const Re=6e4,ve=30*6e4,xe=6e4,Ee=6e4,se=-1,Ne=se,Nt=1e3,It=3e4,ie=6e4,Ie=0,Pt=2147483647,Lt=10*6e4+2e3,Dt=1e4,re=5e3,Pe=10*60*1e3,Le=10*1024*1024,De=800*1024,ae=process.env.ACODE_COMPACTION_DEBUG==="1",Oe=ae?te.join(Xe.tmpdir(),"acode-compaction-debug.log"):"";function u(...n){ae&&console.log(...n)}const Ot=process.env.ACODE_TOKEN_DEBUG==="1";function W(...n){Ot&&console.log("[TokenDebug][Runtime]",...n)}const Ut=64e3;function me(n){const e=n.contextLimit&&n.contextLimit>0?n.contextLimit:Ut,t=n.maxOutput&&n.maxOutput>0?n.maxOutput:8192,o=n.inputLimit&&n.inputLimit>0?n.inputLimit:void 0,s=ft(e,t,o);return{contextLimit:e,maxOutput:t,inputLimit:o,threshold:s}}async function E(n,e,t,o){if(e<=0)return await n;let s;try{return await new Promise((l,i)=>{s=setTimeout(()=>{o?.(),i(new Error(`${t} timed out after ${e}ms`))},e),n.then(l,i)})}finally{s&&clearTimeout(s)}}async function V(n,e,t,o=Dt){try{await E(e,o,n)}catch(s){t(s instanceof Error?s.message:String(s))}}function J(n,e){if(n===0||n==="0")return 0;const t=typeof n=="number"?n:Number(n);return t===se?se:Number.isFinite(t)&&t>0?Math.floor(t):e}function X(n,e){const t=J(n,e);return t>0?t:e}const Ue=3;function de(n){return n?Math.ceil(n.length/Ue):0}function Bt(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 l=o;l.inputSchema&&(t+=JSON.stringify(l.inputSchema).length)}}return Math.ceil(t/Ue)}function Be(n){if(n.length===0)return 0;const e=JSON.stringify(Ke(n));return de(e)}async function qt(n){await new Promise(e=>setTimeout(e,n))}function Ft(n){return typeof n=="boolean"}function zt(n,e,t){if(Ft(t?.supportsImageInput))return t.supportsImageInput;const o=x(e)?e.models:void 0,s=x(o)?o[n]:void 0;if(!x(s))return!1;const l=s.modalities;return!x(l)||!Array.isArray(l.input)?!1:l.input.some(i=>String(i||"").trim().toLowerCase()==="image")}function he(n,e,t,o){if(n!==void 0)return n;if(!e)return;const s=e.models;if(x(s)){const l=s[t];if(x(l)){const i=l[o];if(i!==void 0)return i}}return e[o]}function jt(n,e){const t=e.provider?.default,o=t?.options,s=n.model||t?.model||e.model||"acode-default",l=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:l,systemPrompt:n.systemPrompt||e.systemPrompt,stream:o?.stream!==!1,requestTimeoutMs:X(o?.requestTimeoutMs??o?.timeoutMs,Re),requestTotalTimeoutMs:X(o?.requestTotalTimeoutMs,ve),requestRetryCount:J(o?.requestRetryCount,Ne),requestFirstByteTimeoutMs:X(o?.requestFirstByteTimeoutMs,xe),requestStreamIdleTimeoutMs:X(o?.requestStreamIdleTimeoutMs,Ee),mcpToolTimeoutMs:X(o?.mcpToolTimeoutMs,ie),mcpPollingToolTimeoutMs:J(o?.mcpPollingToolTimeoutMs,Ie),supportsImageInput:zt(s,t,o),contextLimit:J(he(o?.contextLimit,t,s,"contextLimit"),0)||void 0,inputLimit:J(he(o?.inputLimit,t,s,"inputLimit"),0)||void 0,maxOutput:J(he(o?.maxOutput,t,s,"maxOutput"),0)||void 0}}function z(n,e){const t=e.replace(/\s+/g," ").trim();t&&n.push({type:"text",text:t})}function Wt(n,e){const t=e.trim();return/^data:image\/[a-z0-9.+-]+;base64,/i.test(t)?t:`data:${n||"image/png"};base64,${t}`}function Jt(n){return/^data:image\/[a-z0-9.+-]+;base64,/i.test(n.trim())}function Ht(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 Kt(n){const e=await n.arrayBuffer();if(e.byteLength>Le)throw new Error(`ACode image is too large to inline: ${e.byteLength} bytes exceeds ${Le} bytes`);return Buffer.from(e).toString("base64")}async function Gt(n){const e=n.trim();if(Jt(e))return e;Ht(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 Kt(t)}`}function Qt(n){const e=I(n.base64Data??n.base64??n.data);return e?Wt(I(n.mediaType??n.mimeType)||"image/png",e):I(n.url??n.serverUrl)}function qe(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(l=>!!l).join(", ")}]`}function Yt(n){const e=/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,t=[];let o=!1,s=0,l=e.exec(n);for(;l!==null;){z(t,n.slice(s,l.index));const i=l[1],a=(l[2]||"").trim();if(i==="\u56FE\u7247"&&a)t.push({type:"image_url",image_url:{url:a}}),o=!0;else if(i==="\u6587\u4EF6"&&a){const[r="",c="",m="",p=""]=a.split("|").map(h=>h.trim());z(t,qe(r,c,m,p))}else z(t,l[0]);s=l.index+l[0].length,l=e.exec(n)}return t.length===0?{content:n,hasImages:!1}:(z(t,n.slice(s)),{content:t,hasImages:o})}function Vt(n,e){let t=!1;const o=[e.directMessages,e.groupMessages];for(const s of o)if(Array.isArray(s))for(const l of s){if(!x(l))continue;const i=I(l.content);if(!i)continue;const a=I(l.senderName);z(n,a?`Message from ${a}:`:"Message:");const r=pe(i);Array.isArray(r.content)?n.push(...r.content):z(n,r.content),t=t||r.hasImages}return t}function Xt(n){let e;try{e=JSON.parse(n)}catch{return}if(!x(e))return;const t=[];let o=Vt(t,e);const s=I(e.text)||"",l=Array.isArray(e.attachments)?e.attachments:[];z(t,s);for(const i of l){if(!x(i))continue;const a=i;if(String(a.type??a.kind??"").toLowerCase()==="image"){const m=Qt(a);m&&(t.push({type:"image_url",image_url:{url:m}}),o=!0);continue}const c=I(a.url??a.serverUrl)||"";z(t,qe(I(a.name)||"",c,I(a.mediaType??a.mimeType)||"",I(a.size)||""))}return t.length===0?{content:n,hasImages:!1}:{content:t,hasImages:o}}function pe(n){return Xt(n)??Yt(n)}async function Fe(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 Gt(t.image_url.url)}})}return e}function Zt(n){return typeof n=="string"?n:Array.isArray(n)?n.map(e=>e.type==="text"?e.text:"[Image]").join(" ").trim():""}function eo(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(l=>l.trim()).filter(Boolean),deny:[...t.deny??[],...s].map(l=>l.trim()).filter(Boolean)}}function to(n,e){return n==="*"?!0:n.endsWith("*")?e.startsWith(n.slice(0,-1)):n===e}function oo(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 ze(n,e){return oo(e).some(t=>to(n,t))}function je(n,e,t){if(e.length>0&&!e.some(o=>ze(o,n)))throw new Error(t)}function fe(n,e,t){if(e.mode!=="bypassPermissions"){if(e.deny.some(o=>ze(o,n)))throw new Error(`ACode tool denied by permission rule: ${n.exposedName}`);je(n,e.allow,`ACode tool is not in allowed permission rules: ${n.exposedName}`),je(n,t??[],`ACode slash command does not allow tool: ${n.exposedName}`)}}function no(n,e,t){try{return fe(n,e,t),!0}catch{return!1}}function le(n){const e=n.replace(/\/+$/g,"");return/\/chat\/completions$/i.test(e)?e:`${e}/chat/completions`}function so(n){try{const e=new URL(n);e.search="",e.hash="";const t=new URL(le(e.toString()));return`${t.origin}${t.pathname}`}catch{return le(n).replace(/([?&](?:api[_-]?key|token|authorization)=)[^&]+/gi,"$1[redacted]")}}function io(n){const e=[...n].reverse().find(o=>o.role==="user"),t=Zt(e?.content??null).trim();if(t)return t.length>300?`${t.slice(0,300)}...`:t}function We(n){try{const e=JSON.parse(n);return Se(e)?e:{}}catch{return{}}}function ro(n,e,t){if(new Set([it,"await_complete"]).has(n.toolName))return 0;if(n.toolName!=="Bash")return t;const s=e.timeout_ms??e.timeoutMs,l=typeof s=="number"?s:typeof s=="string"?Number(s):NaN;return!Number.isFinite(l)||l<=0?Math.max(t,Lt):Math.min(Math.floor(l),10*6e4)+2e3}function ao(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 O(n){if(!x(n))return String(n??"");const e=n.content;if(Array.isArray(e)){const t=e.map(o=>x(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 Z(n){return n instanceof Error?n.message:String(n)}function lo(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 co(n,e,t,o,s){let l=0;for(const a of n)l+=lo(a);if(l<=e)return 0;const i=await Ae(n,t,o,{llmSummarizer:s});return i.strategy!=="none"?i.prunedToolMessages+i.summarizedMessages:Ce(n,{llmSummarizer:s,contextLimit:t})}function Je(n){const e=Z(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 uo(n){const e=Z(n).toLowerCase();return Je(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 mo(n){if(typeof n!="object"||n===null)return!1;const e=Reflect.get(n,"code"),t=Z(n).toLowerCase();return e===-32001||t.includes("request timed out")}function ho(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 po(n,e){return JSON.stringify({ok:!1,tool:n.exposedName,error:{type:ho(e),message:Z(e)}})}function He(n){const e=JSON.stringify(n);return e.length>500?`${e.slice(0,500)}\u2026`:e}function fo(n){const e=[n?.reasoning_content,n?.reasoning_text,n?.reasoning];for(const t of e){if(typeof t=="string"&&t)return t;if(x(t)){const o=t.text??t.content;if(typeof o=="string"&&o)return o}}return""}function go(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(`
1
+ import{EventEmitter as Ye}from"node:events";import G from"node:fs";import Ve from"node:os";import te from"node:path";import{Client as Xe}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as Ze}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as et}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as tt}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{ToolListChangedNotificationSchema as ot}from"@modelcontextprotocol/sdk/types.js";import{createBuiltInFileTools as nt}from"./built-in-file-tools.js";import{ASK_USER_QUESTION_TOOL_NAME as st,createAskUserQuestionTool as it}from"./ask-user-question-tool.js";import{createSkillTool as rt}from"./skill-tool.js";import{createTodoWriteTool as at,createTodoReadTool as lt}from"./todo-tool.js";import{createSubAgentTools as ct}from"./sub-agent-tools.js";import{createAwaitCompleteTool as ut}from"./await-complete-tool.js";import{cleanupAcodeCmdDist as mt}from"./builtins/commandArtifacts.js";import{backgroundCommandManager as Q}from"./background-command-manager.js";import{createTerminalTool as dt}from"./terminal-tool.js";import{loadAcodeCommands as ht}from"./commands/commandLoader.js";import{ACodeCommandRegistry as ye}from"./commands/commandRegistry.js";import{calculateCompactionThreshold as pt,COMPACTION_LLM_PROMPT_TEMPLATE as ft,conversationSizeKB as Y,estimateConversationTokens as oe,performCompaction as Ae,pruneToolOutputs as gt,summarizeConversation as Ce}from"./compaction.js";import{loadAcodeConfig as Tt,loadAcodeSkillGroup as yt}from"./config.js";import{ACodeHookBus as At,findDeniedHookResult as ce}from"./hooks/hookBus.js";import{isMcpPollingToolName as Ct,isMcpBlockingToolName as _t,getSemanticToolName as _e}from"./mcpToolNames.js";import{runtimeMeetingDebugLog as D}from"./meeting-debug-log.js";import{buildToolCatalog as be,matchesToolAllocation as we,mergeAllocatableTools as ne,PRESET_EXPLORE as bt,rebindDefaultAgentId as $e,resolveToolAllocation as wt,SUB_AGENT_ALLOWED_MCP_TOOLS as $t}from"./tool-allocation.js";function kt(n){if(typeof n!="object"||n===null)return!1;const e=n;return e.kind==="builtin"&&typeof e.toolName=="string"&&typeof e.exposedName=="string"&&typeof e.description=="string"&&typeof e.execute=="function"&&typeof e.inputSchema=="object"&&e.inputSchema!==null}function St(n){return n.type==="text"?{type:"text",text:n.text}:{type:"image_url",image_url:{url:n.image_url.url}}}function Mt(n){return{id:n.id,type:"function",function:{name:n.function.name,arguments:n.function.arguments}}}function Rt(n){const e={role:n.role,content:Array.isArray(n.content)?n.content.map(St):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(Mt)),e}function ue(n){return n.map(Rt)}function vt(n,e){const t=U(n.prompt_cache_hit_tokens),o=U(n.prompt_cache_miss_tokens);if(t!==void 0||o!==void 0)return{cacheHitTokens:t??0,cacheMissTokens:o??0};const s=U(n.cache_read_input_tokens),l=U(n.cache_creation_input_tokens);if(s!==void 0||l!==void 0){const c=U(n.input_tokens)??0;return{cacheHitTokens:s??0,cacheMissTokens:(l??0)+c}}const i=U(n.cache_hit_tokens),a=U(n.cache_miss_tokens);if(i!==void 0||a!==void 0)return{cacheHitTokens:i??0,cacheMissTokens:a??0};const r=U(n.prompt_tokens_details?.cached_tokens);if(r!==void 0){const c=e!==void 0?Math.max(0,e-r):0;return{cacheHitTokens:r,cacheMissTokens:c}}}function U(n){const e=typeof n=="number"?n:typeof n=="string"&&n.trim()?Number(n):NaN;if(!(!Number.isFinite(e)||e<0))return e}function xt(n,e){if(!n)return e;const t=o=>{const s=e[o],l=n[o];return o==="prompt_tokens_details"?{...l,...s}:s??l};return{prompt_tokens:t("prompt_tokens"),completion_tokens:t("completion_tokens"),input_tokens:t("input_tokens"),output_tokens:t("output_tokens"),prompt_cache_hit_tokens:t("prompt_cache_hit_tokens"),prompt_cache_miss_tokens:t("prompt_cache_miss_tokens"),cache_read_input_tokens:t("cache_read_input_tokens"),cache_creation_input_tokens:t("cache_creation_input_tokens"),cache_hit_tokens:t("cache_hit_tokens"),cache_miss_tokens:t("cache_miss_tokens"),prompt_tokens_details:t("prompt_tokens_details")}}function Et(){return new Date().toISOString()}function x(n){return!!(n&&typeof n=="object"&&!Array.isArray(n))}function ke(n){return x(n)}function Se(n,e){return e.map(t=>({serverName:n,toolName:t.name,kind:"mcp",exposedName:Ao(n,t.name),description:t.description,inputSchema:ke(t.inputSchema)?t.inputSchema:{type:"object",properties:{}}}))}function I(n){return String(n??"").trim()||void 0}const Me=6e4,Re=30*6e4,ve=6e4,xe=6e4,se=-1,Ee=se,Nt=1e3,It=3e4,ie=6e4,Ne=0,Pt=2147483647,Lt=10*6e4+2e3,Dt=1e4,re=5e3,Ie=10*60*1e3,Pe=10*1024*1024,Le=800*1024,ae=process.env.ACODE_COMPACTION_DEBUG==="1",De=ae?te.join(Ve.tmpdir(),"acode-compaction-debug.log"):"";function u(...n){ae&&console.log(...n)}const Ot=process.env.ACODE_TOKEN_DEBUG==="1";function W(...n){Ot&&console.log("[TokenDebug][Runtime]",...n)}const Ut=64e3;function me(n){const e=n.contextLimit&&n.contextLimit>0?n.contextLimit:Ut,t=n.maxOutput&&n.maxOutput>0?n.maxOutput:8192,o=n.inputLimit&&n.inputLimit>0?n.inputLimit:void 0,s=pt(e,t,o);return{contextLimit:e,maxOutput:t,inputLimit:o,threshold:s}}async function E(n,e,t,o){if(e<=0)return await n;let s;try{return await new Promise((l,i)=>{s=setTimeout(()=>{o?.(),i(new Error(`${t} timed out after ${e}ms`))},e),n.then(l,i)})}finally{s&&clearTimeout(s)}}async function V(n,e,t,o=Dt){try{await E(e,o,n)}catch(s){t(s instanceof Error?s.message:String(s))}}function J(n,e){if(n===0||n==="0")return 0;const t=typeof n=="number"?n:Number(n);return t===se?se:Number.isFinite(t)&&t>0?Math.floor(t):e}function X(n,e){const t=J(n,e);return t>0?t:e}const Oe=3;function de(n){return n?Math.ceil(n.length/Oe):0}function Bt(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 l=o;l.inputSchema&&(t+=JSON.stringify(l.inputSchema).length)}}return Math.ceil(t/Oe)}function Ue(n){if(n.length===0)return 0;const e=JSON.stringify(He(n));return de(e)}async function qt(n){await new Promise(e=>setTimeout(e,n))}function Ft(n){return typeof n=="boolean"}function zt(n,e,t){if(Ft(t?.supportsImageInput))return t.supportsImageInput;const o=x(e)?e.models:void 0,s=x(o)?o[n]:void 0;if(!x(s))return!1;const l=s.modalities;return!x(l)||!Array.isArray(l.input)?!1:l.input.some(i=>String(i||"").trim().toLowerCase()==="image")}function he(n,e,t,o){if(n!==void 0)return n;if(!e)return;const s=e.models;if(x(s)){const l=s[t];if(x(l)){const i=l[o];if(i!==void 0)return i}}return e[o]}function jt(n,e){const t=e.provider?.default,o=t?.options,s=n.model||t?.model||e.model||"acode-default",l=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:l,systemPrompt:n.systemPrompt||e.systemPrompt,stream:o?.stream!==!1,requestTimeoutMs:X(o?.requestTimeoutMs??o?.timeoutMs,Me),requestTotalTimeoutMs:X(o?.requestTotalTimeoutMs,Re),requestRetryCount:J(o?.requestRetryCount,Ee),requestFirstByteTimeoutMs:X(o?.requestFirstByteTimeoutMs,ve),requestStreamIdleTimeoutMs:X(o?.requestStreamIdleTimeoutMs,xe),mcpToolTimeoutMs:X(o?.mcpToolTimeoutMs,ie),mcpPollingToolTimeoutMs:J(o?.mcpPollingToolTimeoutMs,Ne),supportsImageInput:zt(s,t,o),contextLimit:J(he(o?.contextLimit,t,s,"contextLimit"),0)||void 0,inputLimit:J(he(o?.inputLimit,t,s,"inputLimit"),0)||void 0,maxOutput:J(he(o?.maxOutput,t,s,"maxOutput"),0)||void 0}}function z(n,e){const t=e.replace(/\s+/g," ").trim();t&&n.push({type:"text",text:t})}function Wt(n,e){const t=e.trim();return/^data:image\/[a-z0-9.+-]+;base64,/i.test(t)?t:`data:${n||"image/png"};base64,${t}`}function Jt(n){return/^data:image\/[a-z0-9.+-]+;base64,/i.test(n.trim())}function Ht(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 Kt(n){const e=await n.arrayBuffer();if(e.byteLength>Pe)throw new Error(`ACode image is too large to inline: ${e.byteLength} bytes exceeds ${Pe} bytes`);return Buffer.from(e).toString("base64")}async function Gt(n){const e=n.trim();if(Jt(e))return e;Ht(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 Kt(t)}`}function Qt(n){const e=I(n.base64Data??n.base64??n.data);return e?Wt(I(n.mediaType??n.mimeType)||"image/png",e):I(n.url??n.serverUrl)}function Be(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(l=>!!l).join(", ")}]`}function Yt(n){const e=/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,t=[];let o=!1,s=0,l=e.exec(n);for(;l!==null;){z(t,n.slice(s,l.index));const i=l[1],a=(l[2]||"").trim();if(i==="\u56FE\u7247"&&a)t.push({type:"image_url",image_url:{url:a}}),o=!0;else if(i==="\u6587\u4EF6"&&a){const[r="",c="",m="",p=""]=a.split("|").map(h=>h.trim());z(t,Be(r,c,m,p))}else z(t,l[0]);s=l.index+l[0].length,l=e.exec(n)}return t.length===0?{content:n,hasImages:!1}:(z(t,n.slice(s)),{content:t,hasImages:o})}function Vt(n,e){let t=!1;const o=[e.directMessages,e.groupMessages];for(const s of o)if(Array.isArray(s))for(const l of s){if(!x(l))continue;const i=I(l.content);if(!i)continue;const a=I(l.senderName);z(n,a?`Message from ${a}:`:"Message:");const r=pe(i);Array.isArray(r.content)?n.push(...r.content):z(n,r.content),t=t||r.hasImages}return t}function Xt(n){let e;try{e=JSON.parse(n)}catch{return}if(!x(e))return;const t=[];let o=Vt(t,e);const s=I(e.text)||"",l=Array.isArray(e.attachments)?e.attachments:[];z(t,s);for(const i of l){if(!x(i))continue;const a=i;if(String(a.type??a.kind??"").toLowerCase()==="image"){const m=Qt(a);m&&(t.push({type:"image_url",image_url:{url:m}}),o=!0);continue}const c=I(a.url??a.serverUrl)||"";z(t,Be(I(a.name)||"",c,I(a.mediaType??a.mimeType)||"",I(a.size)||""))}return t.length===0?{content:n,hasImages:!1}:{content:t,hasImages:o}}function pe(n){return Xt(n)??Yt(n)}async function qe(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 Gt(t.image_url.url)}})}return e}function Zt(n){return typeof n=="string"?n:Array.isArray(n)?n.map(e=>e.type==="text"?e.text:"[Image]").join(" ").trim():""}function eo(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(l=>l.trim()).filter(Boolean),deny:[...t.deny??[],...s].map(l=>l.trim()).filter(Boolean)}}function to(n,e){return n==="*"?!0:n.endsWith("*")?e.startsWith(n.slice(0,-1)):n===e}function oo(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 Fe(n,e){return oo(e).some(t=>to(n,t))}function ze(n,e,t){if(e.length>0&&!e.some(o=>Fe(o,n)))throw new Error(t)}function fe(n,e,t){if(e.mode!=="bypassPermissions"){if(e.deny.some(o=>Fe(o,n)))throw new Error(`ACode tool denied by permission rule: ${n.exposedName}`);ze(n,e.allow,`ACode tool is not in allowed permission rules: ${n.exposedName}`),ze(n,t??[],`ACode slash command does not allow tool: ${n.exposedName}`)}}function no(n,e,t){try{return fe(n,e,t),!0}catch{return!1}}function le(n){const e=n.replace(/\/+$/g,"");return/\/chat\/completions$/i.test(e)?e:`${e}/chat/completions`}function so(n){try{const e=new URL(n);e.search="",e.hash="";const t=new URL(le(e.toString()));return`${t.origin}${t.pathname}`}catch{return le(n).replace(/([?&](?:api[_-]?key|token|authorization)=)[^&]+/gi,"$1[redacted]")}}function io(n){const e=[...n].reverse().find(o=>o.role==="user"),t=Zt(e?.content??null).trim();if(t)return t.length>300?`${t.slice(0,300)}...`:t}function je(n){try{const e=JSON.parse(n);return ke(e)?e:{}}catch{return{}}}function ro(n,e,t){if(new Set([st,"await_complete"]).has(n.toolName))return 0;if(n.toolName!=="Bash")return t;const s=e.timeout_ms??e.timeoutMs,l=typeof s=="number"?s:typeof s=="string"?Number(s):NaN;return!Number.isFinite(l)||l<=0?Math.max(t,Lt):Math.min(Math.floor(l),10*6e4)+2e3}function ao(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 O(n){if(!x(n))return String(n??"");const e=n.content;if(Array.isArray(e)){const t=e.map(o=>x(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 Z(n){return n instanceof Error?n.message:String(n)}function lo(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 co(n,e,t,o,s){let l=0;for(const a of n)l+=lo(a);if(l<=e)return 0;const i=await Ae(n,t,o,{llmSummarizer:s});return i.strategy!=="none"?i.prunedToolMessages+i.summarizedMessages:Ce(n,{llmSummarizer:s,contextLimit:t})}function We(n){const e=Z(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 uo(n){const e=Z(n).toLowerCase();return We(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 mo(n){if(typeof n!="object"||n===null)return!1;const e=Reflect.get(n,"code"),t=Z(n).toLowerCase();return e===-32001||t.includes("request timed out")}function ho(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 po(n,e){return JSON.stringify({ok:!1,tool:n.exposedName,error:{type:ho(e),message:Z(e)}})}function Je(n){const e=JSON.stringify(n);return e.length>500?`${e.slice(0,500)}\u2026`:e}function fo(n){const e=[n?.reasoning_content,n?.reasoning_text,n?.reasoning];for(const t of e){if(typeof t=="string"&&t)return t;if(x(t)){const o=t.text??t.content;if(typeof o=="string"&&o)return o}}return""}function go(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
3
  `)}function yo(n){if(!n||typeof n!="object")return"";const e=n,t=[],o=e.displayName,s=e.roleName,l=e.instanceName,i=e.projectId,a=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 l=="string"&&l.trim()&&t.push(`Instance: ${l.trim()}`),typeof i=="string"&&i.trim()&&t.push(`Project: ${i.trim()}`),typeof a=="string"&&a.trim()&&t.push(`Workspace: ${a.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 Ke(n){return n.map(e=>({type:"function",function:{name:e.exposedName,description:e.description||e.toolName,parameters:e.inputSchema}}))}function Ao(n,e){return`${n}__${e}`.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,64)||"mcp_tool"}function Co(n){const e={"Content-Type":"application/json"};return n.apiKey&&(e.Authorization=`Bearer ${n.apiKey}`),e}function _o(n){return Object.fromEntries(Object.entries(n).map(([e,t])=>[e,bo(e)?wo(t):t]))}function bo(n){const e=n.trim().toLowerCase();return e==="authorization"||e==="api-key"||e==="x-api-key"||e==="openai-api-key"}function wo(n){return n.trim().toLowerCase().startsWith("bearer ")?"Bearer ***":"***"}function $o(n){return n.split(/\r?\n/).filter(e=>e.startsWith("data:")).map(e=>e.slice(5).trim()).filter(Boolean)}function ko(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 So(n){return[...n.entries()].sort(([e],[t])=>e-t).map(([,e])=>e).filter(e=>e.function.name.trim().length>0)}function Mo(){const n=process.env.ACODE_ABORT_FORCE_SETTLE_GRACE_MS;if(n===void 0||n.trim()==="")return 6e4;const e=Number(n.trim());return Number.isFinite(e)&&e>=0?Math.floor(e):6e4}class H extends Ve{constructor(e){super(),this.config=e,this.initialConversation=[],this.state={started:!1,terminated:!1,configMcpCount:0,skills:[],provider:{model:"acode-default",stream:!1,requestTimeoutMs:Re,requestTotalTimeoutMs:ve,requestRetryCount:Ne,requestFirstByteTimeoutMs:xe,requestStreamIdleTimeoutMs:Ee,mcpToolTimeoutMs:ie,mcpPollingToolTimeoutMs:Ie,supportsImageInput:!1},permissions:{mode:"default",allow:[],deny:[]},mcpConnections:[],ownsMcpConnections:!0,exposedTools:[],commands:[],commandRegistry:new ye([]),conversation:[],accumulatedInputTokens:0,accumulatedOutputTokens:0,accumulatedCacheHitTokens:0,accumulatedCacheMissTokens:0},this.abortController=null,this.exposedToolsInitialized=!1,this.pendingMemorySubAgents=new Map,this.memoryDelegateCooldownUntil=new Map,this.submitQueue=Promise.resolve(),this.activeTurnToken=null,this.forceSettleWaiters=new Map,this.abortForceSettleTimer=null,this.activeTurn=!1,this.forceMessagePending=!1,this.abortRequested=!1,this.toolSettleSlot=null,this.toolSettleSeq=0,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 Ct({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:Et(),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 yt(this.config.configPath);this.emitAcodeEvent("startup_phase",{phase:"loading_skills"});const{skills:t,skillGroups:o,watchedDirs:s}=await this.loadAllSkills(),l=jt(this.config,e);u(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 resolveProviderConfig \u7ED3\u679C: config.model=${this.config.model??"(undefined)"}, resolvedModel=${l.model}, baseURL=${l.baseURL??"(none)"}, apiKey=${l.apiKey?"[set]":"(none)"}, configPath=${this.config.configPath??"(none)"}`);const i=eo(this.config,e),a=this.config.sharedMcpConnections?this.filterSharedMcpConnectionsForSubAgent(this.config.sharedMcpConnections):await this.connectMcpServers(e.mcpServers??{},l.mcpToolTimeoutMs),r=!this.config.sharedMcpConnections;this.emitAcodeEvent("startup_phase",{phase:"fetching_profile"});const c=await this.fetchProfilePrompt(a),m=this.config.agentId||"unknown";dt(m),Q.reconcileOrphans(m);const p=st(this.config.workingDirectory,m,this.config.onFileChange,{manager:Q,emitCompleted:g=>{this.emitAcodeEvent("background_command_completed",g)}}),h=rt(this.buildAskUserQuestionDeps(),()=>this.contextVersion),k=at(t);this.skillTool=k;const T=lt(m),w=ct(m),C=this.config.subAgentManager?ut(this.buildSubAgentToolDeps(this.config.subAgentManager)):[],d=mt(this.buildAwaitCompleteDeps()),y=this.config.terminalManager?ht(m,{terminalManager:this.config.terminalManager}):null,S=[...p,h,k,T,w,...C,d,...y?[y]:[],...a.flatMap(g=>g.tools),...ke(this.config.extraBuiltInTools??[],this.config.agentId??"")];if(this.config.subAgentAllowedTools&&this.config.subAgentAllowedTools.length>0){const g=ke(this.config.subAgentSuiteTools??[],this.config.agentId??""),q=ne(S,g);S.length=0,S.push(...q)}let A=S;const M=this.config.subAgentAllowedTools;M&&M.length>0&&(A=A.filter(g=>we(g,M)));const $=this.resolveCommandDirs(e);this.emitAcodeEvent("startup_phase",{phase:"loading_commands"});const R=await pt($),f=new ye(R),_=go(t),v=To(R),N=[l.systemPrompt,_,v].map(g=>g?.trim()).filter(g=>!!g).join(`
4
+ `)}function He(n){return n.map(e=>({type:"function",function:{name:e.exposedName,description:e.description||e.toolName,parameters:e.inputSchema}}))}function Ao(n,e){return`${n}__${e}`.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,64)||"mcp_tool"}function Co(n){const e={"Content-Type":"application/json"};return n.apiKey&&(e.Authorization=`Bearer ${n.apiKey}`),e}function _o(n){return Object.fromEntries(Object.entries(n).map(([e,t])=>[e,bo(e)?wo(t):t]))}function bo(n){const e=n.trim().toLowerCase();return e==="authorization"||e==="api-key"||e==="x-api-key"||e==="openai-api-key"}function wo(n){return n.trim().toLowerCase().startsWith("bearer ")?"Bearer ***":"***"}function $o(n){return n.split(/\r?\n/).filter(e=>e.startsWith("data:")).map(e=>e.slice(5).trim()).filter(Boolean)}function ko(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 So(n){return[...n.entries()].sort(([e],[t])=>e-t).map(([,e])=>e).filter(e=>e.function.name.trim().length>0)}function Mo(){const n=process.env.ACODE_ABORT_FORCE_SETTLE_GRACE_MS;if(n===void 0||n.trim()==="")return 6e4;const e=Number(n.trim());return Number.isFinite(e)&&e>=0?Math.floor(e):6e4}class H extends Ye{constructor(e){super(),this.config=e,this.initialConversation=[],this.state={started:!1,terminated:!1,configMcpCount:0,skills:[],provider:{model:"acode-default",stream:!1,requestTimeoutMs:Me,requestTotalTimeoutMs:Re,requestRetryCount:Ee,requestFirstByteTimeoutMs:ve,requestStreamIdleTimeoutMs:xe,mcpToolTimeoutMs:ie,mcpPollingToolTimeoutMs:Ne,supportsImageInput:!1},permissions:{mode:"default",allow:[],deny:[]},mcpConnections:[],ownsMcpConnections:!0,exposedTools:[],commands:[],commandRegistry:new ye([]),conversation:[],accumulatedInputTokens:0,accumulatedOutputTokens:0,accumulatedCacheHitTokens:0,accumulatedCacheMissTokens:0},this.abortController=null,this.exposedToolsInitialized=!1,this.pendingMemorySubAgents=new Map,this.memoryDelegateCooldownUntil=new Map,this.submitQueue=Promise.resolve(),this.activeTurnToken=null,this.forceSettleWaiters=new Map,this.abortForceSettleTimer=null,this.activeTurn=!1,this.forceMessagePending=!1,this.abortRequested=!1,this.toolSettleSlot=null,this.toolSettleSeq=0,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 At({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:Et(),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 Tt(this.config.configPath);this.emitAcodeEvent("startup_phase",{phase:"loading_skills"});const{skills:t,skillGroups:o,watchedDirs:s}=await this.loadAllSkills(),l=jt(this.config,e);u(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 resolveProviderConfig \u7ED3\u679C: config.model=${this.config.model??"(undefined)"}, resolvedModel=${l.model}, baseURL=${l.baseURL??"(none)"}, apiKey=${l.apiKey?"[set]":"(none)"}, configPath=${this.config.configPath??"(none)"}`);const i=eo(this.config,e),a=this.config.sharedMcpConnections?this.filterSharedMcpConnectionsForSubAgent(this.config.sharedMcpConnections):await this.connectMcpServers(e.mcpServers??{},l.mcpToolTimeoutMs),r=!this.config.sharedMcpConnections;this.emitAcodeEvent("startup_phase",{phase:"fetching_profile"});const c=await this.fetchProfilePrompt(a),m=this.config.agentId||"unknown";mt(m),Q.reconcileOrphans(m);const p=nt(this.config.workingDirectory,m,this.config.onFileChange,{manager:Q,emitCompleted:g=>{this.emitAcodeEvent("background_command_completed",g)}}),h=it(this.buildAskUserQuestionDeps(),()=>this.contextVersion),k=rt(t);this.skillTool=k;const T=at(m),w=lt(m),C=this.config.subAgentManager?ct(this.buildSubAgentToolDeps(this.config.subAgentManager)):[],d=ut(this.buildAwaitCompleteDeps()),y=this.config.terminalManager?dt(m,{terminalManager:this.config.terminalManager}):null,S=[...p,h,k,T,w,...C,d,...y?[y]:[],...a.flatMap(g=>g.tools),...$e(this.config.extraBuiltInTools??[],this.config.agentId??"")];if(this.config.subAgentAllowedTools&&this.config.subAgentAllowedTools.length>0){const g=$e(this.config.subAgentSuiteTools??[],this.config.agentId??""),q=ne(S,g);S.length=0,S.push(...q)}let A=S;const M=this.config.subAgentAllowedTools;M&&M.length>0&&(A=A.filter(g=>we(g,M)));const $=this.resolveCommandDirs(e);this.emitAcodeEvent("startup_phase",{phase:"loading_commands"});const R=await ht($),f=new ye(R),_=go(t),v=To(R),N=[l.systemPrompt,_,v].map(g=>g?.trim()).filter(g=>!!g).join(`
5
5
 
6
6
  `),b=g=>g?.trim()?[{role:"system",content:g.trim()}]:[],P=[this.config.rolePrompt,c].map(g=>g?.trim()).filter(g=>!!g).join(`
7
7
 
8
8
  `),B=[...b(this.config.globalPrompt),...b(P),...b(this.config.memory),...N?[{role:"system",content:N}]:[]],F=B.map(g=>g.content).filter(Boolean).join(`
9
9
 
10
- `);this.initialConversation=ue(B),this.state={started:!0,terminated:!1,configMcpCount:Object.keys(e.mcpServers??{}).length,skills:t,provider:l,permissions:i,mcpConnections:a,ownsMcpConnections:r,exposedTools:A,commands:R,commandRegistry:f,conversation:ue(B),accumulatedInputTokens:0,accumulatedOutputTokens:0,accumulatedCacheHitTokens:0,accumulatedCacheMissTokens:0},this.exposedToolsInitialized=!0,this.emitAcodeEvent("startup_phase",{phase:"session_start_hook"}),await this.hookBus.dispatch("SessionStart",{workingDirectory:this.config.workingDirectory,model:l.model,commandCount:R.length});const L=me(l);this.emitAcodeEvent("session_started",{workingDirectory:this.config.workingDirectory,model:l.model,commandCount:R.length,estimatedContextTokens:Bt(F,A),contextLimit:L.contextLimit,maxOutput:L.maxOutput,...L.inputLimit!==void 0?{inputLimit:L.inputLimit}:{},compactionThreshold:L.threshold}),this.emitAcodeEvent("mcp_status",{configPath:this.config.configPath,installedCount:this.state.configMcpCount,servers:Object.keys(e.mcpServers??{}),connectedCount:a.length,builtInToolCount:p.length,toolCount:A.length,permissionMode:i.mode,allowedToolRules:i.allow,deniedToolRules:i.deny,tools:A.map(g=>({name:g.exposedName,source:g.kind==="mcp"?`${g.serverName}.${g.toolName}`:`builtin.${g.toolName}`,description:g.description||""}))}),this.emitAcodeEvent("skill_status",{skillsDir:this.config.skillsDir,installedCount:t.length,skills:t.map(g=>({name:g.name,description:g.description,directory:g.directory})),skillGroups:o.map(g=>({dir:g.dir,exists:g.exists,skills:g.skills.map(q=>({name:q.name,description:q.description,directory:q.directory}))}))}),this.emitAcodeEvent("command_status",{action:"commands_loaded",installedCommandCount:R.length,commandDirs:$,commands:R.map(g=>({name:g.name,description:g.description}))}),this.config.initialPrompt&&await this.submit(this.config.initialPrompt),this.startCompactionDebugLog(),this.startSkillWatchers(s)}async loadAllSkills(){const e=this.config.skillsDir??"",t=te.join(this.config.workingDirectory,".acode","skills"),o=te.join(this.config.workingDirectory,".agentswork","skills"),s=new Set,l=[],i=[];for(const c of[e,t,o]){if(!c)continue;const m=te.resolve(c);if(!s.has(m)){s.add(m),l.push(await At(c));try{await G.promises.access(m),i.push(m)}catch{}}}const a=new Map;for(const c of l)for(const m of c.skills)a.set(m.name,m);return{skills:[...a.values()],skillGroups:l,watchedDirs:i}}startSkillWatchers(e){for(const t of e){let o=null;try{o=G.watch(t,{recursive:!0},()=>{this.scheduleSkillRefresh()})}catch{try{o=G.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()},H.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}))}))}),u(`[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(!ae||this.compactionDebugTimer)return;const e=this.state.provider,{contextLimit:t,maxOutput:o,inputLimit:s,threshold:l}=me(e);this.compactionDebugTimer=setInterval(()=>{try{const i=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,a=oe(this.state.conversation)+Be(this.state.exposedTools),r=Math.max(i,a),c=Y(this.state.conversation),m=this.state.started&&!this.state.terminated,p=[`[${new Date().toISOString()}]`,`started=${this.state.started}`,`terminated=${this.state.terminated}`,`activeTurn=${this.activeTurn}`,`conversationSize=${this.state.conversation.length}msgs`,`sizeKB=${c}KB`,`estimation=${a} tokens`,`actualInput=${this.state.accumulatedInputTokens}`,`actualOutput=${this.state.accumulatedOutputTokens}`,`actualUsed=${i}`,`contextLimit=${t}`,`inputLimit=${s??"n/a"}`,`maxOutput=${o}`,`triggerThreshold=${l}`,`remainingToTrigger=${Math.max(0,l-i)}`,`isRunning=${m}`,`shouldCompact=${m?r>=l:!1}`,"---"].join(" | ");G.promises.appendFile(Oe,p+`
11
- `,"utf-8").catch(()=>{})}catch{}},5e3)}stopCompactionDebugLog(){this.compactionDebugTimer&&(clearInterval(this.compactionDebugTimer),this.compactionDebugTimer=null)}async submit(e){const t=this.contextVersion;u(`[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(()=>(u(`[ACodeRuntime] \u25B6\uFE0F executeSubmit dequeued: contextVersion=${t}`),this.executeSubmitGuarded(e,t)));return this.submitQueue=o.catch(()=>{u("[ACodeRuntime] \u{1F4EC} submit() queued item rejected (catch swallowed)")}),u("[ACodeRuntime] \u{1F4EC} submit() returning queued promise"),o}executeSubmitGuarded(e,t){const o={};this.activeTurnToken=o;const s=this.executeSubmit(e,t),l=new Promise(i=>{this.forceSettleWaiters.set(o,i)});return s.finally(()=>{this.forceSettleWaiters.delete(o),this.activeTurnToken===o&&(this.abortForceSettleTimer&&(clearTimeout(this.abortForceSettleTimer),this.abortForceSettleTimer=null),this.activeTurnToken=null)}).catch(()=>{}),Promise.race([s,l])}armAbortForceSettle(){if(!this.activeTurn||!this.activeTurnToken)return;const e=this.activeTurnToken;this.abortForceSettleTimer&&clearTimeout(this.abortForceSettleTimer);const t=Mo();this.abortForceSettleTimer=setTimeout(()=>{this.abortForceSettleTimer=null,this.activeTurn&&this.activeTurnToken===e&&this.forceSettleActiveTurn(`turn still unsettled ${t}ms after abort()`)},t),typeof this.abortForceSettleTimer.unref=="function"&&this.abortForceSettleTimer.unref()}forceSettleActiveTurn(e){const t=this.activeTurnToken;console.error(`[ACodeRuntime] \u{1F6A8} FORCE SETTLE: active turn ignored abort() (${e}). Force-settling to unblock submitQueue; late executeSubmit continuation will be superseded.`),this.contextVersion+=1,this.activeTurn=!1,this.abortRequested=!1,this.abortController=null,this.rejectAllQuestionWaiters("aborted"),this.cancelPendingAwaitedSubAgents(),this.cancelPendingAwaitedBgTasks(),this.notifyRuntimeStop(),this.emitAcodeEvent("error",{message:`ACode turn force-settled: ${e}`}),this.emitAcodeEvent("turn_complete",{failed:!0});const o=t?this.forceSettleWaiters.get(t):void 0;t&&this.forceSettleWaiters.delete(t),this.activeTurnToken=null,o?.()}notifyForceMessage(){this.forceMessagePending=!0,u("[ACodeRuntime] \u{1F514} Force message pending flag set")}addBuiltInTools(e){if(!this.state||!this.exposedToolsInitialized||!Array.isArray(e))return 0;const t=new Set(this.state.exposedTools.map(s=>s.exposedName)),o=[];for(const s of e)kt(s)&&(t.has(s.exposedName)||(t.add(s.exposedName),o.push(s)));return o.length===0?0:(this.state.exposedTools=[...this.state.exposedTools,...o],this.emitExposedToolsStatus(),o.length)}removeBuiltInToolsByPrefix(e){if(!this.state||!this.exposedToolsInitialized||!e)return 0;const t=this.state.exposedTools.length;this.state.exposedTools=this.state.exposedTools.filter(s=>!s.exposedName.startsWith(e));const o=t-this.state.exposedTools.length;return o>0&&this.emitExposedToolsStatus(),o}emitExposedToolsStatus(){this.emitAcodeEvent("mcp_status",{servers:this.state.mcpConnections.map(e=>e.serverName),connectedCount:this.state.mcpConnections.length,toolCount:this.state.exposedTools.length,tools:this.state.exposedTools.map(e=>({name:e.exposedName,source:e.kind==="mcp"?`${e.serverName}.${e.toolName}`:`builtin.${e.toolName}`,description:e.description||""}))})}async injectForceMessage(){if(!this.forceMessagePending)return!1;this.forceMessagePending=!1;const e=this.state.mcpConnections.find(t=>t.tools.some(o=>o.toolName==="get_message"));if(!e)return u("[ACodeRuntime] injectForceMessage: no connection with get_message found"),!1;try{const t=await E(e.client.callTool({name:"get_message",arguments:{_aws_force_inject:!0}},void 0,{timeout:1e4}),1e4,"injectForceMessage get_message"),o=O(t);let s=[];try{const r=JSON.parse(o);Array.isArray(r?.directMessages)&&(s=r.directMessages.filter(c=>c?.force===!0))}catch{return!1}if(s.length===0)return!1;const l=JSON.stringify({directMessages:s,groupMessages:[]}),i=`forced_get_msg_${Date.now()}`,a=`${e.serverName}__get_message`;return this.state.conversation.push({role:"assistant",content:null,tool_calls:[{id:i,type:"function",function:{name:a,arguments:"{}"}}]}),this.state.conversation.push({role:"tool",tool_call_id:i,content:l}),u(`[ACodeRuntime] injectForceMessage: injected ${s.length} force message(s) into conversation`),!0}catch(t){return u(`[ACodeRuntime] injectForceMessage failed: ${t}`),!1}}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=ue(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(u("[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"),u("[ACodeRuntime] \u25B6\uFE0F executeSubmit STARTED"),u(`[ACodeRuntime] Message: <redacted, length=${e.length}>`),u(`[ACodeRuntime] \u{1F522} Context version: ${t}`),u("[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=this.activeTurnToken,l=e.trim();let i=!1;try{u("[ACodeRuntime] \u{1F50D} Dispatching UserPromptSubmit hook...");const a=Date.now(),r=await this.hookBus.dispatch("UserPromptSubmit",{prompt:l}),c=Date.now()-a;if(u(`[ACodeRuntime] \u2705 UserPromptSubmit hook completed in ${c}ms, results: ${r.length}`),this.isTurnSuperseded(t)){u("[ACodeRuntime] \u26A0\uFE0F Turn superseded after hook, aborting");return}const m=ce(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}),i=!0,u("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (failed=true) due to hook deny");return}u("[ACodeRuntime] \u{1F50D} Expanding command if any...");const p=this.state.commandRegistry.expand(l),h=p?.prompt.trim()||l,k=p?.command.allowedTools;if(p&&(u(`[ACodeRuntime] \u{1F4CB} Slash command detected: ${p.command.name}`),this.emitAcodeEvent("command_status",{action:"slash_command",command:p.command.name,arguments:p.argumentsText,sourcePath:p.command.sourcePath})),!this.state.provider.baseURL||!this.state.provider.apiKey){u("[ACodeRuntime] \u26A0\uFE0F No provider configured, using fallback response");const A=ao(h,this.state);this.emitAcodeEvent("assistant_delta",{text:A}),this.emitAcodeEvent("turn_complete",{usage:{inputTokens:h.length,outputTokens:A.length}}),i=!0,u("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (fallback mode)");return}u("[ACodeRuntime] \u{1F4CE} Parsing attachment message...");const T=pe(h);if(T.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.");u("[ACodeRuntime] \u{1F5BC}\uFE0F Materializing image content if any...");const w=await Fe(T.content);if(this.isTurnSuperseded(t)){u("[ACodeRuntime] \uFE0F Turn superseded after materializing content, aborting");return}u("[ACodeRuntime] \u{1F4AC} Adding user message to conversation"),this.state.conversation.push({role:"user",content:w}),u(`[ACodeRuntime] Conversation size: ${this.state.conversation.length} messages`),u("[ACodeRuntime] Starting runModelTurn...");const C=Date.now(),d=await this.runModelTurn(k,t),y=Date.now()-C;if(u(`[ACodeRuntime] \u2705 runModelTurn completed in ${y}ms`),u(`[ACodeRuntime] \u{1F4DD} Result: text=${d.text?d.text.slice(0,80)+(d.text.length>80?"...":""):"(empty)"}, finishReason=${d.finishReason||"(none)"}`),this.isTurnSuperseded(t)){u("[ACodeRuntime] \uFE0F Turn superseded after runModelTurn, aborting");return}d.text&&!this.state.provider.stream&&(u("[ACodeRuntime] \u{1F4E4} Emitting assistant_delta (non-streaming mode)"),this.emitAcodeEvent("assistant_delta",{text:d.text})),u("[ACodeRuntime] \u{1F4E4} Emitting turn_complete..."),this.emitAcodeEvent("turn_complete",{usage:d.usage??{inputTokens:h.length,outputTokens:d.totalOutputTextLength??d.text.length},...d.responseBody?{responseBody:d.responseBody}:{},...d.finishReason?{finishReason:d.finishReason}:{}}),W(`turn_complete emitted: usage=${JSON.stringify(d.usage??{inputTokens:h.length,outputTokens:d.totalOutputTextLength??d.text.length})} (providerUsage=${d.usage?"real":"FALLBACK-text-length"}) textLength=${d.text.length} totalOutputTextLength=${d.totalOutputTextLength}`),u(`[ACodeRuntime] \u{1F4B0} Current context usage: input=${this.state.accumulatedInputTokens}, output=${this.state.accumulatedOutputTokens}`+(d.usage?"":" (estimated, no provider usage)")),i=!0;const S=Date.now()-o;u("[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"),u(`[ACodeRuntime] \u2705 executeSubmit COMPLETED in ${S}ms`),u("[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(a){const r=Date.now()-o;if(console.error(`[ACodeRuntime] \u274C executeSubmit FAILED after ${r}ms:`,a instanceof Error?a.message:String(a)),console.error("[ACodeRuntime] \u{1F50D} Error stack:",a instanceof Error?a.stack:"(no stack)"),this.isTurnSuperseded(t)){u("[ACodeRuntime] \uFE0F Turn superseded in error handler, skipping recovery");return}if(this.abortRequested){u("[ACodeRuntime] \u26A0\uFE0F Abort requested, emitting aborted turn_complete"),this.emitAcodeEvent("turn_complete",{aborted:!0}),i=!0;return}u("[ACodeRuntime] Emitting error and failed turn_complete..."),this.emitAcodeEvent("error",{message:a instanceof Error?a.message:String(a)}),this.emitAcodeEvent("turn_complete",{failed:!0}),i=!0}finally{const a=Date.now()-o;u(`[ACodeRuntime] \u{1F51A} executeSubmit finally block entered after ${a}ms`),u(`[ACodeRuntime] \u{1F50D} turnCompleted=${i}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, contextVersion=${t}, currentContextVersion=${this.contextVersion}`),this.activeTurnToken===s&&(this.activeTurn=!1,this.abortRequested=!1),!i&&!this.isTurnSuperseded(t)&&(console.error(`[ACodeRuntime] \u{1F6A8} CRITICAL: executeSubmit finally block reached without turn_complete event! Duration: ${a}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}),u("[ACodeRuntime] Emergency turn_complete (failed=true) emitted"))}}async abort(){const e=this.abortController!==null,t=this.activeTurn;this.abortRequested=this.activeTurn,this.abortController?(u(`[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(),this.armAbortForceSettle()}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})})}}async buildAllocatableToolList(){const e=this.state?.exposedTools??[],t=this.config.subAgentSuiteTools??[];let o=[];if(this.config.subAgentSuiteToolProvider)try{o=await this.config.subAgentSuiteToolProvider([])}catch{o=[]}return ne(e,ne(t,o))}buildSubAgentToolDeps(e){const t=this.config.agentId??"unknown",o=this.config.sessionId,s=this.config.workingDirectory,l=this.config;return{spawnSubAgent:async i=>{let a=this.config.subAgentSuiteTools;if(i.allowedTools&&i.allowedTools.length>0&&this.config.subAgentSuiteToolProvider)try{const c=await this.config.subAgentSuiteToolProvider(i.allowedTools);c.length>0&&(a=a?ne(a,c):c)}catch{}const r=await e.spawn({parentAgentId:t,parentSessionId:o,subagentType:i.subagentType,description:i.description,prompt:i.prompt,...i.allowedTools&&i.allowedTools.length>0?{allowedTools:i.allowedTools}:{},workingDirectory:s,parentConfig:{...l,sharedMcpConnections:this.state?.mcpConnections,...a&&a.length>0?{subAgentSuiteTools:a}:{}}});return await e.start(r),{subId:r}},listSubAgentToolCatalog:async()=>be(await this.buildAllocatableToolList()),listSubAgents:async()=>{const i=e.listByParent(t),a=[],r=[];for(const c of i){const m={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"?a.push(m):r.push(m)}return r.sort((c,m)=>(m.endedAt??0)-(c.endedAt??0)),{running:a,history:r}},getSubAgentStatus:async i=>{const a=e.getSubAgent(i);return a?{subId:a.subId,subagentType:a.subagentType,description:a.description,status:a.status,startedAt:a.startedAt,endedAt:a.endedAt,durationMs:a.durationMs,prompt:a.prompt,result:a.result,errorMessage:a.errorMessage,contextSnapshot:a.contextSnapshot}:null},awaitSubAgents:async(i,a)=>{const r=new Set;for(const c of i)this.pendingAwaitedSubIds.add(c),r.add(c);try{return await e.awaitCompletion(i,a)}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 l of o)this.pendingAwaitedSubIds.add(l);try{return this.buildSubAgentToolDeps(t).awaitSubAgents(o,s)}finally{for(const l of o)this.pendingAwaitedSubIds.delete(l)}}:null,awaitBgCommands:(o,s)=>{for(const l of o)this.pendingAwaitedBgTaskIds.add(l);try{return Q.awaitCompletion(e,o,s)}finally{for(const l of o)this.pendingAwaitedBgTaskIds.delete(l)}}}}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);u(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited sub-agent(s): ${t.join(", ")}`);for(const o of t)e.abort(o).catch(s=>{u(`[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);u(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited background command(s): ${t.join(", ")}`),Q.interruptAwaits(e,t)}detachCurrentToolExecution(){const e=this.toolSettleSlot;return!e||!e.settlable||e.settled?!1:(e.settled=!0,e.resolveSettle?.(),u(`[ACodeRuntime] \u{1F680} detachCurrentToolExecution: settling tool ${e.toolName} (toolCallId=${e.toolCallId}) to background`),!0)}beginToolSettle(e,t,o){const s=e.toolName==="Bash",l=++this.toolSettleSeq;let i;const a=s?new Promise(r=>{i=r}):void 0;return this.toolSettleSlot={seq:l,toolName:e.toolName,toolCallId:o,settlable:s,settled:!1,resolveSettle:i??null},{seq:l,signal:a}}clearToolSettle(e){this.toolSettleSlot?.seq===e&&(this.toolSettleSlot=null)}async stop(){if(this.state.terminated)return;this.state.terminated=!0,this.notifyRuntimeStop(),this.abortRequested=this.activeTurn,this.abortController?.abort(),this.abortController=null,this.armAbortForceSettle(),this.rejectAllQuestionWaiters("session terminated"),this.cancelPendingAwaitedSubAgents(),this.cancelPendingAwaitedBgTasks(),await V("ACode active turn shutdown",this.submitQueue,t=>{this.emitAcodeEvent("error",{message:t})}),await this.disconnectMcpServers();const e=this.config.agentId||"unknown";if(await V("ACode background commands shutdown",Q.disposeAgent(e),t=>{this.emitAcodeEvent("error",{message:t})}),V("ACode agent PTY sessions shutdown",Promise.resolve(this.config.terminalManager?.killByAgent?.(e)),t=>{this.emitAcodeEvent("error",{message:t})}),await V("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(),ae)try{G.promises.appendFile(Oe,`[${new Date().toISOString()}] runtime stopped | ---
10
+ `);this.initialConversation=ue(B),this.state={started:!0,terminated:!1,configMcpCount:Object.keys(e.mcpServers??{}).length,skills:t,provider:l,permissions:i,mcpConnections:a,ownsMcpConnections:r,exposedTools:A,commands:R,commandRegistry:f,conversation:ue(B),accumulatedInputTokens:0,accumulatedOutputTokens:0,accumulatedCacheHitTokens:0,accumulatedCacheMissTokens:0},this.exposedToolsInitialized=!0,this.emitAcodeEvent("startup_phase",{phase:"session_start_hook"}),await this.hookBus.dispatch("SessionStart",{workingDirectory:this.config.workingDirectory,model:l.model,commandCount:R.length});const L=me(l);this.emitAcodeEvent("session_started",{workingDirectory:this.config.workingDirectory,model:l.model,commandCount:R.length,estimatedContextTokens:Bt(F,A),contextLimit:L.contextLimit,maxOutput:L.maxOutput,...L.inputLimit!==void 0?{inputLimit:L.inputLimit}:{},compactionThreshold:L.threshold}),this.emitAcodeEvent("mcp_status",{configPath:this.config.configPath,installedCount:this.state.configMcpCount,servers:Object.keys(e.mcpServers??{}),connectedCount:a.length,builtInToolCount:p.length,toolCount:A.length,permissionMode:i.mode,allowedToolRules:i.allow,deniedToolRules:i.deny,tools:A.map(g=>({name:g.exposedName,source:g.kind==="mcp"?`${g.serverName}.${g.toolName}`:`builtin.${g.toolName}`,description:g.description||""}))}),this.emitAcodeEvent("skill_status",{skillsDir:this.config.skillsDir,installedCount:t.length,skills:t.map(g=>({name:g.name,description:g.description,directory:g.directory})),skillGroups:o.map(g=>({dir:g.dir,exists:g.exists,skills:g.skills.map(q=>({name:q.name,description:q.description,directory:q.directory}))}))}),this.emitAcodeEvent("command_status",{action:"commands_loaded",installedCommandCount:R.length,commandDirs:$,commands:R.map(g=>({name:g.name,description:g.description}))}),this.config.initialPrompt&&await this.submit(this.config.initialPrompt),this.startCompactionDebugLog(),this.startSkillWatchers(s)}async loadAllSkills(){const e=this.config.skillsDir??"",t=te.join(this.config.workingDirectory,".acode","skills"),o=te.join(this.config.workingDirectory,".agentswork","skills"),s=new Set,l=[],i=[];for(const c of[e,t,o]){if(!c)continue;const m=te.resolve(c);if(!s.has(m)){s.add(m),l.push(await yt(c));try{await G.promises.access(m),i.push(m)}catch{}}}const a=new Map;for(const c of l)for(const m of c.skills)a.set(m.name,m);return{skills:[...a.values()],skillGroups:l,watchedDirs:i}}startSkillWatchers(e){for(const t of e){let o=null;try{o=G.watch(t,{recursive:!0},()=>{this.scheduleSkillRefresh()})}catch{try{o=G.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()},H.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}))}))}),u(`[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(!ae||this.compactionDebugTimer)return;const e=this.state.provider,{contextLimit:t,maxOutput:o,inputLimit:s,threshold:l}=me(e);this.compactionDebugTimer=setInterval(()=>{try{const i=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,a=oe(this.state.conversation)+Ue(this.state.exposedTools),r=Math.max(i,a),c=Y(this.state.conversation),m=this.state.started&&!this.state.terminated,p=[`[${new Date().toISOString()}]`,`started=${this.state.started}`,`terminated=${this.state.terminated}`,`activeTurn=${this.activeTurn}`,`conversationSize=${this.state.conversation.length}msgs`,`sizeKB=${c}KB`,`estimation=${a} tokens`,`actualInput=${this.state.accumulatedInputTokens}`,`actualOutput=${this.state.accumulatedOutputTokens}`,`actualUsed=${i}`,`contextLimit=${t}`,`inputLimit=${s??"n/a"}`,`maxOutput=${o}`,`triggerThreshold=${l}`,`remainingToTrigger=${Math.max(0,l-i)}`,`isRunning=${m}`,`shouldCompact=${m?r>=l:!1}`,"---"].join(" | ");G.promises.appendFile(De,p+`
11
+ `,"utf-8").catch(()=>{})}catch{}},5e3)}stopCompactionDebugLog(){this.compactionDebugTimer&&(clearInterval(this.compactionDebugTimer),this.compactionDebugTimer=null)}async submit(e){const t=this.contextVersion;u(`[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(()=>(u(`[ACodeRuntime] \u25B6\uFE0F executeSubmit dequeued: contextVersion=${t}`),this.executeSubmitGuarded(e,t)));return this.submitQueue=o.catch(()=>{u("[ACodeRuntime] \u{1F4EC} submit() queued item rejected (catch swallowed)")}),u("[ACodeRuntime] \u{1F4EC} submit() returning queued promise"),o}executeSubmitGuarded(e,t){const o={};this.activeTurnToken=o;const s=this.executeSubmit(e,t),l=new Promise(i=>{this.forceSettleWaiters.set(o,i)});return s.finally(()=>{this.forceSettleWaiters.delete(o),this.activeTurnToken===o&&(this.abortForceSettleTimer&&(clearTimeout(this.abortForceSettleTimer),this.abortForceSettleTimer=null),this.activeTurnToken=null)}).catch(()=>{}),Promise.race([s,l])}armAbortForceSettle(){if(!this.activeTurn||!this.activeTurnToken)return;const e=this.activeTurnToken;this.abortForceSettleTimer&&clearTimeout(this.abortForceSettleTimer);const t=Mo();this.abortForceSettleTimer=setTimeout(()=>{this.abortForceSettleTimer=null,this.activeTurn&&this.activeTurnToken===e&&this.forceSettleActiveTurn(`turn still unsettled ${t}ms after abort()`)},t),typeof this.abortForceSettleTimer.unref=="function"&&this.abortForceSettleTimer.unref()}forceSettleActiveTurn(e){const t=this.activeTurnToken;console.error(`[ACodeRuntime] \u{1F6A8} FORCE SETTLE: active turn ignored abort() (${e}). Force-settling to unblock submitQueue; late executeSubmit continuation will be superseded.`),this.contextVersion+=1,this.activeTurn=!1,this.abortRequested=!1,this.abortController=null,this.rejectAllQuestionWaiters("aborted"),this.cancelPendingAwaitedSubAgents(),this.cancelPendingAwaitedBgTasks(),this.notifyRuntimeStop(),this.emitAcodeEvent("error",{message:`ACode turn force-settled: ${e}`}),this.emitAcodeEvent("turn_complete",{failed:!0});const o=t?this.forceSettleWaiters.get(t):void 0;t&&this.forceSettleWaiters.delete(t),this.activeTurnToken=null,o?.()}notifyForceMessage(){this.forceMessagePending=!0,u("[ACodeRuntime] \u{1F514} Force message pending flag set")}addBuiltInTools(e){if(!this.state||!this.exposedToolsInitialized||!Array.isArray(e))return 0;const t=new Set(this.state.exposedTools.map(s=>s.exposedName)),o=[];for(const s of e)kt(s)&&(t.has(s.exposedName)||(t.add(s.exposedName),o.push(s)));return o.length===0?0:(this.state.exposedTools=[...this.state.exposedTools,...o],this.emitExposedToolsStatus(),o.length)}removeBuiltInToolsByPrefix(e){if(!this.state||!this.exposedToolsInitialized||!e)return 0;const t=this.state.exposedTools.length;this.state.exposedTools=this.state.exposedTools.filter(s=>!s.exposedName.startsWith(e));const o=t-this.state.exposedTools.length;return o>0&&this.emitExposedToolsStatus(),o}emitExposedToolsStatus(){this.emitAcodeEvent("mcp_status",{servers:this.state.mcpConnections.map(e=>e.serverName),connectedCount:this.state.mcpConnections.length,toolCount:this.state.exposedTools.length,tools:this.state.exposedTools.map(e=>({name:e.exposedName,source:e.kind==="mcp"?`${e.serverName}.${e.toolName}`:`builtin.${e.toolName}`,description:e.description||""}))})}async injectForceMessage(){if(!this.forceMessagePending)return!1;this.forceMessagePending=!1;const e=this.state.mcpConnections.find(t=>t.tools.some(o=>o.toolName==="get_message"));if(!e)return u("[ACodeRuntime] injectForceMessage: no connection with get_message found"),!1;try{const t=await E(e.client.callTool({name:"get_message",arguments:{_aws_force_inject:!0}},void 0,{timeout:1e4}),1e4,"injectForceMessage get_message"),o=O(t);let s=[];try{const r=JSON.parse(o);Array.isArray(r?.directMessages)&&(s=r.directMessages.filter(c=>c?.force===!0))}catch{return!1}if(s.length===0)return!1;const l=JSON.stringify({directMessages:s,groupMessages:[]}),i=`forced_get_msg_${Date.now()}`,a=`${e.serverName}__get_message`;return this.state.conversation.push({role:"assistant",content:null,tool_calls:[{id:i,type:"function",function:{name:a,arguments:"{}"}}]}),this.state.conversation.push({role:"tool",tool_call_id:i,content:l}),u(`[ACodeRuntime] injectForceMessage: injected ${s.length} force message(s) into conversation`),!0}catch(t){return u(`[ACodeRuntime] injectForceMessage failed: ${t}`),!1}}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=ue(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(u("[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"),u("[ACodeRuntime] \u25B6\uFE0F executeSubmit STARTED"),u(`[ACodeRuntime] Message: <redacted, length=${e.length}>`),u(`[ACodeRuntime] \u{1F522} Context version: ${t}`),u("[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=this.activeTurnToken,l=e.trim();let i=!1;try{u("[ACodeRuntime] \u{1F50D} Dispatching UserPromptSubmit hook...");const a=Date.now(),r=await this.hookBus.dispatch("UserPromptSubmit",{prompt:l}),c=Date.now()-a;if(u(`[ACodeRuntime] \u2705 UserPromptSubmit hook completed in ${c}ms, results: ${r.length}`),this.isTurnSuperseded(t)){u("[ACodeRuntime] \u26A0\uFE0F Turn superseded after hook, aborting");return}const m=ce(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}),i=!0,u("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (failed=true) due to hook deny");return}u("[ACodeRuntime] \u{1F50D} Expanding command if any...");const p=this.state.commandRegistry.expand(l),h=p?.prompt.trim()||l,k=p?.command.allowedTools;if(p&&(u(`[ACodeRuntime] \u{1F4CB} Slash command detected: ${p.command.name}`),this.emitAcodeEvent("command_status",{action:"slash_command",command:p.command.name,arguments:p.argumentsText,sourcePath:p.command.sourcePath})),!this.state.provider.baseURL||!this.state.provider.apiKey){u("[ACodeRuntime] \u26A0\uFE0F No provider configured, using fallback response");const A=ao(h,this.state);this.emitAcodeEvent("assistant_delta",{text:A}),this.emitAcodeEvent("turn_complete",{usage:{inputTokens:h.length,outputTokens:A.length}}),i=!0,u("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (fallback mode)");return}u("[ACodeRuntime] \u{1F4CE} Parsing attachment message...");const T=pe(h);if(T.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.");u("[ACodeRuntime] \u{1F5BC}\uFE0F Materializing image content if any...");const w=await qe(T.content);if(this.isTurnSuperseded(t)){u("[ACodeRuntime] \uFE0F Turn superseded after materializing content, aborting");return}u("[ACodeRuntime] \u{1F4AC} Adding user message to conversation"),this.state.conversation.push({role:"user",content:w}),u(`[ACodeRuntime] Conversation size: ${this.state.conversation.length} messages`),u("[ACodeRuntime] Starting runModelTurn...");const C=Date.now(),d=await this.runModelTurn(k,t),y=Date.now()-C;if(u(`[ACodeRuntime] \u2705 runModelTurn completed in ${y}ms`),u(`[ACodeRuntime] \u{1F4DD} Result: text=${d.text?d.text.slice(0,80)+(d.text.length>80?"...":""):"(empty)"}, finishReason=${d.finishReason||"(none)"}`),this.isTurnSuperseded(t)){u("[ACodeRuntime] \uFE0F Turn superseded after runModelTurn, aborting");return}d.text&&!this.state.provider.stream&&(u("[ACodeRuntime] \u{1F4E4} Emitting assistant_delta (non-streaming mode)"),this.emitAcodeEvent("assistant_delta",{text:d.text})),u("[ACodeRuntime] \u{1F4E4} Emitting turn_complete..."),this.emitAcodeEvent("turn_complete",{usage:d.usage??{inputTokens:h.length,outputTokens:d.totalOutputTextLength??d.text.length},...d.responseBody?{responseBody:d.responseBody}:{},...d.finishReason?{finishReason:d.finishReason}:{}}),W(`turn_complete emitted: usage=${JSON.stringify(d.usage??{inputTokens:h.length,outputTokens:d.totalOutputTextLength??d.text.length})} (providerUsage=${d.usage?"real":"FALLBACK-text-length"}) textLength=${d.text.length} totalOutputTextLength=${d.totalOutputTextLength}`),u(`[ACodeRuntime] \u{1F4B0} Current context usage: input=${this.state.accumulatedInputTokens}, output=${this.state.accumulatedOutputTokens}`+(d.usage?"":" (estimated, no provider usage)")),i=!0;const S=Date.now()-o;u("[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"),u(`[ACodeRuntime] \u2705 executeSubmit COMPLETED in ${S}ms`),u("[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(a){const r=Date.now()-o;if(console.error(`[ACodeRuntime] \u274C executeSubmit FAILED after ${r}ms:`,a instanceof Error?a.message:String(a)),console.error("[ACodeRuntime] \u{1F50D} Error stack:",a instanceof Error?a.stack:"(no stack)"),this.isTurnSuperseded(t)){u("[ACodeRuntime] \uFE0F Turn superseded in error handler, skipping recovery");return}if(this.abortRequested){u("[ACodeRuntime] \u26A0\uFE0F Abort requested, emitting aborted turn_complete"),this.emitAcodeEvent("turn_complete",{aborted:!0}),i=!0;return}u("[ACodeRuntime] Emitting error and failed turn_complete..."),this.emitAcodeEvent("error",{message:a instanceof Error?a.message:String(a)}),this.emitAcodeEvent("turn_complete",{failed:!0}),i=!0}finally{const a=Date.now()-o;u(`[ACodeRuntime] \u{1F51A} executeSubmit finally block entered after ${a}ms`),u(`[ACodeRuntime] \u{1F50D} turnCompleted=${i}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, contextVersion=${t}, currentContextVersion=${this.contextVersion}`),this.activeTurnToken===s&&(this.activeTurn=!1,this.abortRequested=!1),!i&&!this.isTurnSuperseded(t)&&(console.error(`[ACodeRuntime] \u{1F6A8} CRITICAL: executeSubmit finally block reached without turn_complete event! Duration: ${a}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}),u("[ACodeRuntime] Emergency turn_complete (failed=true) emitted"))}}async abort(){const e=this.abortController!==null,t=this.activeTurn;this.abortRequested=this.activeTurn,this.abortController?(u(`[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(),this.armAbortForceSettle()}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})})}}async buildAllocatableToolList(){const e=this.state?.exposedTools??[],t=this.config.subAgentSuiteTools??[];let o=[];if(this.config.subAgentSuiteToolProvider)try{o=await this.config.subAgentSuiteToolProvider([])}catch{o=[]}return ne(e,ne(t,o))}buildSubAgentToolDeps(e){const t=this.config.agentId??"unknown",o=this.config.sessionId,s=this.config.workingDirectory,l=this.config;return{spawnSubAgent:async i=>{let a=this.config.subAgentSuiteTools;if(i.allowedTools&&i.allowedTools.length>0&&this.config.subAgentSuiteToolProvider)try{const c=await this.config.subAgentSuiteToolProvider(i.allowedTools);c.length>0&&(a=a?ne(a,c):c)}catch{}const r=await e.spawn({parentAgentId:t,parentSessionId:o,subagentType:i.subagentType,description:i.description,prompt:i.prompt,...i.allowedTools&&i.allowedTools.length>0?{allowedTools:i.allowedTools}:{},workingDirectory:s,parentConfig:{...l,sharedMcpConnections:this.state?.mcpConnections,...a&&a.length>0?{subAgentSuiteTools:a}:{}}});return await e.start(r),{subId:r}},listSubAgentToolCatalog:async()=>be(await this.buildAllocatableToolList()),listSubAgents:async()=>{const i=e.listByParent(t),a=[],r=[];for(const c of i){const m={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"?a.push(m):r.push(m)}return r.sort((c,m)=>(m.endedAt??0)-(c.endedAt??0)),{running:a,history:r}},getSubAgentStatus:async i=>{const a=e.getSubAgent(i);return a?{subId:a.subId,subagentType:a.subagentType,description:a.description,status:a.status,startedAt:a.startedAt,endedAt:a.endedAt,durationMs:a.durationMs,prompt:a.prompt,result:a.result,errorMessage:a.errorMessage,contextSnapshot:a.contextSnapshot}:null},awaitSubAgents:async(i,a)=>{const r=new Set;for(const c of i)this.pendingAwaitedSubIds.add(c),r.add(c);try{return await e.awaitCompletion(i,a)}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 l of o)this.pendingAwaitedSubIds.add(l);try{return this.buildSubAgentToolDeps(t).awaitSubAgents(o,s)}finally{for(const l of o)this.pendingAwaitedSubIds.delete(l)}}:null,awaitBgCommands:(o,s)=>{for(const l of o)this.pendingAwaitedBgTaskIds.add(l);try{return Q.awaitCompletion(e,o,s)}finally{for(const l of o)this.pendingAwaitedBgTaskIds.delete(l)}}}}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);u(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited sub-agent(s): ${t.join(", ")}`);for(const o of t)e.abort(o).catch(s=>{u(`[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);u(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited background command(s): ${t.join(", ")}`),Q.interruptAwaits(e,t)}detachCurrentToolExecution(){const e=this.toolSettleSlot;return!e||!e.settlable||e.settled?!1:(e.settled=!0,e.resolveSettle?.(),u(`[ACodeRuntime] \u{1F680} detachCurrentToolExecution: settling tool ${e.toolName} (toolCallId=${e.toolCallId}) to background`),!0)}beginToolSettle(e,t,o){const s=e.toolName==="Bash",l=++this.toolSettleSeq;let i;const a=s?new Promise(r=>{i=r}):void 0;return this.toolSettleSlot={seq:l,toolName:e.toolName,toolCallId:o,settlable:s,settled:!1,resolveSettle:i??null},{seq:l,signal:a}}clearToolSettle(e){this.toolSettleSlot?.seq===e&&(this.toolSettleSlot=null)}async stop(){if(this.state.terminated)return;this.state.terminated=!0,this.notifyRuntimeStop(),this.abortRequested=this.activeTurn,this.abortController?.abort(),this.abortController=null,this.armAbortForceSettle(),this.rejectAllQuestionWaiters("session terminated"),this.cancelPendingAwaitedSubAgents(),this.cancelPendingAwaitedBgTasks(),await V("ACode active turn shutdown",this.submitQueue,t=>{this.emitAcodeEvent("error",{message:t})}),await this.disconnectMcpServers();const e=this.config.agentId||"unknown";if(await V("ACode background commands shutdown",Q.disposeAgent(e),t=>{this.emitAcodeEvent("error",{message:t})}),V("ACode agent PTY sessions shutdown",Promise.resolve(this.config.terminalManager?.killByAgent?.(e)),t=>{this.emitAcodeEvent("error",{message:t})}),await V("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(),ae)try{G.promises.appendFile(De,`[${new Date().toISOString()}] runtime stopped | ---
12
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,l,i,a="",r=0;this.lastIterationUsage=void 0,u(`[ACodeRuntime] \u25B6\uFE0F runModelTurn started (contextVersion: ${t})`);const c=50;for(let m=0;m<c;m+=1){if(u(`[ACodeRuntime] \u{1F504} Iteration ${m+1} starting...`),this.isTurnSuperseded(t))return u(`[ACodeRuntime] \u26A0\uFE0F Turn superseded at iteration ${m+1}, aborting`),{text:"",totalOutputTextLength:a.length};await this.injectForceMessage();const p=Date.now(),h=await this.requestChatCompletion(e),k=Date.now()-p;if(u(`[ACodeRuntime] \u{1F916} AI request completed in ${k}ms, choices: ${h.choices?.length||0}`),this.isTurnSuperseded(t))return u(`[ACodeRuntime] \u26A0\uFE0F Turn superseded after AI response at iteration ${m+1}`),{text:"",totalOutputTextLength:a.length};if(this.state.terminated)throw u(`[ACodeRuntime] Runtime terminated at iteration ${m+1}`),new Error("ACode runtime was stopped during the active turn");const T=h.choices?.[0];l=JSON.stringify(h,null,2),i=typeof T?.finish_reason=="string"?T.finish_reason:void 0;const w=T?.message,C=typeof w?.content=="string"?w.content:"",d=Array.isArray(w?.tool_calls)?w.tool_calls:[];if(u(`[ACodeRuntime] AI response: content=${C?C.slice(0,100)+(C.length>100?"...":""):"(empty)"}, toolCalls=${d.length}, finishReason=${i||"(none)"}`),h.usage){const M=U(h.usage.prompt_tokens??h.usage.input_tokens),$=U(h.usage.completion_tokens??h.usage.output_tokens),R=M!==void 0,f=$!==void 0;if(W(`provider usage parsed: raw=${JSON.stringify(h.usage)} input=${M} output=${$} hasInput=${R} hasOutput=${f} iteration=${m+1}`),R||f){const _=vt(h.usage,M),v=s?.outputTokens??a.length+C.length;this.state.accumulatedCacheHitTokens+=_?.cacheHitTokens??0,this.state.accumulatedCacheMissTokens+=_?.cacheMissTokens??0,s={inputTokens:R?M:s?.inputTokens??0,outputTokens:f?$:v,cacheHitTokens:this.state.accumulatedCacheHitTokens,cacheMissTokens:this.state.accumulatedCacheMissTokens},this.lastIterationUsage=s,r+=R?M:0,this.state.accumulatedInputTokens=R?M:this.state.accumulatedInputTokens,this.state.accumulatedOutputTokens=f?$:this.state.accumulatedOutputTokens,W(`finalUsage updated: ${JSON.stringify(s)} (cacheUsage=${JSON.stringify(_??null)})`),u(`[ACodeRuntime] \u{1F4B0} Token usage: input=${s.inputTokens}, output=${s.outputTokens} (turn accumulated cost: input=${r})`),u(_?`[ACodeRuntime] \u{1F4B0} Cache usage (provider reported): hit=${_.cacheHitTokens}, miss=${_.cacheMissTokens}`:'[ACodeRuntime] \u{1F4B0} Cache usage: provider usage \u4E2D\u65E0\u7F13\u5B58\u5B57\u6BB5\uFF08\u9762\u677F\u5C06\u663E\u793A "-"\uFF09')}}else W(`provider response has NO usage field (fallback to text-length estimate), iteration=${m+1}`);if(this.state.conversation.push({role:"assistant",content:C||null,tool_calls:d.length>0?d:void 0}),C&&(o=C,a+=C,u(`[ACodeRuntime] \u2728 Captured assistant text: ${C.slice(0,80)}...`)),d.length===0)return u(`[ACodeRuntime] \u2705 No tool calls at iteration ${m+1}, completing turn`),{text:o,usage:s,responseBody:l,finishReason:i,totalOutputTextLength:a.length};const y=d.map(M=>M.function.name).join(", ");u(`[ACodeRuntime] \u{1F527} Executing ${d.length} tool(s) at iteration ${m+1}: ${y}`);const S=Date.now();await this.handleToolCalls(d,e,t);const A=Date.now()-S;if(u(`[ACodeRuntime] \u2699\uFE0F Tool execution completed in ${A}ms at iteration ${m+1}`),this.isTurnSuperseded(t))return u(`[ACodeRuntime] \u26A0\uFE0F Turn superseded after tool execution at iteration ${m+1}`),{text:"",totalOutputTextLength:a.length};u(`[ACodeRuntime] \u{1F504} Preparing iteration ${m+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:l,finishReason:i||"safety_iteration_limit_reached",totalOutputTextLength:a.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 l={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
- `+gt}]},i=new AbortController;this.abortController=i;let a=!1;try{return await E((async()=>{const r=await E(fetch(le(o),{method:"POST",headers:s,body:JSON.stringify(l),signal:i.signal}),t.requestTotalTimeoutMs,"ACode LLM summarization",()=>{a=!0,i.abort()});if(!r.ok){const p=await E(r.text(),t.requestTimeoutMs,"ACode LLM summarization error response body",()=>{a=!0,i.abort()}),h=p.length>500?`${p.slice(0,500)}...(truncated, total ${p.length} chars)`:p;throw new Error(`ACode LLM summarization request failed: ${r.status} ${h}`)}const m=(await E(r.json(),t.requestTimeoutMs,"ACode LLM summarization response body",()=>{a=!0,i.abort()})).choices?.[0]?.message?.content;if(!m||m.trim().length===0)throw new Error("ACode LLM summarization returned empty content");return m})(),t.requestTotalTimeoutMs,"ACode LLM summarization total",()=>{i.abort()})}catch(r){throw r instanceof Error&&r.name==="AbortError"?a?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:l,inputLimit:i,threshold:a}=me(t),r=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,c=oe(this.state.conversation)+Be(this.state.exposedTools),m=Math.max(r,c),p=m>=a;if(u(`[ACodeRuntime] \u{1F50D} Compaction check: actualUsed=${r}, estimation=${c}, effectiveUsed=${m}, contextLimit=${s}, inputLimit=${i??"n/a"}, maxOutput=${l}, triggerThreshold=${a}, shouldCompact=${p}`),p){const f=Y(this.state.conversation),_=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:_,sizeKB:f,estimatedTokens:c,actualInputTokens:this.state.accumulatedInputTokens,actualOutputTokens:this.state.accumulatedOutputTokens,messageCount:this.state.conversation.length,model:t.model,trigger:r>=a?"actual_usage":"estimated_overflow"}),this.emitCompactionPhase(_,"detect","\u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6709\u6548\u7528\u91CF: ${m} tokens, \u9608\u503C: ${a}, \u89E6\u53D1: ${r>=a?"\u5B9E\u9645\u7528\u91CF":"\u4F30\u7B97\u6EA2\u51FA"}`);const v=await Ae(this.state.conversation,s,l,{llmSummarizer:b=>this.summarizeConversationWithLLM(b),onPhase:b=>this.handleCompactionPhase(_,b),actualUsedTokens:m}),N=Y(this.state.conversation);this.emitAcodeEvent("context_compaction",{action:"end",compactionId:_,sizeBeforeKB:f,sizeAfterKB:N,freedKB:Math.round((f-N)*10)/10,strategy:v.strategy,freedTokens:v.freedTokens,tokensBefore:v.tokensBefore,tokensAfter:v.tokensAfter,prunedToolMessages:v.prunedToolMessages,summarizedMessages:v.summarizedMessages,messageCountBefore:v.messageCountBefore,messageCountAfter:v.messageCountAfter}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}const h=await co(this.state.conversation,De,s,l,f=>this.summarizeConversationWithLLM(f));h>0&&(this.emitAcodeEvent("warning",{message:`Conversation truncated: removed ${h} older messages to fit within ${De} byte request size limit`}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0);const k=this.state.exposedTools.filter(f=>no(f,this.state.permissions,e)),T=()=>{const f={model:t.model,messages:this.state.conversation,stream:t.stream};return t.effort&&(f.reasoning_effort=t.effort),t.stream&&(f.stream_options={include_usage:!0}),k.length>0&&(f.tools=Ke(k),f.tool_choice="auto"),f},w="POST",C=so(o),d=Co(t),y=_o(d),S=f=>{const _=JSON.stringify(f,null,2);u(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 emitAiRequest: \u53D1\u9001\u8BF7\u6C42 model=${t.model}, endpoint=${C}, messageCount=${this.state.conversation.length}`),this.emitAcodeEvent("ai_request",{model:t.model,endpoint:C,requestMethod:w,requestUrl:C,requestHeaders:y,stream:t.stream,messageCount:this.state.conversation.length,toolCount:k.length,lastUserMessagePreview:io(this.state.conversation),estimatedContextTokens:de(_),requestBody:_,...this.lastIterationUsage?{lastUsage:this.lastIterationUsage}:{}}),W(`ai_request emitted: model=${t.model} stream=${t.stream} messageCount=${this.state.conversation.length} toolCount=${k.length} estimatedContextTokens=${de(_)} lastUsage=${JSON.stringify(this.lastIterationUsage??null)}`)};let A=T();S(A);const M=t.requestRetryCount===se,$=M?1/0:t.requestRetryCount+1;let R=!1;for(let f=1;M||f<=$;f+=1){this.state.terminated||(this.abortRequested=!1),f>1&&S(A);const _=new AbortController;this.abortController=_;let v=!1;try{return await E((async()=>{const N=t.stream?t.requestFirstByteTimeoutMs:t.requestTotalTimeoutMs,b=await E(fetch(le(o),{method:w,headers:d,body:JSON.stringify(A),signal:_.signal}),N,"ACode provider request",()=>{v=!0,_.abort()});if(!b.ok){const F=await E(b.text(),t.requestStreamIdleTimeoutMs,"ACode provider error response body",()=>{v=!0,_.abort()}),L=F.length>500?`${F.slice(0,500)}...(truncated, total ${F.length} chars)`:F;throw new Error(`ACode provider request failed: ${b.status} ${L}`)}const P=b.headers?.get?.("content-type")||"";if(t.stream&&P.toLowerCase().includes("text/event-stream"))return await this.readChatCompletionStream(b,t.requestStreamIdleTimeoutMs,_,t.requestFirstByteTimeoutMs);const B=await E(b.json(),t.requestStreamIdleTimeoutMs,"ACode provider response body",()=>{v=!0,_.abort()});return x(B)?B:(this.emitAcodeEvent("warning",{message:`ACode provider returned invalid response format (expected object, got ${typeof B}); treating as empty response`}),{})})(),t.requestTotalTimeoutMs,"ACode provider request total",()=>{_.abort()})}catch(N){let b;if(N instanceof Error&&N.name==="AbortError"?v?b=new Error(`ACode provider request timed out (firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):this.state.terminated?b=new Error("ACode provider request aborted by user"):b=new Error(`ACode provider request timed out (watchdog abort, firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):b=N instanceof Error?N:new Error(String(N)),!R&&!this.abortRequested&&!this.state.terminated&&Je(b)){const L=Y(this.state.conversation),g=oe(this.state.conversation),q=this.state.conversation.length,j=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:j,sizeKB:L,estimatedTokens:g,messageCount:q,model:t.model,trigger:"provider_overflow_error"}),this.emitCompactionPhase(j,"detect","Provider \u8FD4\u56DE\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6D88\u606F: ${q}\u6761, \u5927\u5C0F: ${L}KB`),this.emitCompactionPhase(j,"prune","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA","\u6B63\u5728\u88C1\u526A...");const K=Tt(this.state.conversation,s);this.emitCompactionPhase(j,"prune_done","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA",`\u88C1\u526A\u4E86 ${K.prunedCount} \u6761\u5DE5\u5177\u8F93\u51FA, \u91CA\u653E ${K.freedTokens} tokens`),this.emitCompactionPhase(j,"summarize","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD","\u6B63\u5728\u6458\u8981...");const ee=await Ce(this.state.conversation,{llmSummarizer:Ye=>this.summarizeConversationWithLLM(Ye),contextLimit:s});this.emitCompactionPhase(j,"summarize_done","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD",`\u6458\u8981\u5316\u4E86 ${ee} \u6761\u6D88\u606F`);const ge=Y(this.state.conversation),Ge=oe(this.state.conversation),Qe=this.state.conversation.length;R=!0;const Te=K.prunedCount+ee;if(this.emitAcodeEvent("context_compaction",{action:"end",compactionId:j,sizeBeforeKB:L,sizeAfterKB:ge,freedKB:Math.round((L-ge)*10)/10,tokensBefore:g,tokensAfter:Ge,messageCountBefore:q,messageCountAfter:Qe,strategy:ee>0?"summarize":"prune",freedTokens:K.freedTokens,prunedToolMessages:K.prunedCount,summarizedMessages:ee,trigger:"provider_overflow_error"}),Te===0)throw b;this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0,this.emitAcodeEvent("warning",{message:`ACode provider context limit exceeded; summarized ${Te} older messages and rebuilt the request instead of retrying the same oversized payload`}),A=T(),S(A),f-=1;continue}if(!((M||f<$)&&!this.abortRequested&&!this.state.terminated&&uo(b)))throw b;this.emitAcodeEvent("error",{message:`ACode provider request attempt ${f}${M?"":`/${$}`} failed; retrying: ${b.message}`,nonFatal:!0});const B=Math.min(It,Nt*Math.pow(2,f-1)),F=Math.random()*1e3;await qt(B+F)}finally{this.abortController===_&&(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 l=e.body.getReader(),i=new TextDecoder,a=new Map;let r="",c="",m;const p=k=>{for(const T of $o(k)){if(T==="[DONE]")continue;const w=JSON.parse(T);if(!x(w))continue;const C=w.usage;C&&(m=xt(m,C),W(`stream usage chunk received: ${JSON.stringify(C)} -> merged: ${JSON.stringify(m)}`));const y=w.choices?.[0]?.delta,S=fo(y);S&&this.emitAcodeEvent("thinking_delta",{text:S});const A=typeof y?.content=="string"?y.content:"";A&&(r+=A,this.emitAcodeEvent("assistant_delta",{text:A}));const M=Array.isArray(y?.tool_calls)?y.tool_calls:[];for(const $ of M)ko(a,$)}};let h=!0;for(;;){const k=h&&s?s:t,{done:T,value:w}=await E(l.read(),k,h?"ACode provider stream first byte":"ACode provider stream idle",()=>o?.abort());if(h=!1,T)break;c+=i.decode(w,{stream:!0});const C=c.split(/\r?\n\r?\n/);c=C.pop()??"";for(const d of C)p(d)}return c+=i.decode(),c.trim()&&p(c),{choices:[{message:{content:r||null,tool_calls:So(a)}}],...m?{usage:m}:{}}}async handleToolCalls(e,t,o=this.contextVersion){u(`[ACodeRuntime] handleToolCalls started with ${e.length} tool(s)`);const s=i=>_e(i.function.name)==="poll_message",l=[...e.filter(i=>!s(i)),...e.filter(i=>s(i))];e.length>1&&l.some((i,a)=>i!==e[a])&&u(`[ACodeRuntime] \u2195\uFE0F Reordered tool calls (poll_message \u2192 end): ${l.map(i=>i.function.name).join(", ")}`);for(const i of l){if(this.isTurnSuperseded(o)){u("[ACodeRuntime] \uFE0F Turn superseded, skipping remaining tools");return}const a=i.function.name;u(`[ACodeRuntime] \u{1F50D} Looking up tool: ${a}`);let r=this.state.exposedTools.find(c=>c.exposedName===a);if(r||(r=this.state.exposedTools.find(c=>c.toolName===a),r&&u(`[ACodeRuntime] \u21A9\uFE0F \u88F8\u540D\u56DE\u9000\u5339\u914D: ${a} -> ${r.exposedName}`)),!r){console.error(`[ACodeRuntime] \u274C Tool not found: ${a}, 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: ${a}`});continue}u(`[ACodeRuntime] Found tool: ${r.toolName} (kind: ${r.kind}, source: ${r.kind==="mcp"?r.serverName:"builtin"})`);try{if(r.kind==="builtin"){const A=We(i.function.arguments);u(`[ACodeRuntime] Built-in tool arguments: ${JSON.stringify(A).slice(0,200)}`),fe(r,this.state.permissions,t);const M=await this.hookBus.dispatch("PreToolUse",{source:"builtin",toolName:r.toolName,exposedName:r.exposedName,arguments:A});if(this.isTurnSuperseded(o))return;const $=ce(M);if($)throw console.error(`[ACodeRuntime] \u274C Tool denied by hook: ${r.exposedName}: ${$.message}`),new Error($.message||`ACode tool denied by hook: ${r.exposedName}`);u(`[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:A,argumentsPreview:He(A)});const R=Date.now(),f=ro(r,A,this.state.provider.mcpToolTimeoutMs);u(`[ACodeRuntime] \u25B6\uFE0F Executing built-in tool: ${r.exposedName} (timeout: ${f}ms, abortRequested: ${this.abortRequested})`),f<=0&&console.warn(`[ACodeRuntime] \u26A0\uFE0F Built-in tool ${r.exposedName} has NO timeout (timeoutMs=${f})! If this tool hangs, executeSubmit will NEVER resolve, blocking the submit queue permanently.`);const _=this.beginToolSettle(r,A,i.id);try{const v=await E(r.execute(A,{onOutput:P=>{this.emitAcodeEvent("command_output",{server:"builtin",tool:r.toolName,exposedName:r.exposedName,toolUseId:i.id,stream:P.stream,text:P.text,sequence:P.sequence,cwd:P.cwd,commandLineCount:P.commandLineCount,...P.commandFilePath?{commandFilePath:P.commandFilePath}:{}})},toolCallId:i.id,..._.signal?{settleSignal:_.signal}:{}}),f,`ACode built-in tool ${r.toolName}`),N=Date.now()-R;if(u(`[ACodeRuntime] \u2705 Built-in tool ${r.exposedName} completed in ${N}ms`),this.isTurnSuperseded(o)||(await this.hookBus.dispatch("PostToolUse",{source:"builtin",toolName:r.toolName,exposedName:r.exposedName,result:O(v)}),this.isTurnSuperseded(o)))return;const b=O(v);u(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result for ${r.exposedName}, result length: ${b.length} chars`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:"builtin",tool:r.toolName,result:b}),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:b}),await this.appendSyntheticMultimodalUserMessage(b,i.id,o)}finally{this.clearToolSettle(_.seq)}continue}const c=this.state.mcpConnections.find(A=>A.serverName===r.serverName);if(!c){console.error(`[ACodeRuntime] \u274C MCP server not connected: ${r.serverName}, connected servers: ${this.state.mcpConnections.map(A=>A.serverName).join(", ")}`),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:`ACode MCP server not connected: ${r.serverName}`});continue}const m=We(i.function.arguments);u(`[ACodeRuntime] MCP tool arguments: ${JSON.stringify(m).slice(0,200)}`),fe(r,this.state.permissions,t);const p=await this.hookBus.dispatch("PreToolUse",{source:"mcp",serverName:r.serverName,toolName:r.toolName,exposedName:r.exposedName,arguments:m});if(this.isTurnSuperseded(o))return;const h=ce(p);if(h)throw console.error(`[ACodeRuntime] \u274C MCP tool denied by hook: ${r.exposedName}: ${h.message}`),new Error(h.message||`ACode tool denied by hook: ${r.exposedName}`);u(`[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:m,argumentsPreview:He(m)});const k=_t(r.toolName),T=bt(r.toolName),w=k?this.state.provider.mcpPollingToolTimeoutMs:T?0:this.state.provider.mcpToolTimeoutMs,C=Date.now();u(`[ACodeRuntime] \u25B6\uFE0F Executing MCP tool: ${r.exposedName} (timeout: ${w}ms, polling: ${k})`);const d=k&&_e(r.toolName)==="poll_message"?await this.callPollMessageWithSubAgentRace(c,r,m,w):await this.callMcpToolWithTimeout(c,r,m,w,k),y=Date.now()-C;if(u(`[ACodeRuntime] \u2705 MCP tool ${r.exposedName} completed in ${y}ms`),this.isTurnSuperseded(o)||(await this.hookBus.dispatch("PostToolUse",{source:"mcp",serverName:r.serverName,toolName:r.toolName,exposedName:r.exposedName,result:O(d)}),this.isTurnSuperseded(o)))return;const S=O(d);u(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result for MCP ${r.exposedName}, result length: ${S.length} chars`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:r.serverName,tool:r.toolName,result:S}),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:S}),await this.appendSyntheticMultimodalUserMessage(S,i.id,o)}catch(c){const m=c instanceof Error&&c.message.includes("timed out after"),p=c instanceof Error&&c.name==="AbortError";if(console.error(`[ACodeRuntime] \u274C Tool execution failed: ${i.function.name}`,`isTimeout=${m}, isAbortError=${p}`,c instanceof Error?c.message:String(c)),this.isTurnSuperseded(o)){u("[ACodeRuntime] \uFE0F Turn superseded after tool error, skipping");return}if(this.abortRequested||this.state.terminated)throw u(`[ACodeRuntime] \u26A0\uFE0F Rethrowing error due to abort/termination (abortRequested=${this.abortRequested}, terminated=${this.state.terminated})`),u(`[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));u(`[ACodeRuntime] Calling appendToolFailureResult for ${r.exposedName} (isTimeout=${m})`),this.appendToolFailureResult(i,r,c)}}u(`[ACodeRuntime] handleToolCalls completed for all ${e.length} tool(s)`)}async callMcpToolWithTimeout(e,t,o,s,l,i){const a=s>0?s:Pt,c=!!this.config.sharedMcpConnections?{...o,_aws_sub_agent:!0}:o;for(;;){const m=this.createRuntimeStopWaiter(`ACode MCP tool ${t.serverName}/${t.toolName}`);try{return await E(Promise.race([e.client.callTool({name:t.toolName,arguments:c},void 0,{timeout:a,...i?{signal:i}:{}}),m.promise]),s,`ACode MCP tool ${t.serverName}/${t.toolName}`)}catch(p){if(i?.aborted||!l||s>0||!mo(p))throw p;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(o=>{const s=o.error?`Sub-agent ${o.subId} [${o.status}]: ${o.description}
18
+ `+ft}]},i=new AbortController;this.abortController=i;let a=!1;try{return await E((async()=>{const r=await E(fetch(le(o),{method:"POST",headers:s,body:JSON.stringify(l),signal:i.signal}),t.requestTotalTimeoutMs,"ACode LLM summarization",()=>{a=!0,i.abort()});if(!r.ok){const p=await E(r.text(),t.requestTimeoutMs,"ACode LLM summarization error response body",()=>{a=!0,i.abort()}),h=p.length>500?`${p.slice(0,500)}...(truncated, total ${p.length} chars)`:p;throw new Error(`ACode LLM summarization request failed: ${r.status} ${h}`)}const m=(await E(r.json(),t.requestTimeoutMs,"ACode LLM summarization response body",()=>{a=!0,i.abort()})).choices?.[0]?.message?.content;if(!m||m.trim().length===0)throw new Error("ACode LLM summarization returned empty content");return m})(),t.requestTotalTimeoutMs,"ACode LLM summarization total",()=>{i.abort()})}catch(r){throw r instanceof Error&&r.name==="AbortError"?a?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:l,inputLimit:i,threshold:a}=me(t),r=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,c=oe(this.state.conversation)+Ue(this.state.exposedTools),m=Math.max(r,c),p=m>=a;if(u(`[ACodeRuntime] \u{1F50D} Compaction check: actualUsed=${r}, estimation=${c}, effectiveUsed=${m}, contextLimit=${s}, inputLimit=${i??"n/a"}, maxOutput=${l}, triggerThreshold=${a}, shouldCompact=${p}`),p){const f=Y(this.state.conversation),_=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:_,sizeKB:f,estimatedTokens:c,actualInputTokens:this.state.accumulatedInputTokens,actualOutputTokens:this.state.accumulatedOutputTokens,messageCount:this.state.conversation.length,model:t.model,trigger:r>=a?"actual_usage":"estimated_overflow"}),this.emitCompactionPhase(_,"detect","\u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6709\u6548\u7528\u91CF: ${m} tokens, \u9608\u503C: ${a}, \u89E6\u53D1: ${r>=a?"\u5B9E\u9645\u7528\u91CF":"\u4F30\u7B97\u6EA2\u51FA"}`);const v=await Ae(this.state.conversation,s,l,{llmSummarizer:b=>this.summarizeConversationWithLLM(b),onPhase:b=>this.handleCompactionPhase(_,b),actualUsedTokens:m}),N=Y(this.state.conversation);this.emitAcodeEvent("context_compaction",{action:"end",compactionId:_,sizeBeforeKB:f,sizeAfterKB:N,freedKB:Math.round((f-N)*10)/10,strategy:v.strategy,freedTokens:v.freedTokens,tokensBefore:v.tokensBefore,tokensAfter:v.tokensAfter,prunedToolMessages:v.prunedToolMessages,summarizedMessages:v.summarizedMessages,messageCountBefore:v.messageCountBefore,messageCountAfter:v.messageCountAfter}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}const h=await co(this.state.conversation,Le,s,l,f=>this.summarizeConversationWithLLM(f));h>0&&(this.emitAcodeEvent("warning",{message:`Conversation truncated: removed ${h} older messages to fit within ${Le} byte request size limit`}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0);const k=this.state.exposedTools.filter(f=>no(f,this.state.permissions,e)),T=()=>{const f={model:t.model,messages:this.state.conversation,stream:t.stream};return t.effort&&(f.reasoning_effort=t.effort),t.stream&&(f.stream_options={include_usage:!0}),k.length>0&&(f.tools=He(k),f.tool_choice="auto"),f},w="POST",C=so(o),d=Co(t),y=_o(d),S=f=>{const _=JSON.stringify(f,null,2);u(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 emitAiRequest: \u53D1\u9001\u8BF7\u6C42 model=${t.model}, endpoint=${C}, messageCount=${this.state.conversation.length}`),this.emitAcodeEvent("ai_request",{model:t.model,endpoint:C,requestMethod:w,requestUrl:C,requestHeaders:y,stream:t.stream,messageCount:this.state.conversation.length,toolCount:k.length,lastUserMessagePreview:io(this.state.conversation),estimatedContextTokens:de(_),requestBody:_,...this.lastIterationUsage?{lastUsage:this.lastIterationUsage}:{}}),W(`ai_request emitted: model=${t.model} stream=${t.stream} messageCount=${this.state.conversation.length} toolCount=${k.length} estimatedContextTokens=${de(_)} lastUsage=${JSON.stringify(this.lastIterationUsage??null)}`)};let A=T();S(A);const M=t.requestRetryCount===se,$=M?1/0:t.requestRetryCount+1;let R=!1;for(let f=1;M||f<=$;f+=1){this.state.terminated||(this.abortRequested=!1),f>1&&S(A);const _=new AbortController;this.abortController=_;let v=!1;try{return await E((async()=>{const N=t.stream?t.requestFirstByteTimeoutMs:t.requestTotalTimeoutMs,b=await E(fetch(le(o),{method:w,headers:d,body:JSON.stringify(A),signal:_.signal}),N,"ACode provider request",()=>{v=!0,_.abort()});if(!b.ok){const F=await E(b.text(),t.requestStreamIdleTimeoutMs,"ACode provider error response body",()=>{v=!0,_.abort()}),L=F.length>500?`${F.slice(0,500)}...(truncated, total ${F.length} chars)`:F;throw new Error(`ACode provider request failed: ${b.status} ${L}`)}const P=b.headers?.get?.("content-type")||"";if(t.stream&&P.toLowerCase().includes("text/event-stream"))return await this.readChatCompletionStream(b,t.requestStreamIdleTimeoutMs,_,t.requestFirstByteTimeoutMs);const B=await E(b.json(),t.requestStreamIdleTimeoutMs,"ACode provider response body",()=>{v=!0,_.abort()});return x(B)?B:(this.emitAcodeEvent("warning",{message:`ACode provider returned invalid response format (expected object, got ${typeof B}); treating as empty response`}),{})})(),t.requestTotalTimeoutMs,"ACode provider request total",()=>{_.abort()})}catch(N){let b;if(N instanceof Error&&N.name==="AbortError"?v?b=new Error(`ACode provider request timed out (firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):this.state.terminated?b=new Error("ACode provider request aborted by user"):b=new Error(`ACode provider request timed out (watchdog abort, firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):b=N instanceof Error?N:new Error(String(N)),!R&&!this.abortRequested&&!this.state.terminated&&We(b)){const L=Y(this.state.conversation),g=oe(this.state.conversation),q=this.state.conversation.length,j=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:j,sizeKB:L,estimatedTokens:g,messageCount:q,model:t.model,trigger:"provider_overflow_error"}),this.emitCompactionPhase(j,"detect","Provider \u8FD4\u56DE\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6D88\u606F: ${q}\u6761, \u5927\u5C0F: ${L}KB`),this.emitCompactionPhase(j,"prune","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA","\u6B63\u5728\u88C1\u526A...");const K=gt(this.state.conversation,s);this.emitCompactionPhase(j,"prune_done","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA",`\u88C1\u526A\u4E86 ${K.prunedCount} \u6761\u5DE5\u5177\u8F93\u51FA, \u91CA\u653E ${K.freedTokens} tokens`),this.emitCompactionPhase(j,"summarize","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD","\u6B63\u5728\u6458\u8981...");const ee=await Ce(this.state.conversation,{llmSummarizer:Qe=>this.summarizeConversationWithLLM(Qe),contextLimit:s});this.emitCompactionPhase(j,"summarize_done","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD",`\u6458\u8981\u5316\u4E86 ${ee} \u6761\u6D88\u606F`);const ge=Y(this.state.conversation),Ke=oe(this.state.conversation),Ge=this.state.conversation.length;R=!0;const Te=K.prunedCount+ee;if(this.emitAcodeEvent("context_compaction",{action:"end",compactionId:j,sizeBeforeKB:L,sizeAfterKB:ge,freedKB:Math.round((L-ge)*10)/10,tokensBefore:g,tokensAfter:Ke,messageCountBefore:q,messageCountAfter:Ge,strategy:ee>0?"summarize":"prune",freedTokens:K.freedTokens,prunedToolMessages:K.prunedCount,summarizedMessages:ee,trigger:"provider_overflow_error"}),Te===0)throw b;this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0,this.emitAcodeEvent("warning",{message:`ACode provider context limit exceeded; summarized ${Te} older messages and rebuilt the request instead of retrying the same oversized payload`}),A=T(),S(A),f-=1;continue}if(!((M||f<$)&&!this.abortRequested&&!this.state.terminated&&uo(b)))throw b;this.emitAcodeEvent("error",{message:`ACode provider request attempt ${f}${M?"":`/${$}`} failed; retrying: ${b.message}`,nonFatal:!0});const B=Math.min(It,Nt*Math.pow(2,f-1)),F=Math.random()*1e3;await qt(B+F)}finally{this.abortController===_&&(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 l=e.body.getReader(),i=new TextDecoder,a=new Map;let r="",c="",m;const p=k=>{for(const T of $o(k)){if(T==="[DONE]")continue;const w=JSON.parse(T);if(!x(w))continue;const C=w.usage;C&&(m=xt(m,C),W(`stream usage chunk received: ${JSON.stringify(C)} -> merged: ${JSON.stringify(m)}`));const y=w.choices?.[0]?.delta,S=fo(y);S&&this.emitAcodeEvent("thinking_delta",{text:S});const A=typeof y?.content=="string"?y.content:"";A&&(r+=A,this.emitAcodeEvent("assistant_delta",{text:A}));const M=Array.isArray(y?.tool_calls)?y.tool_calls:[];for(const $ of M)ko(a,$)}};let h=!0;for(;;){const k=h&&s?s:t,{done:T,value:w}=await E(l.read(),k,h?"ACode provider stream first byte":"ACode provider stream idle",()=>o?.abort());if(h=!1,T)break;c+=i.decode(w,{stream:!0});const C=c.split(/\r?\n\r?\n/);c=C.pop()??"";for(const d of C)p(d)}return c+=i.decode(),c.trim()&&p(c),{choices:[{message:{content:r||null,tool_calls:So(a)}}],...m?{usage:m}:{}}}async handleToolCalls(e,t,o=this.contextVersion){u(`[ACodeRuntime] handleToolCalls started with ${e.length} tool(s)`);const s=i=>_e(i.function.name)==="poll_message",l=[...e.filter(i=>!s(i)),...e.filter(i=>s(i))];e.length>1&&l.some((i,a)=>i!==e[a])&&u(`[ACodeRuntime] \u2195\uFE0F Reordered tool calls (poll_message \u2192 end): ${l.map(i=>i.function.name).join(", ")}`);for(const i of l){if(this.isTurnSuperseded(o)){u("[ACodeRuntime] \uFE0F Turn superseded, skipping remaining tools");return}const a=i.function.name;u(`[ACodeRuntime] \u{1F50D} Looking up tool: ${a}`);let r=this.state.exposedTools.find(c=>c.exposedName===a);if(r||(r=this.state.exposedTools.find(c=>c.toolName===a),r&&u(`[ACodeRuntime] \u21A9\uFE0F \u88F8\u540D\u56DE\u9000\u5339\u914D: ${a} -> ${r.exposedName}`)),!r){console.error(`[ACodeRuntime] \u274C Tool not found: ${a}, 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: ${a}`});continue}u(`[ACodeRuntime] Found tool: ${r.toolName} (kind: ${r.kind}, source: ${r.kind==="mcp"?r.serverName:"builtin"})`);try{if(r.kind==="builtin"){const A=je(i.function.arguments);u(`[ACodeRuntime] Built-in tool arguments: ${JSON.stringify(A).slice(0,200)}`),fe(r,this.state.permissions,t);const M=await this.hookBus.dispatch("PreToolUse",{source:"builtin",toolName:r.toolName,exposedName:r.exposedName,arguments:A});if(this.isTurnSuperseded(o))return;const $=ce(M);if($)throw console.error(`[ACodeRuntime] \u274C Tool denied by hook: ${r.exposedName}: ${$.message}`),new Error($.message||`ACode tool denied by hook: ${r.exposedName}`);u(`[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:A,argumentsPreview:Je(A)});const R=Date.now(),f=ro(r,A,this.state.provider.mcpToolTimeoutMs);u(`[ACodeRuntime] \u25B6\uFE0F Executing built-in tool: ${r.exposedName} (timeout: ${f}ms, abortRequested: ${this.abortRequested})`),f<=0&&console.warn(`[ACodeRuntime] \u26A0\uFE0F Built-in tool ${r.exposedName} has NO timeout (timeoutMs=${f})! If this tool hangs, executeSubmit will NEVER resolve, blocking the submit queue permanently.`);const _=this.beginToolSettle(r,A,i.id);try{const v=await E(r.execute(A,{onOutput:P=>{this.emitAcodeEvent("command_output",{server:"builtin",tool:r.toolName,exposedName:r.exposedName,toolUseId:i.id,stream:P.stream,text:P.text,sequence:P.sequence,cwd:P.cwd,commandLineCount:P.commandLineCount,...P.commandFilePath?{commandFilePath:P.commandFilePath}:{}})},toolCallId:i.id,..._.signal?{settleSignal:_.signal}:{}}),f,`ACode built-in tool ${r.toolName}`),N=Date.now()-R;if(u(`[ACodeRuntime] \u2705 Built-in tool ${r.exposedName} completed in ${N}ms`),this.isTurnSuperseded(o)||(await this.hookBus.dispatch("PostToolUse",{source:"builtin",toolName:r.toolName,exposedName:r.exposedName,result:O(v)}),this.isTurnSuperseded(o)))return;const b=O(v);u(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result for ${r.exposedName}, result length: ${b.length} chars`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:"builtin",tool:r.toolName,result:b}),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:b}),await this.appendSyntheticMultimodalUserMessage(b,i.id,o)}finally{this.clearToolSettle(_.seq)}continue}const c=this.state.mcpConnections.find(A=>A.serverName===r.serverName);if(!c){console.error(`[ACodeRuntime] \u274C MCP server not connected: ${r.serverName}, connected servers: ${this.state.mcpConnections.map(A=>A.serverName).join(", ")}`),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:`ACode MCP server not connected: ${r.serverName}`});continue}const m=je(i.function.arguments);u(`[ACodeRuntime] MCP tool arguments: ${JSON.stringify(m).slice(0,200)}`),fe(r,this.state.permissions,t);const p=await this.hookBus.dispatch("PreToolUse",{source:"mcp",serverName:r.serverName,toolName:r.toolName,exposedName:r.exposedName,arguments:m});if(this.isTurnSuperseded(o))return;const h=ce(p);if(h)throw console.error(`[ACodeRuntime] \u274C MCP tool denied by hook: ${r.exposedName}: ${h.message}`),new Error(h.message||`ACode tool denied by hook: ${r.exposedName}`);u(`[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:m,argumentsPreview:Je(m)});const k=Ct(r.toolName),T=_t(r.toolName),w=k?this.state.provider.mcpPollingToolTimeoutMs:T?0:this.state.provider.mcpToolTimeoutMs,C=Date.now();u(`[ACodeRuntime] \u25B6\uFE0F Executing MCP tool: ${r.exposedName} (timeout: ${w}ms, polling: ${k})`);const d=k&&_e(r.toolName)==="poll_message"?await this.callPollMessageWithSubAgentRace(c,r,m,w):await this.callMcpToolWithTimeout(c,r,m,w,k),y=Date.now()-C;if(u(`[ACodeRuntime] \u2705 MCP tool ${r.exposedName} completed in ${y}ms`),this.isTurnSuperseded(o)||(await this.hookBus.dispatch("PostToolUse",{source:"mcp",serverName:r.serverName,toolName:r.toolName,exposedName:r.exposedName,result:O(d)}),this.isTurnSuperseded(o)))return;const S=O(d);u(`[ACodeRuntime] \u{1F4E4} Emitting mcp_status tool_result for MCP ${r.exposedName}, result length: ${S.length} chars`),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:r.serverName,tool:r.toolName,result:S}),this.state.conversation.push({role:"tool",tool_call_id:i.id,content:S}),await this.appendSyntheticMultimodalUserMessage(S,i.id,o)}catch(c){const m=c instanceof Error&&c.message.includes("timed out after"),p=c instanceof Error&&c.name==="AbortError";if(console.error(`[ACodeRuntime] \u274C Tool execution failed: ${i.function.name}`,`isTimeout=${m}, isAbortError=${p}`,c instanceof Error?c.message:String(c)),this.isTurnSuperseded(o)){u("[ACodeRuntime] \uFE0F Turn superseded after tool error, skipping");return}if(this.abortRequested||this.state.terminated)throw u(`[ACodeRuntime] \u26A0\uFE0F Rethrowing error due to abort/termination (abortRequested=${this.abortRequested}, terminated=${this.state.terminated})`),u(`[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));u(`[ACodeRuntime] Calling appendToolFailureResult for ${r.exposedName} (isTimeout=${m})`),this.appendToolFailureResult(i,r,c)}}u(`[ACodeRuntime] handleToolCalls completed for all ${e.length} tool(s)`)}async callMcpToolWithTimeout(e,t,o,s,l,i){const a=s>0?s:Pt,c=!!this.config.sharedMcpConnections?{...o,_aws_sub_agent:!0}:o;for(;;){const m=this.createRuntimeStopWaiter(`ACode MCP tool ${t.serverName}/${t.toolName}`);try{return await E(Promise.race([e.client.callTool({name:t.toolName,arguments:c},void 0,{timeout:a,...i?{signal:i}:{}}),m.promise]),s,`ACode MCP tool ${t.serverName}/${t.toolName}`)}catch(p){if(i?.aborted||!l||s>0||!mo(p))throw p;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(o=>{const s=o.error?`Sub-agent ${o.subId} [${o.status}]: ${o.description}
19
19
  Error: ${o.error}`:`Sub-agent ${o.subId} [${o.status}]: ${o.description}
20
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=O(e);let s;try{s=JSON.parse(o)}catch{return e}const i=[...t.map(a=>{const r=a.error?`Sub-agent ${a.subId} [${a.status}]: ${a.description}
21
21
  Error: ${a.error}`:`Sub-agent ${a.subId} [${a.status}]: ${a.description}
@@ -105,5 +105,5 @@ ${a}`}).join(`
105
105
  - \u2705 \u82E5\u5168\u90E8 memory_status \u4E3A "normal"\uFF1A\u9759\u9ED8\u7ED3\u675F
106
106
 
107
107
  \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
108
- \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=O(e)}catch{return e}let s;try{s=JSON.parse(o)}catch{return e}const l=s.directMessages;if(!Array.isArray(l)||l.length===0)return e;const i=[];let a=0;for(const c of l){const m=c._acodeAutoDelegate;if(m&&(m.type==="memory_expiration"||m.type==="memory_file_change"||m.type==="memory_cleanup")){a++;const p=Date.now(),h=m.uris.filter(d=>this.pendingMemorySubAgents.has(d)).length,k=m.uris.filter(d=>{const y=this.memoryDelegateCooldownUntil.get(d);return y!==void 0&&p<y}).length,T=m.uris.filter(d=>{if(this.pendingMemorySubAgents.has(d))return!1;const y=this.memoryDelegateCooldownUntil.get(d);return!(y!==void 0&&p<y)});if(T.length===0){u(`[ACodeRuntime] Memory ${m.type} skipped: ${h} in-progress, ${k} in cooldown (total ${m.uris.length} URIs)`);continue}const w=Array.isArray(m.fileChanges)?m.fileChanges.filter(d=>T.includes(d.uri)):void 0,C=this.buildMemoryDelegatePrompt({type:m.type,uris:T,fileChanges:w});try{const d=wt([$e],be(await this.buildAllocatableToolList())).patterns,y=await t.spawn({parentAgentId:this.config.agentId||"unknown",parentSessionId:this.config.sessionId,subagentType:$e,description:`Memory ${m.type} auto-delegate (${T.length} items)`,prompt:C,...d.length>0?{allowedTools:d}:{},workingDirectory:this.config.workingDirectory,parentConfig:{...this.config,sharedMcpConnections:this.state?.mcpConnections},silent:!0});for(const $ of T)this.pendingMemorySubAgents.set($,y);const S=new Set(T);t.subscribe(y,()=>{const $=t.getSubAgent(y);if($&&($.status==="completed"||$.status==="failed"||$.status==="cancelled")){const R=Date.now();for(const f of S)this.pendingMemorySubAgents.get(f)===y&&this.pendingMemorySubAgents.delete(f),this.memoryDelegateCooldownUntil.set(f,R+Pe);for(const[f,_]of this.memoryDelegateCooldownUntil)_<=R&&this.memoryDelegateCooldownUntil.delete(f);u(`[ACodeRuntime] Memory delegate sub-agent ${y} finished (${$.status}), ${S.size} URI(s) entered ${Pe}ms cooldown`)}});const A=m.type,M=async($,R)=>this.recheckMemoryDelegate(A,T,$,R);await t.startWithRecheck(y,M,3),u(`[ACodeRuntime] Auto-delegated memory ${m.type} to sub-agent ${y} (${T.length} URIs, ${m.uris.length-T.length} already in progress)`)}catch(d){for(const y of T)this.pendingMemorySubAgents.delete(y);u(`[ACodeRuntime] Failed to auto-delegate memory ${m.type} (suppressed, will retry next poll): ${d instanceof Error?d.message:String(d)}`)}}else i.push(c)}if(a===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 l=this.config.subAgentManager;if(!l)return D("runtime.poll.no-subagent-manager","\u65E0 SubAgentManager\uFF0C\u76F4\u63A5\u8D70\u666E\u901A MCP \u8C03\u7528"),await this.callMcpToolWithTimeout(e,t,o,s,!0);const i=l.takeCompletedSubAgents();if(i.length>0)return u(`[ACodeRuntime] poll_message: ${i.length} sub-agent(s) already completed, returning synthetic result`),D("runtime.poll.subagent-synthetic",`${i.length} \u4E2A\u5B50 agent \u5DF2\u5B8C\u6210\uFF0C\u76F4\u63A5\u8FD4\u56DE\u5408\u6210\u7ED3\u679C\uFF08\u4E0D\u8C03 MCP\uFF09`),H.formatSubAgentCompletionAsPollResult(i);let a=!1,r=0;for(;;){r++,D("runtime.poll.round-start",`\u7B2C ${r} \u8F6E race \u5F00\u59CB: timeoutMs=${s} silent=${a}`);const c=new AbortController,m=l.waitForAnyCompletion(),p=a?{...o,_aws_silent_poll:!0}:o,h=Date.now(),k=this.callMcpToolWithTimeout(e,t,p,s,!0,c.signal);try{const T=await Promise.race([k.then(d=>({type:"mcp",result:d})),m.promise.then(d=>({type:"subagent",notif:d}))]);if(T.type==="subagent"){D("runtime.poll.race-winner-subagent",`\u5B50 agent \u5148\u5B8C\u6210\uFF0Cabort MCP \u8C03\u7528\uFF08\u5DF2\u7B49\u5F85 ${Date.now()-h}ms\uFF09\u540E\u8FD4\u56DE\u5408\u6210\u7ED3\u679C`),c.abort(),k.catch(()=>{});const d=l.takeCompletedSubAgents();return d.length===0&&d.push(T.notif),u(`[ACodeRuntime] poll_message: sub-agent ${T.notif.subId} completed during race, returning synthetic result (${d.length} notification(s))`),H.formatSubAgentCompletionAsPollResult(d)}D("runtime.poll.mcp-returned",`MCP \u5148\u8FD4\u56DE\uFF08\u8017\u65F6 ${Date.now()-h}ms\uFF09\uFF0C\u68C0\u67E5\u5F85\u5408\u5E76\u7684\u5B50 agent \u5B8C\u6210`);const w=l.takeCompletedSubAgents();if(w.length>0){u(`[ACodeRuntime] poll_message: MCP returned, merging ${w.length} sub-agent completion(s)`);const d=H.mergeSubAgentCompletionsIntoMcpResult(T.result,w),y=await this.processMemoryAutoDelegates(d);if(D("runtime.poll.delegate-check",`\u5408\u5E76 ${w.length} \u4E2A\u5B50 agent \u5B8C\u6210\u540E\u59D4\u6258\u68C0\u67E5: processed=${y===null?"\u5168\u90E8\u88AB\u59D4\u6258(null)":"\u6709\u53EF\u4EA4\u4ED8"}`),y!==null){if(this.pollResultHasMessages(y))return D("runtime.poll.final-return",`\u7B2C ${r} \u8F6E\uFF1A\u8FD4\u56DE\uFF08MCP+\u5B50agent\u5408\u5E76\u7ED3\u679C\uFF09`),y;D("runtime.poll.empty-repoll",`\u7B2C ${r} \u8F6E\uFF1A\u5408\u5E76\u7ED3\u679C\u4E3A\u7A7A\uFF0C\u7B49\u5F85 ${re}ms \u540E\u91CD\u65B0 poll`)}await this.waitForDelegateRepoll(),a=!0;continue}const C=await this.processMemoryAutoDelegates(T.result);if(D("runtime.poll.delegate-check",`\u59D4\u6258\u68C0\u67E5: processed=${C===null?"\u5168\u90E8\u88AB\u59D4\u6258(null)":"\u6709\u53EF\u4EA4\u4ED8"}`),C!==null){if(this.pollResultHasMessages(C)){const d=this.summarizePollResultForDebug(C);return D("runtime.poll.final-return",`\u7B2C ${r} \u8F6E\uFF1A\u8FD4\u56DE poll \u7ED3\u679C\u7ED9 LLM: ${d}`),C}D("runtime.poll.empty-repoll",`\u7B2C ${r} \u8F6E\uFF1Apoll \u7ED3\u679C\u65E0\u5B9E\u9645\u6D88\u606F\uFF08directMessages/groupMessages \u5747\u7A7A\uFF09\uFF0C\u7B49\u5F85 ${re}ms \u540E\u91CD\u65B0 poll`)}await this.waitForDelegateRepoll(),a=!0}catch(T){throw D("runtime.poll.error",`\u7B2C ${r} \u8F6E MCP \u8C03\u7528\u5F02\u5E38: ${T instanceof Error?T.message:String(T)}`),T}finally{m.cancel()}}}summarizePollResultForDebug(e){try{const t=O(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages:[],l=Array.isArray(o.groupMessages)?o.groupMessages:[];return`dm=${s.length}${s.length>0?JSON.stringify(s.map(i=>({id:i.msgId,ch:i.channel}))):""} gm=${l.length}`}catch{return"(\u65E0\u6CD5\u89E3\u6790\u4E3A JSON)"}}pollResultHasMessages(e){try{const t=O(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages.length:0,l=Array.isArray(o.groupMessages)?o.groupMessages.length:0;return s>0||l>0}catch{return!0}}async waitForDelegateRepoll(){u(`[ACodeRuntime] poll_message: all messages delegated, waiting ${re}ms before re-poll`);const e=this.createRuntimeStopWaiter("delegate re-poll delay");try{await Promise.race([new Promise(t=>{const o=setTimeout(t,re);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,l)=>{t=()=>{l(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=pe(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 l=await Fe(s.content);if(this.isTurnSuperseded(o))return;this.state.conversation.push({role:"user",content:l});const i=this.state.conversation.find(a=>a.role==="tool"&&a.tool_call_id===t);if(i&&typeof i.content=="string"){let a;try{const r=JSON.parse(i.content);if(typeof r=="object"&&r!==null){const c={...r};"attachments"in c&&(delete c.attachments,a=JSON.stringify(c))}}catch{}if(a===void 0){const r=i.content.replace(/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,"").trim();r!==i.content&&(a=r)}a!==void 0&&a.length>0?i.content=a:a!==void 0&&(i.content="[Tool result contained images; see user message above]")}}appendToolFailureResult(e,t,o){const s=po(t,o);u(`[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}: ${Z(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){const t=this.config.subAgentAllowedTools&&this.config.subAgentAllowedTools.length>0?this.config.subAgentAllowedTools:null;return e.map(o=>({...o,tools:o.tools.filter(s=>t?we(s,t):$t.has(s.toolName))}))}async connectMcpServers(e,t){const o=[];for(const[s,l]of Object.entries(e))try{const i=new Ze({name:"acode",version:"0.1.0"}),a=this.createMcpTransport(l);await E(i.connect(a),t,`ACode MCP server ${s} connect`);const r={serverName:s,client:i,transport:a,tools:[]};i.setNotificationHandler(nt,()=>{this.refreshMcpConnectionTools(r,t)});const{tools:c}=await E(i.listTools(),t,`ACode MCP server ${s} listTools`);r.tools=Me(s,c),o.push(r)}catch(i){this.emitAcodeEvent("error",{message:`ACode MCP server failed to connect: ${s}: ${i instanceof Error?i.message:String(i)}`})}return o}requestMcpToolsRefresh(e){const t=this.state.mcpConnections.filter(o=>!e||o.serverName===e);for(const o of t)this.refreshMcpConnectionTools(o,this.state.provider.mcpToolTimeoutMs)}async refreshMcpConnectionTools(e,t){try{const{tools:s}=await E(e.client.listTools(),t,`ACode MCP server ${e.serverName} listTools refresh`);e.tools=Me(e.serverName,s)}catch(s){this.emitAcodeEvent("warning",{message:`ACode MCP server ${e.serverName} tools/list_changed refresh failed: ${s instanceof Error?s.message:String(s)}`});return}if(!this.exposedToolsInitialized)return;const o=this.state.exposedTools.filter(s=>!(s.kind==="mcp"&&s.serverName===e.serverName));this.state.exposedTools=[...o,...e.tools],this.emitExposedToolsStatus()}createMcpTransport(e){if(e.type==="stdio"||e.command){if(!e.command)throw new Error("stdio MCP server requires command");const o=new tt({command:e.command,args:e.args,cwd:e.cwd||this.config.workingDirectory,env:{...this.config.env??{},...e.env??{}},stderr:"pipe"});return o.stderr?.on("data",()=>{}),o}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 et(new URL(e.url),{requestInit:t}):new ot(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 E(t.client.callTool({name:"get_profile",arguments:{}},void 0,{timeout:ie}),ie,"ACode startup get_profile"),l=this.extractProfileFromToolResult(s);return yo(l)}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(!x(e))return null;const t=e.content;if(Array.isArray(t)){for(const o of t)if(x(o)&&typeof o.text=="string"&&o.text.trim())try{const s=JSON.parse(o.text);if(x(s))return s}catch{}}return x(e)?e:null}async disconnectMcpServers(){if(!this.state.ownsMcpConnections){this.state.mcpConnections=[],this.state.exposedTools=[],this.exposedToolsInitialized=!1;return}const e=this.state.mcpConnections;this.state.mcpConnections=[],this.state.exposedTools=[],this.exposedToolsInitialized=!1,await Promise.all(e.map(t=>V(`ACode MCP server ${t.serverName} close`,t.transport.close(),o=>{this.emitAcodeEvent("error",{message:o})},this.state.provider.mcpToolTimeoutMs)))}}H.SKILL_REFRESH_DEBOUNCE_MS=500;export{H as ACodeRuntime};
108
+ \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=O(e)}catch{return e}let s;try{s=JSON.parse(o)}catch{return e}const l=s.directMessages;if(!Array.isArray(l)||l.length===0)return e;const i=[];let a=0;for(const c of l){const m=c._acodeAutoDelegate;if(m&&(m.type==="memory_expiration"||m.type==="memory_file_change"||m.type==="memory_cleanup")){a++;const p=Date.now(),h=m.uris.filter(d=>this.pendingMemorySubAgents.has(d)).length,k=m.uris.filter(d=>{const y=this.memoryDelegateCooldownUntil.get(d);return y!==void 0&&p<y}).length,T=m.uris.filter(d=>{if(this.pendingMemorySubAgents.has(d))return!1;const y=this.memoryDelegateCooldownUntil.get(d);return!(y!==void 0&&p<y)});if(T.length===0){u(`[ACodeRuntime] Memory ${m.type} skipped: ${h} in-progress, ${k} in cooldown (total ${m.uris.length} URIs)`);continue}const w=Array.isArray(m.fileChanges)?m.fileChanges.filter(d=>T.includes(d.uri)):void 0,C=this.buildMemoryDelegatePrompt({type:m.type,uris:T,fileChanges:w});try{const d=wt("explore",[],be(await this.buildAllocatableToolList())).patterns,y=await t.spawn({parentAgentId:this.config.agentId||"unknown",parentSessionId:this.config.sessionId,subagentType:bt,description:`Memory ${m.type} auto-delegate (${T.length} items)`,prompt:C,...d.length>0?{allowedTools:d}:{},workingDirectory:this.config.workingDirectory,parentConfig:{...this.config,sharedMcpConnections:this.state?.mcpConnections},silent:!0});for(const $ of T)this.pendingMemorySubAgents.set($,y);const S=new Set(T);t.subscribe(y,()=>{const $=t.getSubAgent(y);if($&&($.status==="completed"||$.status==="failed"||$.status==="cancelled")){const R=Date.now();for(const f of S)this.pendingMemorySubAgents.get(f)===y&&this.pendingMemorySubAgents.delete(f),this.memoryDelegateCooldownUntil.set(f,R+Ie);for(const[f,_]of this.memoryDelegateCooldownUntil)_<=R&&this.memoryDelegateCooldownUntil.delete(f);u(`[ACodeRuntime] Memory delegate sub-agent ${y} finished (${$.status}), ${S.size} URI(s) entered ${Ie}ms cooldown`)}});const A=m.type,M=async($,R)=>this.recheckMemoryDelegate(A,T,$,R);await t.startWithRecheck(y,M,3),u(`[ACodeRuntime] Auto-delegated memory ${m.type} to sub-agent ${y} (${T.length} URIs, ${m.uris.length-T.length} already in progress)`)}catch(d){for(const y of T)this.pendingMemorySubAgents.delete(y);u(`[ACodeRuntime] Failed to auto-delegate memory ${m.type} (suppressed, will retry next poll): ${d instanceof Error?d.message:String(d)}`)}}else i.push(c)}if(a===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 l=this.config.subAgentManager;if(!l)return D("runtime.poll.no-subagent-manager","\u65E0 SubAgentManager\uFF0C\u76F4\u63A5\u8D70\u666E\u901A MCP \u8C03\u7528"),await this.callMcpToolWithTimeout(e,t,o,s,!0);const i=l.takeCompletedSubAgents();if(i.length>0)return u(`[ACodeRuntime] poll_message: ${i.length} sub-agent(s) already completed, returning synthetic result`),D("runtime.poll.subagent-synthetic",`${i.length} \u4E2A\u5B50 agent \u5DF2\u5B8C\u6210\uFF0C\u76F4\u63A5\u8FD4\u56DE\u5408\u6210\u7ED3\u679C\uFF08\u4E0D\u8C03 MCP\uFF09`),H.formatSubAgentCompletionAsPollResult(i);let a=!1,r=0;for(;;){r++,D("runtime.poll.round-start",`\u7B2C ${r} \u8F6E race \u5F00\u59CB: timeoutMs=${s} silent=${a}`);const c=new AbortController,m=l.waitForAnyCompletion(),p=a?{...o,_aws_silent_poll:!0}:o,h=Date.now(),k=this.callMcpToolWithTimeout(e,t,p,s,!0,c.signal);try{const T=await Promise.race([k.then(d=>({type:"mcp",result:d})),m.promise.then(d=>({type:"subagent",notif:d}))]);if(T.type==="subagent"){D("runtime.poll.race-winner-subagent",`\u5B50 agent \u5148\u5B8C\u6210\uFF0Cabort MCP \u8C03\u7528\uFF08\u5DF2\u7B49\u5F85 ${Date.now()-h}ms\uFF09\u540E\u8FD4\u56DE\u5408\u6210\u7ED3\u679C`),c.abort(),k.catch(()=>{});const d=l.takeCompletedSubAgents();return d.length===0&&d.push(T.notif),u(`[ACodeRuntime] poll_message: sub-agent ${T.notif.subId} completed during race, returning synthetic result (${d.length} notification(s))`),H.formatSubAgentCompletionAsPollResult(d)}D("runtime.poll.mcp-returned",`MCP \u5148\u8FD4\u56DE\uFF08\u8017\u65F6 ${Date.now()-h}ms\uFF09\uFF0C\u68C0\u67E5\u5F85\u5408\u5E76\u7684\u5B50 agent \u5B8C\u6210`);const w=l.takeCompletedSubAgents();if(w.length>0){u(`[ACodeRuntime] poll_message: MCP returned, merging ${w.length} sub-agent completion(s)`);const d=H.mergeSubAgentCompletionsIntoMcpResult(T.result,w),y=await this.processMemoryAutoDelegates(d);if(D("runtime.poll.delegate-check",`\u5408\u5E76 ${w.length} \u4E2A\u5B50 agent \u5B8C\u6210\u540E\u59D4\u6258\u68C0\u67E5: processed=${y===null?"\u5168\u90E8\u88AB\u59D4\u6258(null)":"\u6709\u53EF\u4EA4\u4ED8"}`),y!==null){if(this.pollResultHasMessages(y))return D("runtime.poll.final-return",`\u7B2C ${r} \u8F6E\uFF1A\u8FD4\u56DE\uFF08MCP+\u5B50agent\u5408\u5E76\u7ED3\u679C\uFF09`),y;D("runtime.poll.empty-repoll",`\u7B2C ${r} \u8F6E\uFF1A\u5408\u5E76\u7ED3\u679C\u4E3A\u7A7A\uFF0C\u7B49\u5F85 ${re}ms \u540E\u91CD\u65B0 poll`)}await this.waitForDelegateRepoll(),a=!0;continue}const C=await this.processMemoryAutoDelegates(T.result);if(D("runtime.poll.delegate-check",`\u59D4\u6258\u68C0\u67E5: processed=${C===null?"\u5168\u90E8\u88AB\u59D4\u6258(null)":"\u6709\u53EF\u4EA4\u4ED8"}`),C!==null){if(this.pollResultHasMessages(C)){const d=this.summarizePollResultForDebug(C);return D("runtime.poll.final-return",`\u7B2C ${r} \u8F6E\uFF1A\u8FD4\u56DE poll \u7ED3\u679C\u7ED9 LLM: ${d}`),C}D("runtime.poll.empty-repoll",`\u7B2C ${r} \u8F6E\uFF1Apoll \u7ED3\u679C\u65E0\u5B9E\u9645\u6D88\u606F\uFF08directMessages/groupMessages \u5747\u7A7A\uFF09\uFF0C\u7B49\u5F85 ${re}ms \u540E\u91CD\u65B0 poll`)}await this.waitForDelegateRepoll(),a=!0}catch(T){throw D("runtime.poll.error",`\u7B2C ${r} \u8F6E MCP \u8C03\u7528\u5F02\u5E38: ${T instanceof Error?T.message:String(T)}`),T}finally{m.cancel()}}}summarizePollResultForDebug(e){try{const t=O(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages:[],l=Array.isArray(o.groupMessages)?o.groupMessages:[];return`dm=${s.length}${s.length>0?JSON.stringify(s.map(i=>({id:i.msgId,ch:i.channel}))):""} gm=${l.length}`}catch{return"(\u65E0\u6CD5\u89E3\u6790\u4E3A JSON)"}}pollResultHasMessages(e){try{const t=O(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages.length:0,l=Array.isArray(o.groupMessages)?o.groupMessages.length:0;return s>0||l>0}catch{return!0}}async waitForDelegateRepoll(){u(`[ACodeRuntime] poll_message: all messages delegated, waiting ${re}ms before re-poll`);const e=this.createRuntimeStopWaiter("delegate re-poll delay");try{await Promise.race([new Promise(t=>{const o=setTimeout(t,re);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,l)=>{t=()=>{l(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=pe(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 l=await qe(s.content);if(this.isTurnSuperseded(o))return;this.state.conversation.push({role:"user",content:l});const i=this.state.conversation.find(a=>a.role==="tool"&&a.tool_call_id===t);if(i&&typeof i.content=="string"){let a;try{const r=JSON.parse(i.content);if(typeof r=="object"&&r!==null){const c={...r};"attachments"in c&&(delete c.attachments,a=JSON.stringify(c))}}catch{}if(a===void 0){const r=i.content.replace(/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,"").trim();r!==i.content&&(a=r)}a!==void 0&&a.length>0?i.content=a:a!==void 0&&(i.content="[Tool result contained images; see user message above]")}}appendToolFailureResult(e,t,o){const s=po(t,o);u(`[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}: ${Z(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){const t=this.config.subAgentAllowedTools&&this.config.subAgentAllowedTools.length>0?this.config.subAgentAllowedTools:null;return e.map(o=>({...o,tools:o.tools.filter(s=>t?we(s,t):$t.has(s.toolName))}))}async connectMcpServers(e,t){const o=[];for(const[s,l]of Object.entries(e))try{const i=new Xe({name:"acode",version:"0.1.0"}),a=this.createMcpTransport(l);await E(i.connect(a),t,`ACode MCP server ${s} connect`);const r={serverName:s,client:i,transport:a,tools:[]};i.setNotificationHandler(ot,()=>{this.refreshMcpConnectionTools(r,t)});const{tools:c}=await E(i.listTools(),t,`ACode MCP server ${s} listTools`);r.tools=Se(s,c),o.push(r)}catch(i){this.emitAcodeEvent("error",{message:`ACode MCP server failed to connect: ${s}: ${i instanceof Error?i.message:String(i)}`})}return o}requestMcpToolsRefresh(e){const t=this.state.mcpConnections.filter(o=>!e||o.serverName===e);for(const o of t)this.refreshMcpConnectionTools(o,this.state.provider.mcpToolTimeoutMs)}async refreshMcpConnectionTools(e,t){try{const{tools:s}=await E(e.client.listTools(),t,`ACode MCP server ${e.serverName} listTools refresh`);e.tools=Se(e.serverName,s)}catch(s){this.emitAcodeEvent("warning",{message:`ACode MCP server ${e.serverName} tools/list_changed refresh failed: ${s instanceof Error?s.message:String(s)}`});return}if(!this.exposedToolsInitialized)return;const o=this.state.exposedTools.filter(s=>!(s.kind==="mcp"&&s.serverName===e.serverName));this.state.exposedTools=[...o,...e.tools],this.emitExposedToolsStatus()}createMcpTransport(e){if(e.type==="stdio"||e.command){if(!e.command)throw new Error("stdio MCP server requires command");const o=new et({command:e.command,args:e.args,cwd:e.cwd||this.config.workingDirectory,env:{...this.config.env??{},...e.env??{}},stderr:"pipe"});return o.stderr?.on("data",()=>{}),o}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 Ze(new URL(e.url),{requestInit:t}):new tt(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 E(t.client.callTool({name:"get_profile",arguments:{}},void 0,{timeout:ie}),ie,"ACode startup get_profile"),l=this.extractProfileFromToolResult(s);return yo(l)}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(!x(e))return null;const t=e.content;if(Array.isArray(t)){for(const o of t)if(x(o)&&typeof o.text=="string"&&o.text.trim())try{const s=JSON.parse(o.text);if(x(s))return s}catch{}}return x(e)?e:null}async disconnectMcpServers(){if(!this.state.ownsMcpConnections){this.state.mcpConnections=[],this.state.exposedTools=[],this.exposedToolsInitialized=!1;return}const e=this.state.mcpConnections;this.state.mcpConnections=[],this.state.exposedTools=[],this.exposedToolsInitialized=!1,await Promise.all(e.map(t=>V(`ACode MCP server ${t.serverName} close`,t.transport.close(),o=>{this.emitAcodeEvent("error",{message:o})},this.state.provider.mcpToolTimeoutMs)))}}H.SKILL_REFRESH_DEBOUNCE_MS=500;export{H as ACodeRuntime};
109
109
 
@@ -1,19 +1,20 @@
1
- import{PRESET_CORE as d,PRESET_EXPLORE as c,resolveToolAllocation as g,ToolAllocationError as b}from"./tool-allocation.js";const h=`Launch a new sub-agent to handle a task autonomously (non-blocking).
1
+ import{resolveToolAllocation as d,ToolAllocationError as g}from"./tool-allocation.js";const b=`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
5
5
  2. Run multiple independent tasks in parallel (multiple tool calls in one message)
6
6
  3. Keep the main context window focused by offloading detailed work
7
7
 
8
- Tool allocation (the 'tools' parameter) \u2014 elements combine by union:
9
- - Presets (start with '@'):
10
- - "${c}": read-only set (read/grep/Bash/symbols etc., plus memory MCP tools).
11
- Omitting 'tools' means ["${c}"] \u2014 read-only default
12
- - "${d}": all core default tools (read/write/edit/grep/Bash/todo/terminal; no suites/MCP)
8
+ Sub-agent types (the 'subagent_type' parameter):
9
+ - "explore": read-only set (read/grep/Bash/symbols etc., plus memory MCP tools). Default.
10
+ - "core": all core default tools (read/write/edit/grep/Bash/todo/terminal; no suites/MCP)
11
+ - "custom": allocate specific tools via 'tools' parameter (required when type is custom)
12
+
13
+ Tool allocation (the 'tools' parameter, required for 'custom' type):
13
14
  - Category name allocates a whole suite: "office", "browser", "desktop"
14
15
  - Exact tool path allocates one tool: "default.read_file"
15
- - Mix freely: ["${d}", "browser"]
16
- - Unknown presets/categories are rejected with an error listing what is available;
16
+ - Elements combine by union: ["browser", "default.read_file"]
17
+ - Unknown categories/paths are rejected with an error listing what is available;
17
18
  call list_sub_agent_tools to see all allocatable categories and tool paths first.
18
19
 
19
20
  This tool is NON-BLOCKING: it returns immediately with a subId after spawn.
@@ -27,13 +28,13 @@ Guidelines:
27
28
  - Write a clear, self-contained prompt (the sub-agent starts with a fresh context)
28
29
  - Launch multiple agents concurrently when possible (multiple tool calls in one message)
29
30
  - Sub-agents cannot spawn further sub-agents (no nesting)
30
- - Always call await_complete (with this subId in 'sub_agent_ids') before reporting completion to the user`;function m(n){return{kind:"builtin",toolName:"sub_agent",exposedName:"sub_agent",description:h,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)."},tools:{type:"array",items:{type:"string"},description:`Optional tool allocation, elements combine by union. Presets: '${c}' (read-only default), '${d}' (all core default tools). Or category names ('office', 'browser') / exact tool paths ('default.read_file'). Omit for read-only mode. See list_sub_agent_tools for the full catalog.`}},required:["description","prompt"]},async execute(r){if("subagent_type"in r)return{title:"sub_agent validation error",output:"Invalid input: 'subagent_type' has been removed. Use 'tools' instead: omit for read-only mode, or pass presets ('@explore', '@core') / categories / exact tool paths.",metadata:{error:!0}};const e=typeof r.description=="string"?r.description.trim():"",t=typeof r.prompt=="string"?r.prompt.trim():"";if(!e)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}};const o=r.tools,s=typeof o=="string"?[o]:Array.isArray(o)?o.filter(i=>typeof i=="string"):[];let a,l;try{const i=await n.listSubAgentToolCatalog(),u=g(s,i);a=u.patterns,l=u.label}catch(i){if(i instanceof b)return{title:"sub_agent validation error",output:`Invalid input: ${i.message}`,metadata:{error:!0}};throw i}const p=a.length>0;try{const{subId:i}=await n.spawnSubAgent({subagentType:l,description:e,prompt:t,...p?{allowedTools:a}:{}}),u=p?`
31
- tool allocation (${l}): ${a.join(", ")} (whitelist mode \u2014 only matching tools are exposed)`:`
32
- mode: ${l} (no allocatable tools found in catalog)`;return{title:e,output:`sub_agent spawned: ${i}
33
- type: ${l}${u}
31
+ - Always call await_complete (with this subId in 'sub_agent_ids') before reporting completion to the user`;function h(a){return{kind:"builtin",toolName:"sub_agent",exposedName:"sub_agent",description:b,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:["explore","core","custom"],description:"Sub-agent type: 'explore' (read-only default), 'core' (all core tools), or 'custom' (specific tools via 'tools' param)."},tools:{type:"array",items:{type:"string"},description:"Tool allocation for 'custom' type (required when subagent_type is 'custom'). Category names ('office', 'browser') or exact tool paths ('default.read_file'). Elements combine by union."}},required:["description","prompt","subagent_type"]},async execute(n){const o=typeof n.description=="string"?n.description.trim():"",t=typeof n.prompt=="string"?n.prompt.trim():"",e=typeof n.subagent_type=="string"?n.subagent_type.trim():"";if(!o)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||!["explore","core","custom"].includes(e))return{title:"sub_agent validation error",output:"Invalid input: 'subagent_type' must be one of 'explore', 'core', or 'custom'.",metadata:{error:!0}};const s=n.tools,r=typeof s=="string"?[s]:Array.isArray(s)?s.filter(i=>typeof i=="string"):[];let u,l;try{const i=await a.listSubAgentToolCatalog(),c=d(e,r,i);u=c.patterns,l=c.label}catch(i){if(i instanceof g)return{title:"sub_agent validation error",output:`Invalid input: ${i.message}`,metadata:{error:!0}};throw i}const p=u.length>0;try{const{subId:i}=await a.spawnSubAgent({subagentType:l,description:o,prompt:t,...p?{allowedTools:u}:{}}),c=p?`
32
+ tool allocation (${l}): ${u.join(", ")} (whitelist mode \u2014 only matching tools are exposed)`:`
33
+ mode: ${l} (no allocatable tools found in catalog)`;return{title:o,output:`sub_agent spawned: ${i}
34
+ type: ${l}${c}
34
35
 
35
36
  Call await_complete with this subId in 'sub_agent_ids' to get the result.
36
- Call get_sub_agent_status to check progress.`,metadata:{subId:i,spawned:!0,typeLabel:l,...p?{allocatedTools:a}:{}}}}catch(i){const u=i instanceof Error?i.message:String(i);return{title:e,output:`Failed to spawn sub-agent: ${u}`,metadata:{error:!0}}}}}}const _=`List all sub-agents for the current agent.
37
+ Call get_sub_agent_status to check progress.`,metadata:{subId:i,spawned:!0,typeLabel:l,...p?{allocatedTools:u}:{}}}}catch(i){const c=i instanceof Error?i.message:String(i);return{title:o,output:`Failed to spawn sub-agent: ${c}`,metadata:{error:!0}}}}}}const m=`List all sub-agents for the current agent.
37
38
 
38
39
  Returns two arrays:
39
40
  - running: sub-agents currently in pending/running state
@@ -42,8 +43,8 @@ Returns two arrays:
42
43
  Use this to:
43
44
  1. Check which sub-agents are still running
44
45
  2. Review completed sub-agent history
45
- 3. Find a subId before calling await_complete (sub_agent_ids) or get_sub_agent_status`;function f(n){return{kind:"builtin",toolName:"list_sub_agents",exposedName:"list_sub_agents",description:_,inputSchema:{type:"object",properties:{}},async execute(r){try{const{running:e,history:t}=await n.listSubAgents(),o=a=>{const l=a.durationMs!==void 0?`${(a.durationMs/1e3).toFixed(1)}s`:a.endedAt?`${((a.endedAt-a.startedAt)/1e3).toFixed(1)}s`:"ongoing";return` - ${a.subId} [${a.status}] (${l}) ${a.description}`},s=[];return s.push(`Running (${e.length}):`),e.length===0?s.push(" (none)"):e.forEach(a=>s.push(o(a))),s.push(""),s.push(`History (${t.length}):`),t.length===0?s.push(" (none)"):t.forEach(a=>s.push(o(a))),{title:"sub-agents list",output:s.join(`
46
- `),metadata:{runningCount:e.length,historyCount:t.length}}}catch(e){return{title:"list_sub_agents error",output:`Failed to list sub-agents: ${e instanceof Error?e.message:String(e)}`,metadata:{error:!0}}}}}}const y=`Get the current status and context snapshot of a sub-agent.
46
+ 3. Find a subId before calling await_complete (sub_agent_ids) or get_sub_agent_status`;function f(a){return{kind:"builtin",toolName:"list_sub_agents",exposedName:"list_sub_agents",description:m,inputSchema:{type:"object",properties:{}},async execute(n){try{const{running:o,history:t}=await a.listSubAgents(),e=r=>{const u=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}] (${u}) ${r.description}`},s=[];return s.push(`Running (${o.length}):`),o.length===0?s.push(" (none)"):o.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(`
47
+ `),metadata:{runningCount:o.length,historyCount:t.length}}}catch(o){return{title:"list_sub_agents error",output:`Failed to list sub-agents: ${o instanceof Error?o.message:String(o)}`,metadata:{error:!0}}}}}}const _=`Get the current status and context snapshot of a sub-agent.
47
48
 
48
49
  Returns:
49
50
  - status: pending/running/completed/failed/cancelled
@@ -54,9 +55,9 @@ Returns:
54
55
  - result: final output (if completed)
55
56
  - error: error message (if failed)
56
57
 
57
- Use this to check progress of a running sub-agent before awaiting it.`;function w(n){return{kind:"builtin",toolName:"get_sub_agent_status",exposedName:"get_sub_agent_status",description:y,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID returned by sub_agent tool."}},required:["sub_id"]},async execute(r){const e=typeof r.sub_id=="string"?r.sub_id.trim():"";if(!e)return{title:"get_sub_agent_status validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{const t=await n.getSubAgentStatus(e);if(!t)return{title:"sub-agent not found",output:`sub-agent not found: ${e}`,metadata:{subId:e,error:!0}};const o=[];if(o.push(`subId: ${t.subId}`),o.push(`type: ${t.subagentType}`),o.push(`description: ${t.description}`),o.push(`status: ${t.status}`),t.startedAt&&o.push(`startedAt: ${new Date(t.startedAt).toISOString()}`),t.endedAt&&o.push(`endedAt: ${new Date(t.endedAt).toISOString()}`),t.durationMs!==void 0&&o.push(`duration: ${(t.durationMs/1e3).toFixed(2)}s`),t.contextSnapshot){if(o.push(""),o.push("Context:"),t.contextSnapshot.currentTool&&o.push(` currentTool: ${t.contextSnapshot.currentTool}`),t.contextSnapshot.lastAssistantText){const s=t.contextSnapshot.lastAssistantText;o.push(` lastOutput: ${s.length>200?s.slice(-200)+"...":s}`)}o.push(` tokens: input=${t.contextSnapshot.tokenUsage.input}, output=${t.contextSnapshot.tokenUsage.output}`),o.push(` messages: ${t.contextSnapshot.messageCount}`),o.push(` updatedAt: ${t.contextSnapshot.updatedAt}`)}if(t.result){o.push(""),o.push("Result:");const s=t.result;o.push(s.length>500?s.slice(0,500)+`
58
- ... (truncated)`:s)}return t.errorMessage&&(o.push(""),o.push(`Error: ${t.errorMessage}`)),{title:`status: ${t.description}`,output:o.join(`
59
- `),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:e,error:!0}}}}}}const S=`Abort a running sub-agent.
58
+ Use this to check progress of a running sub-agent before awaiting it.`;function y(a){return{kind:"builtin",toolName:"get_sub_agent_status",exposedName:"get_sub_agent_status",description:_,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID returned by sub_agent tool."}},required:["sub_id"]},async execute(n){const o=typeof n.sub_id=="string"?n.sub_id.trim():"";if(!o)return{title:"get_sub_agent_status validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{const t=await a.getSubAgentStatus(o);if(!t)return{title:"sub-agent not found",output:`sub-agent not found: ${o}`,metadata:{subId:o,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)+`
59
+ ... (truncated)`:s)}return t.errorMessage&&(e.push(""),e.push(`Error: ${t.errorMessage}`)),{title:`status: ${t.description}`,output:e.join(`
60
+ `),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:o,error:!0}}}}}}const w=`Abort a running sub-agent.
60
61
 
61
62
  Use this to cancel a sub-agent that is taking too long or is no longer needed.
62
63
  Only pending or running sub-agents can be aborted; completed/failed/cancelled are no-ops.
@@ -64,21 +65,24 @@ Only pending or running sub-agents can be aborted; completed/failed/cancelled ar
64
65
  After abort:
65
66
  - The sub-agent's status becomes 'cancelled'
66
67
  - Its completionPromise resolves with error='aborted'
67
- - Any await_complete waiting on it (with this subId in 'sub_agent_ids') will return immediately`;function $(n){return{kind:"builtin",toolName:"abort_sub_agent",exposedName:"abort_sub_agent",description:S,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID to abort."}},required:["sub_id"]},async execute(r){const e=typeof r.sub_id=="string"?r.sub_id.trim():"";if(!e)return{title:"abort_sub_agent validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{return await n.abortSubAgent(e),{title:"sub-agent aborted",output:`sub-agent ${e} has been aborted.`,metadata:{subId:e,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:e,error:!0}}}}}}const T=`List all tool presets, categories and tools that can be allocated to sub-agents.
68
+ - Any await_complete waiting on it (with this subId in 'sub_agent_ids') will return immediately`;function S(a){return{kind:"builtin",toolName:"abort_sub_agent",exposedName:"abort_sub_agent",description:w,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID to abort."}},required:["sub_id"]},async execute(n){const o=typeof n.sub_id=="string"?n.sub_id.trim():"";if(!o)return{title:"abort_sub_agent validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{return await a.abortSubAgent(o),{title:"sub-agent aborted",output:`sub-agent ${o} has been aborted.`,metadata:{subId:o,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:o,error:!0}}}}}}const T=`List all tool categories and tools that can be allocated to sub-agents.
68
69
 
69
- Output starts with the built-in '@' presets, then categories (suite). Each category
70
- line shows its tool short names:
70
+ Output shows categories (suite). Each category line shows its tool short names:
71
71
  - default: core file/shell tools (read_file, write_file, grep, Bash, ...)
72
72
  - <suite>: suite tools (e.g. browser: launch, navigate, click, ...)
73
73
  - <mcp-server>: MCP tools under that server (e.g. memory: read_memory, ...)
74
74
 
75
- Use this before spawning a sub-agent with the 'tools' parameter:
76
- - Pass a preset to use a built-in bundle: tools: ["@explore"] or ["@core"]
75
+ Use this before spawning a sub-agent with subagent_type='custom' and 'tools' parameter:
77
76
  - Pass a category name to allocate the whole suite: tools: ["office"]
78
77
  - Pass an exact tool path for one tool: tools: ["default.read_file"]
79
- - Elements combine by union: ["@core", "browser"]
78
+ - Elements combine by union: ["browser", "default.read_file"]
79
+
80
+ Sub-agent types:
81
+ - "explore": read-only set (default category minus write tools + memory MCP tools)
82
+ - "core": all core default tools (no suites/MCP)
83
+ - "custom": allocate specific tools via 'tools' parameter
80
84
 
81
85
  If a tool you need is not listed, it cannot be allocated (the sub-agent pool
82
- equals the current agent's tool set).`;function x(n){return{kind:"builtin",toolName:"list_sub_agent_tools",exposedName:"list_sub_agent_tools",description:T,inputSchema:{type:"object",properties:{}},async execute(r){try{const e=await n.listSubAgentToolCatalog();if(e.length===0)return{title:"allocatable tools",output:"No allocatable tools found (tool catalog is empty).",metadata:{categories:0}};const t=["Presets (for sub_agent 'tools' param):",` ${c} \u2014 read-only set (default category minus write tools + memory MCP tools); omitting 'tools' means ["${c}"]`,` ${d} \u2014 all core default tools (no suites/MCP)`,"","Allocatable tool categories:",""];for(const o of e)t.push(`[${o.category}] ${o.kind} (${o.tools.length}):`),t.push(` ${o.tools.join(", ")}`);return t.push(""),t.push("Usage:"),t.push(`- tools: ["${d}"] \u2192 all core default tools`),t.push(`- tools: ["<category>"] \u2192 all tools in that category (e.g. ["${e[0].category}"])`),t.push(`- tools: ["<category>.<tool>"] \u2192 exactly that tool (e.g. ["${e[0].category}.${e[0].tools[0]??"tool"}"])`),t.push('- elements combine by union, e.g. ["@core", "browser"]'),t.push(`- omit tools \u2192 read-only mode (\u2261 ["${c}"])`),{title:"allocatable tools",output:t.join(`
83
- `),metadata:{categories:e.length}}}catch(e){return{title:"list_sub_agent_tools error",output:`Failed to list allocatable tools: ${e instanceof Error?e.message:String(e)}`,metadata:{error:!0}}}}}}function I(n){return[m(n),f(n),w(n),$(n),x(n)]}export{$ as createAbortSubAgentTool,w as createGetSubAgentStatusTool,x as createListSubAgentToolsTool,f as createListSubAgentsTool,m as createSubAgentTool,I as createSubAgentTools};
86
+ equals the current agent's tool set).`;function x(a){return{kind:"builtin",toolName:"list_sub_agent_tools",exposedName:"list_sub_agent_tools",description:T,inputSchema:{type:"object",properties:{}},async execute(n){try{const o=await a.listSubAgentToolCatalog();if(o.length===0)return{title:"allocatable tools",output:"No allocatable tools found (tool catalog is empty).",metadata:{categories:0}};const t=["Sub-agent types:"," explore \u2014 read-only set (default category minus write tools + memory MCP tools)"," core \u2014 all core default tools (no suites/MCP)"," custom \u2014 allocate specific tools via 'tools' parameter","","Allocatable tool categories:",""];for(const e of o)t.push(`[${e.category}] ${e.kind} (${e.tools.length}):`),t.push(` ${e.tools.join(", ")}`);return t.push(""),t.push("Usage:"),t.push('- subagent_type: "explore" \u2192 read-only mode (default)'),t.push('- subagent_type: "core" \u2192 all core default tools'),t.push('- subagent_type: "custom", tools: ["<category>"] \u2192 all tools in that category'),t.push('- subagent_type: "custom", tools: ["<category>.<tool>"] \u2192 exactly that tool'),t.push('- tools elements combine by union, e.g. ["browser", "default.read_file"]'),{title:"allocatable tools",output:t.join(`
87
+ `),metadata:{categories:o.length}}}catch(o){return{title:"list_sub_agent_tools error",output:`Failed to list allocatable tools: ${o instanceof Error?o.message:String(o)}`,metadata:{error:!0}}}}}}function $(a){return[h(a),f(a),y(a),S(a),x(a)]}export{S as createAbortSubAgentTool,y as createGetSubAgentStatusTool,x as createListSubAgentToolsTool,f as createListSubAgentsTool,h as createSubAgentTool,$ as createSubAgentTools};
84
88
 
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- export type SubAgentType = "@explore" | "@core" | "custom";
3
+ export type SubAgentType = "explore" | "core" | "custom";
4
4
 
5
5
  export type SubAgentStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
6
6