aws-runtime-bridge 1.9.162 → 1.9.169
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +324 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +31 -3
- package/dist/adapter/AcodeSdkAdapter.js +4 -9
- package/dist/adapter/ClaudeSdkAdapter.d.ts +2 -0
- package/dist/adapter/ClaudeSdkAdapter.js +3 -3
- package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
- package/dist/adapter/CodexSdkAdapter.js +3 -3
- package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/OpencodeSdkAdapter.js +3 -3
- package/dist/adapter/prompts.d.ts +1 -1
- package/dist/adapter/prompts.js +1 -1
- package/dist/adapter/types.d.ts +41 -4
- package/dist/adapter/types.js +1 -1
- package/dist/browser/frame-encode.d.ts +25 -0
- package/dist/browser/frame-encode.js +2 -0
- package/dist/browser/screencast-differ.d.ts +2 -3
- package/dist/browser/screencast-differ.js +1 -1
- package/dist/browser/screencast-manager.js +1 -1
- package/dist/browser/types.d.ts +5 -1
- package/dist/browser/types.js +1 -1
- package/dist/desktop/desktop-mcp-client.js +2 -2
- package/dist/routes/background-tasks.js +3 -3
- package/dist/routes/capabilities.js +1 -1
- package/dist/routes/dashboard.d.ts +2 -0
- package/dist/routes/dashboard.js +4 -4
- package/dist/routes/git.js +22 -22
- package/dist/routes/instance.js +1 -1
- package/dist/routes/launch.js +10 -10
- package/dist/routes/mcp-extra.js +2 -2
- package/dist/routes/mcp.d.ts +4 -0
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/plugins.js +1 -1
- package/dist/routes/pty.d.ts +11 -3
- package/dist/routes/pty.js +3 -3
- package/dist/routes/runtime-binding.js +1 -1
- package/dist/routes/sessions.js +1 -1
- package/dist/routes/skills.js +1 -1
- package/dist/routes/sub-agents.js +8 -8
- package/dist/routes/terminal.d.ts +16 -2
- package/dist/routes/terminal.js +34 -36
- package/dist/services/agent-process-manager.js +1 -1
- package/dist/services/agent-pty-manager.js +4 -4
- package/dist/services/aws-client-agent-mcp.js +2 -2
- package/dist/services/capability-config.d.ts +8 -0
- package/dist/services/capability-config.js +2 -2
- package/dist/services/desktop-mcp-manager.d.ts +3 -1
- package/dist/services/desktop-mcp-manager.js +1 -1
- package/dist/services/instance-ai-config-service.js +1 -1
- package/dist/services/instance-features.d.ts +10 -0
- package/dist/services/instance-features.js +1 -1
- package/dist/services/instance-init-service.js +1 -1
- package/dist/services/launch-manager.d.ts +9 -1
- package/dist/services/launch-manager.js +6 -6
- package/dist/services/launch-metrics.d.ts +1 -1
- package/dist/services/launch-metrics.js +4 -3
- package/dist/services/mcp-deploy.d.ts +4 -0
- package/dist/services/mcp-env-injector.d.ts +12 -0
- package/dist/services/mcp-env-injector.js +2 -0
- package/dist/services/mcp-launch-binding-queue.d.ts +8 -0
- package/dist/services/mcp-launch-binding-queue.js +1 -1
- package/dist/services/orphan-monitor.js +1 -1
- package/dist/services/panel-env.d.ts +6 -2
- package/dist/services/panel-env.js +1 -1
- package/dist/services/plugin-manager.js +9 -9
- package/dist/services/process-detector.d.ts +23 -3
- package/dist/services/process-detector.js +13 -13
- package/dist/services/runtime-resources-snapshot.d.ts +3 -0
- package/dist/services/runtime-resources-snapshot.js +3 -0
- package/dist/services/session-output.d.ts +13 -0
- package/dist/services/session-output.js +4 -4
- package/dist/services/tunnel-client.js +1 -1
- package/dist/services/workspace-files.js +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/utils/env-safety.d.ts +15 -0
- package/dist/utils/env-safety.js +2 -0
- package/dist/utils/lifecycle-log.d.ts +2 -0
- package/dist/utils/lifecycle-log.js +3 -0
- package/dist/utils/mcp-utils.js +1 -1
- package/package/acode/dist/background-command-manager.js +4 -4
- package/package/acode/dist/built-in-file-tools.d.ts +13 -0
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/builtins/shellCommandPreparation.d.ts +2 -0
- package/package/acode/dist/builtins/shellCommandPreparation.js +2 -2
- package/package/acode/dist/compaction.d.ts +10 -0
- package/package/acode/dist/compaction.js +6 -6
- package/package/acode/dist/context-overflow.js +1 -1
- package/package/acode/dist/index.d.ts +1 -0
- package/package/acode/dist/index.js +1 -1
- package/package/acode/dist/mcpToolNames.d.ts +4 -0
- package/package/acode/dist/mcpToolNames.js +1 -1
- package/package/acode/dist/runtime-environment.d.ts +2 -0
- package/package/acode/dist/runtime-environment.js +3 -2
- package/package/acode/dist/runtime.d.ts +68 -8
- package/package/acode/dist/runtime.js +28 -27
- package/package/acode/dist/sub-agent-manager.js +1 -1
- package/package/acode/dist/tool-allocation.js +1 -1
- package/package/acode/dist/tool-group-manager.d.ts +12 -0
- package/package/acode/dist/tool-group-manager.js +8 -4
- package/package/acode/dist/types.d.ts +8 -0
- package/package/acode/package.json +1 -1
- package/package/aws-client-agent-mcp/README.md +1 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +22 -8
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
- package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -1
- package/package/aws-client-agent-mcp/dist/logger.js +2 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +19 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.js +18 -18
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +15 -4
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +79 -29
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/memory-store.js +3 -3
- package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
- package/package/aws-client-agent-mcp/dist/office/office-workspace.d.ts +15 -0
- package/package/aws-client-agent-mcp/dist/office/office-workspace.js +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
- package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +4 -0
- package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
- package/package/aws-client-agent-mcp/dist/types.d.ts +52 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
- package/package/aws-client-agent-mcp/package.json +1 -1
- package/package.json +1 -1
|
@@ -1,39 +1,40 @@
|
|
|
1
|
-
import{EventEmitter as
|
|
2
|
-
`;
|
|
3
|
-
`)}return JSON.stringify(n)}function ue(n){return n instanceof Error?n.message:String(n)}function
|
|
4
|
-
${
|
|
5
|
-
${
|
|
6
|
-
`)}function
|
|
7
|
-
`)}function Xe(n){return n.map(e=>({type:"function",function:{name:e.exposedName,description:e.description||e.toolName,parameters:e.inputSchema}}))}function Fo(n,e){return`${n}__${e}`.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,64)||"mcp_tool"}function zo(n){const e={"Content-Type":"application/json"};return n.apiKey&&(e.Authorization=`Bearer ${n.apiKey}`),e}function jo(n){return Object.fromEntries(Object.entries(n).map(([e,t])=>[e,Wo(e)?Jo(t):t]))}function Wo(n){const e=n.trim().toLowerCase();return e==="authorization"||e==="api-key"||e==="x-api-key"||e==="openai-api-key"}function Jo(n){return n.trim().toLowerCase().startsWith("bearer ")?"Bearer ***":"***"}function Go(n){return n.split(/\r?\n/).filter(e=>e.startsWith("data:")).map(e=>e.slice(5).trim()).filter(Boolean)}function Ze(n){if(!$(n))return null;const e=n.error;if($(e)){const t=typeof e.message=="string"?e.message:"",o=e.code??e.status??e.type,s=o==null?"":String(o);return t||s?[s,t].filter(Boolean).join(" "):null}if(typeof e=="string"&&e)return e;if(n.type==="error"||n.object==="error"){const t=typeof n.message=="string"?n.message:"",o=n.code??n.status,s=o==null?"":String(o);if(t||s)return[s,t].filter(Boolean).join(" ")}return null}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 Ho(n){return[...n.entries()].sort(([e],[t])=>e-t).map(([,e])=>e).filter(e=>e.function.name.trim().length>0)}function Qo(){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 K extends ot{constructor(e){super(),this.config=e,this.initialConversation=[],this.state={started:!1,terminated:!1,configMcpCount:0,skills:[],provider:{model:"acode-default",stream:!1,requestTimeoutMs:De,requestTotalTimeoutMs:Le,requestRetryCount:qe,requestFirstByteTimeoutMs:Ue,requestStreamIdleTimeoutMs:Be,mcpToolTimeoutMs:ie,mcpPollingToolTimeoutMs:Fe,supportsImageInput:!1},permissions:{mode:"default",allow:[],deny:[]},mcpConnections:[],ownsMcpConnections:!0,exposedTools:[],commands:[],commandRegistry:new we([]),conversation:[],accumulatedInputTokens:0,accumulatedOutputTokens:0,accumulatedCacheHitTokens:0,accumulatedCacheMissTokens:0,skipNextCompaction:!1,toolPermissionPolicy:{...be}},this.abortController=null,this.exposedToolsInitialized=!1,this.recoveredToolNames=new Set,this.readFileStateTracker=new ut,this.pendingMemorySubAgents=new Map,this.memoryDelegateCooldownUntil=new Map,this.toolGroupManager=null,this.submitQueue=Promise.resolve(),this.activeTurnToken=null,this.forceSettleWaiters=new Map,this.abortForceSettleTimer=null,this.activeTurn=!1,this.forceMessagePending=!1,this.turnPromptPushed=!1,this.turnSkipProactiveCompaction=!1,this.abortRequested=!1,this.toolSettleSlots=new Map,this.toolSettleSeq=0,this.toolResourceLock=Dt(),this.toolConcurrencyScheduler=new Lt,this.toolReadOnlyLimiter=null,this.toolBashLimiter=null,this.toolConcurrencyEnabled=!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.permissionWaiters=new Map,this.hookBus=new Rt({sessionId:e.sessionId,onError:(i,a)=>{this.emitAcodeEvent("error",{message:`ACode hook failed: ${i.name}: ${a instanceof Error?a.message:String(a)}`})}});for(const i of e.hooks??[])this.hookBus.register(i);e.toolPermissionPolicy&&(this.state.toolPermissionPolicy={...be,...e.toolPermissionPolicy});const t=e.toolConcurrency;this.toolConcurrencyEnabled=t?.enabled!==!1;const o=t?.maxReadOnly??8;this.toolReadOnlyLimiter=new Ie(o);const s=t?.maxBash??0;this.toolBashLimiter=s>0?new Ie(s):null}getAvailableTools(){return this.state.exposedTools.map(e=>e.exposedName)}emitAcodeEvent(e,t){const o={type:e,sessionId:this.config.sessionId,timestamp:Wt(),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 xt(this.config.configPath);this.emitAcodeEvent("startup_phase",{phase:"loading_skills"});const{skills:t,skillGroups:o,watchedDirs:s}=await this.loadAllSkills(),i=io(this.config,e);d(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 resolveProviderConfig \u7ED3\u679C: config.model=${this.config.model??"(undefined)"}, resolvedModel=${i.model}, baseURL=${i.baseURL??"(none)"}, apiKey=${i.apiKey?"[set]":"(none)"}, configPath=${this.config.configPath??"(none)"}`);const a=Co(this.config,e),r=this.config.sharedMcpConnections?this.filterSharedMcpConnectionsForSubAgent(this.config.sharedMcpConnections):await this.connectMcpServers(e.mcpServers??{},i.mcpToolTimeoutMs),l=!this.config.sharedMcpConnections;this.emitAcodeEvent("startup_phase",{phase:"fetching_profile"});const c=await this.fetchProfilePrompt(r),u=this.config.agentId||"unknown";yt(u),Y.reconcileOrphans(u);const m=ct(this.config.workingDirectory,u,this.config.onFileChange,{manager:Y,emitCompleted:g=>{this.emitAcodeEvent("background_command_completed",g)}},this.createToolPermissionController(),{tracker:this.readFileStateTracker,enabled:this.config.enableStaleFileGuard!==!1}),h=dt(this.buildAskUserQuestionDeps(),()=>this.contextVersion),A=pt(t);this.skillTool=A;const f=ht(u),p=ft(u),k=this.config.subAgentManager?gt(this.buildSubAgentToolDeps(this.config.subAgentManager)):[],T=Tt(this.buildAwaitCompleteDeps()),y=this.config.terminalManager?At(u,{terminalManager:this.config.terminalManager}):null,_=new _t({stateOf:this.config.capabilityState??(()=>"disabled")});_.register({key:"pencil",label:"\u8BBE\u8BA1\u753B\u5E03(pencil)",summary:"UI design editor",collapsible:!0}),_.register({key:"draw",label:"\u7ED8\u56FE",summary:"\u7ED8\u5236 draw.io \u6D41\u7A0B\u56FE/\u6CF3\u9053\u56FE",collapsible:!0}),_.register({key:"office",label:"Office \u6587\u4EF6",summary:"\u521B\u5EFA/\u7F16\u8F91 Word/PPT/Excel",collapsible:!0}),_.register({key:"launch",label:"\u542F\u52A8\u9879\u7BA1\u7406",summary:"\u7BA1\u7406\u5F00\u53D1\u670D\u52A1\u8FDB\u7A0B",collapsible:!0}),_.register({key:"hire",label:"\u62DB\u8058\u5DE5\u5177",summary:"\u62DB\u8058\u65B0\u7684\u540C\u4E8B Agent",collapsible:!0}),_.register({key:"browser",label:"\u6D4F\u89C8\u5668\u64CD\u4F5C",summary:"\u542F\u52A8\u6D4F\u89C8\u5668\u4F1A\u8BDD\u3001\u5BFC\u822A\u3001\u622A\u56FE\u4E0E\u9875\u9762\u4EA4\u4E92",collapsible:!0}),_.register({key:"desktop",label:"\u684C\u9762\u64CD\u4F5C",summary:"\u622A\u5C4F\u3001\u9F20\u6807\u952E\u76D8\u63A7\u5236\u4E0E UI \u81EA\u52A8\u5316",collapsible:!1}),_.register({key:"task",label:"\u6D41\u7A0B\u4EFB\u52A1",summary:"\u5904\u7406\u6D41\u7A0B\u7EBF\u4EFB\u52A1\uFF1A\u67E5\u770B\u5F53\u524D\u4EFB\u52A1\u3001\u63D0\u4EA4\u6267\u884C\u7ED3\u679C\u3001\u62D2\u7EDD/\u7EC8\u6B62/\u56DE\u9000\u4EFB\u52A1\u3001\u7ED9\u6D41\u7A0B\u5B9E\u4F8B\u7559\u8A00",collapsible:!0,toolNames:["my_task","submit_task_result","reject_task","terminate_task","start_task_rollback","finish_task_rollback","create_task_instance_comment"]}),_.register({key:"meeting",label:"\u4F1A\u8BAE",summary:"\u521B\u5EFA/\u52A0\u5165\u4F1A\u8BAE\u3001\u53D1\u8A00\u3001\u67E5\u770B\u4F1A\u8BAE\u4FE1\u606F\u3001\u79BB\u5F00/\u7ED3\u675F\u4F1A\u8BAE",collapsible:!0,toolNames:["create_meeting","leave_meeting","end_meeting","meeting_speak","get_meeting_info","my_meetings"]}),_.register({key:"debug",label:"\u8C03\u8BD5\u65E5\u5FD7",summary:"\u6309\u6761\u4EF6\u5206\u9875\u67E5\u8BE2 Debug \u65E5\u5FD7\u4E0E\u83B7\u53D6\u65E5\u5FD7\u4E0A\u62A5\u914D\u7F6E",collapsible:!0,toolNames:["get_debug_log_config","query_debug_logs"]}),_.register({key:"fileHistory",label:"\u6587\u4EF6\u53D8\u66F4\u5386\u53F2",summary:"\u6309\u89D2\u8272/\u5B9E\u4F8B/\u6587\u4EF6\u8DEF\u5F84\u8FC7\u6EE4\u67E5\u8BE2\u6587\u4EF6\u53D8\u66F4\u5386\u53F2",collapsible:!0,toolNames:["query_file_changes_history"]}),this.toolGroupManager=_;const R=bt({toolGroupManager:_,getAllTools:()=>this.state.exposedTools,capabilityToolRelay:this.config.capabilityToolRelay}),x=wt({toolGroupManager:_,pluginBridge:this.config.pluginBridge,capabilityToolRelay:this.config.capabilityToolRelay,findTool:g=>{const O=this.state.exposedTools.find(Ae=>Ae.exposedName===g||Ae.toolName===g);if(!O)return;const de=_.getGroupForExposedName(O.exposedName);return{kind:O.kind,group:de,toolName:O.toolName}},dispatchTool:(g,O,de)=>this.executeSingleToolByName(g,O,de)}),S=[...m,h,A,f,p,...k,T,...y?[y]:[],R,x,...r.flatMap(g=>g.tools),...Re(this.config.extraBuiltInTools??[],this.config.agentId??"")];if(this.config.subAgentAllowedTools&&this.config.subAgentAllowedTools.length>0){const g=Re(this.config.subAgentSuiteTools??[],this.config.agentId??""),O=ne(S,g);S.length=0,S.push(...O)}let C=S;const b=this.config.subAgentAllowedTools;b&&b.length>0&&(C=C.filter(g=>Ee(g,b)));const M=this.resolveCommandDirs(e);let v=[...M,...this.discoverPluginCommandDirs()];if(this.config.pluginBridge?.getCommandDirs)try{const g=await this.config.pluginBridge.getCommandDirs();g.length>0&&(v=[...v,...g])}catch(g){d(`[ACodeRuntime] \u63D2\u4EF6\u547D\u4EE4\u76EE\u5F55\u83B7\u53D6\u5931\u8D25\uFF08\u5FFD\u7565\uFF09: ${g instanceof Error?g.message:String(g)}`)}v=[...new Set(v)],this.emitAcodeEvent("startup_phase",{phase:"loading_commands"});const w=await kt(v),q=new we(w),N=Uo(t),H=Bo(w),F=_.buildCapabilityPrompt(),ee=this.config.pluginBridge?["","## \u63D2\u4EF6\u7CFB\u7EDF","\u63D2\u4EF6\u5DE5\u5177\u4E0D\u5728\u4F60\u7684\u9759\u6001\u5DE5\u5177\u5217\u8868\u4E2D\uFF1A\u7D27\u51D1\u76EE\u5F55\u968F poll_message \u7ED3\u679C\u7684 pluginCatalog \u5B57\u6BB5\u8FD4\u56DE\uFF1B",'\u7528 call_tool \u8C03\u7528\uFF08action="catalog" \u53D6\u76EE\u5F55\uFF0Caction="schema" \u53D6\u5B9A\u4E49\uFF0C','\u6216 action="call"\uFF08\u9ED8\u8BA4\uFF09+ name="\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D" + arguments={...} \u8C03\u7528\uFF09\u3002',"\u63D2\u4EF6\u4E8B\u4EF6\u5C3E\u90E8\u6709 toolHints\uFF08\u5EFA\u8BAE\u8C03\u7528\u7684\u5DE5\u5177\uFF09\uFF0C\u6309\u63D0\u793A\u7528 call_tool \u5904\u7406\u3002","\u63D2\u4EF6\u751F\u547D\u5468\u671F\uFF08\u5B89\u88C5/\u5378\u8F7D/\u91CD\u8F7D/\u542F\u505C/\u5217\u8868\uFF09\u4E5F\u662F\u63D2\u4EF6\u5DE5\u5177\uFF1A",'\u7ECF call_tool \u8C03\u7528 plugin-manager.manage\uFF0C\u5373 call_tool({name: "plugin-manager.manage", arguments:{action:"...", ...}})\u3002',"\u672A\u7ECF\u7528\u6237\u660E\u786E\u8981\u6C42\u4E0D\u8981\u5B89\u88C5\u6216\u5378\u8F7D\u63D2\u4EF6\u3002"].join(`
|
|
8
|
-
`):"",
|
|
1
|
+
import{EventEmitter as ft}from"node:events";import{randomUUID as gt}from"node:crypto";import B from"node:fs";import Ie from"node:os";import z from"node:path";import{Client as Tt}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as yt}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as Ct}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as _t}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{ToolListChangedNotificationSchema as At}from"@modelcontextprotocol/sdk/types.js";import{createBuiltInFileTools as bt,DEFAULT_TOOL_PERMISSION_POLICY as Ne,getEditFailureSnapshot as wt}from"./built-in-file-tools.js";import{ReadFileStateTracker as kt}from"./read-file-state.js";import{ASK_USER_QUESTION_TOOL_NAME as St,createAskUserQuestionTool as Mt}from"./ask-user-question-tool.js";import{createSkillTool as $t}from"./skill-tool.js";import{createTodoWriteTool as vt,createTodoReadTool as Et}from"./todo-tool.js";import{createSubAgentTools as xt}from"./sub-agent-tools.js";import{createAwaitCompleteTool as Rt}from"./await-complete-tool.js";import{cleanupAcodeCmdDist as It}from"./builtins/commandArtifacts.js";import{buildRuntimeEnvironmentPrompt as Nt}from"./runtime-environment.js";import{resolveAcodeHome as Pt}from"./paths.js";import{backgroundCommandManager as ie}from"./background-command-manager.js";import{createTerminalTool as Ot}from"./terminal-tool.js";import{ToolGroupManager as Dt,createExpandToolsTool as Lt,createCallToolTool as Bt,mcpGroupKeyOf as Ut}from"./tool-group-manager.js";import{loadAcodeCommands as qt}from"./commands/commandLoader.js";import{ACodeCommandRegistry as Pe}from"./commands/commandRegistry.js";import{calculateCompactionThreshold as Ft,COMPACTION_LLM_PROMPT_TEMPLATE as zt,conversationSizeBytes as Oe,conversationSizeKB as Y,estimateConversationTokens as j,isCompactionSummaryMessage as jt,isRuntimeResourcesMessage as Wt,performCompaction as Ae,resolveReplayWindow as Gt,pruneToolOutputs as Jt,RUNTIME_RESOURCES_PREFIX as Ht,summarizeConversation as De}from"./compaction.js";import{isContextOverflowError as be,resolveFinishReasonOverflow as Kt}from"./context-overflow.js";import{loadAcodeConfig as Yt,loadAcodeSkillGroup as Qt}from"./config.js";import{ACodeHookBus as Vt,findDeniedHookResult as Le}from"./hooks/hookBus.js";import{isMcpPollingToolName as Be,isMcpBlockingToolName as we,isMcpBatchExcludedToolName as ke,isMcpIndefinitelyBlockingToolName as Xt,getSemanticToolName as Se}from"./mcpToolNames.js";import{runtimeMeetingDebugLog as U}from"./meeting-debug-log.js";import{buildToolCatalog as Ue,matchesToolAllocation as qe,mergeAllocatableTools as de,PRESET_EXPLORE as Zt,rebindDefaultAgentId as Fe,resolveToolAllocation as eo,SUB_AGENT_ALLOWED_MCP_TOOLS as to}from"./tool-allocation.js";import{ConcurrencyLimiter as ze,getSharedResourceLock as oo,ToolConcurrencyScheduler as so,ToolTraceRecorder as je}from"./tool-concurrency/index.js";function no(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 io(n){return n.type==="text"?{type:"text",text:n.text}:{type:"image_url",image_url:{url:n.image_url.url}}}function ro(n){return{id:n.id,type:"function",function:{name:n.function.name,arguments:n.function.arguments}}}function ao(n){const e={role:n.role,content:Array.isArray(n.content)?n.content.map(io):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(ro)),e}function re(n){return n.map(ao)}function lo(n,e){const t=W(n.prompt_cache_hit_tokens),o=W(n.prompt_cache_miss_tokens);if(t!==void 0||o!==void 0)return{cacheHitTokens:t??0,cacheMissTokens:o??0};const s=W(n.cache_read_input_tokens),r=W(n.cache_creation_input_tokens);if(s!==void 0||r!==void 0){const u=s??0,c=r??0,m=W(n.input_tokens)??(e!==void 0?Math.max(0,e-u-c):0);return{cacheHitTokens:u,cacheMissTokens:c+m}}const i=W(n.cache_hit_tokens),a=W(n.cache_miss_tokens);if(i!==void 0||a!==void 0)return{cacheHitTokens:i??0,cacheMissTokens:a??0};const l=W(n.prompt_tokens_details?.cached_tokens);if(l!==void 0){const u=e!==void 0?Math.max(0,e-l):0;return{cacheHitTokens:l,cacheMissTokens:u}}}function W(n){const e=typeof n=="number"?n:typeof n=="string"&&n.trim()?Number(n):NaN;if(!(!Number.isFinite(e)||e<0))return e}function co(n,e){if(!n)return e;const t=o=>{const s=e[o],r=n[o];return o==="prompt_tokens_details"?{...r,...s}:s??r};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 uo(){return new Date().toISOString()}function S(n){return!!(n&&typeof n=="object"&&!Array.isArray(n))}function pe(n){return S(n)}function We(n,e){return e.map(t=>({serverName:n,toolName:t.name,kind:"mcp",exposedName:ms(n,t.name),description:t.description,inputSchema:pe(t.inputSchema)?t.inputSchema:{type:"object",properties:{}}}))}const he="ACODE_TOOL_GROUPS_V1:";function mo(n){const e=String(n??"").trim();if(!e.startsWith(he))return[];const t=e.slice(he.length).trim();if(!t)return[];let o;try{o=JSON.parse(t)}catch{return[]}if(!pe(o)||!Array.isArray(o.groups))return[];const s=[];for(const r of o.groups){if(!pe(r))continue;const i=typeof r.key=="string"?r.key.trim():"";if(!i)continue;const a=Array.isArray(r.toolNames)?r.toolNames.filter(l=>typeof l=="string"&&l.length>0):[];s.push({key:i,label:typeof r.label=="string"&&r.label.trim()?r.label:i,toolNames:a})}return s}function po(n){const e=String(n??"").trim();if(!e)return;if(!e.startsWith(he))return e;const t=e.slice(he.length).trim();return t.startsWith("{")?void 0:t||void 0}function O(n){return String(n??"").trim()||void 0}const Ge=6e4,Je=30*6e4,He=6e4,Ke=6e4,Me=-1,Ye=0,ho=1e3,fo=3e4,fe=6e4,Qe=0,go=2147483647,To=8,yo=10*6e4+2e3,Co=1e4,ge=5e3,Ve=10*60*1e3,ee=10*1024*1024,Xe=800*1024,Ze=32*1024*1024,_o=4,Ao=1.25;function et(){const n=Number.parseInt(String(process.env.ACODE_MAX_REQUEST_BODY_BYTES??"").trim(),10);return Number.isFinite(n)&&n>0?n:void 0}function bo(){return et()!==void 0}function wo(n){const e=et();if(e!==void 0)return e;if(!Number.isFinite(n)||n<=0)return Xe;const t=Math.floor(n*_o*Ao);return Math.min(Ze,Math.max(Xe,t))}const Te=process.env.ACODE_COMPACTION_DEBUG==="1",tt=Te?z.join(Ie.tmpdir(),"acode-compaction-debug.log"):"";function p(...n){Te&&console.log(...n)}const ko=process.env.ACODE_IMAGE_DIAG==="1",So=process.env.ACODE_IMAGE_DIAG_LOG||z.join(Ie.tmpdir(),"acode-image-inject.log");function ye(n){if(!ko)return;const e=`[${new Date().toISOString()}] ${JSON.stringify(n)}
|
|
2
|
+
`;B.promises.appendFile(So,e).catch(()=>{})}const Mo=process.env.ACODE_TOKEN_DEBUG==="1";function te(...n){Mo&&console.log("[TokenDebug][Runtime]",...n)}const $o=64e3;function Ce(n){const e=n.contextLimit&&n.contextLimit>0?n.contextLimit:$o,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 R(n,e,t,o){if(e<=0)return await n;let s;try{return await new Promise((r,i)=>{s=setTimeout(()=>{o?.(),i(new Error(`${t} timed out after ${e}ms`))},e),n.then(r,i)})}finally{s&&clearTimeout(s)}}function ot(){return`toolbatch-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}async function ae(n,e,t,o=Co){try{await R(e,o,n)}catch(s){t(s instanceof Error?s.message:String(s))}}function oe(n,e){if(n===0||n==="0")return 0;const t=typeof n=="number"?n:Number(n);return t===Me?Me:Number.isFinite(t)&&t>0?Math.floor(t):e}function le(n,e){const t=oe(n,e);return t>0?t:e}const st=3;function $e(n){return n?Math.ceil(n.length/st):0}function vo(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 r=o;r.inputSchema&&(t+=JSON.stringify(r.inputSchema).length)}}return Math.ceil(t/st)}function ce(n){if(n.length===0)return 0;const e=JSON.stringify(mt(n));return $e(e)}async function Eo(n){await new Promise(e=>setTimeout(e,n))}function xo(n){return typeof n=="boolean"}function Ro(n,e,t){if(xo(t?.supportsImageInput))return t.supportsImageInput;const o=S(e)?e.models:void 0,s=S(o)?o[n]:void 0;if(!S(s))return!1;const r=s.modalities;return!S(r)||!Array.isArray(r.input)?!1:r.input.some(i=>String(i||"").trim().toLowerCase()==="image")}function ve(n,e,t,o){if(n!==void 0)return n;if(!e)return;const s=e.models;if(S(s)){const r=s[t];if(S(r)){const i=r[o];if(i!==void 0)return i}}return e[o]}function Io(n,e){const t=e.provider?.default,o=t?.options,s=n.model||t?.model||e.model||"acode-default",r=O(n.effort)||O(o?.effort)||O(t?.effort)||void 0;return{model:s,baseURL:O(o?.baseURL||o?.baseUrl),apiKey:O(o?.apiKey),effort:r,systemPrompt:n.systemPrompt||e.systemPrompt,stream:o?.stream!==!1,requestTimeoutMs:le(o?.requestTimeoutMs??o?.timeoutMs,Ge),requestTotalTimeoutMs:le(o?.requestTotalTimeoutMs,Je),requestRetryCount:oe(o?.requestRetryCount,Ye),requestFirstByteTimeoutMs:le(o?.requestFirstByteTimeoutMs,He),requestStreamIdleTimeoutMs:le(o?.requestStreamIdleTimeoutMs,Ke),mcpToolTimeoutMs:le(o?.mcpToolTimeoutMs,fe),mcpPollingToolTimeoutMs:oe(o?.mcpPollingToolTimeoutMs,Qe),supportsImageInput:Ro(s,t,o),contextLimit:oe(ve(o?.contextLimit,t,s,"contextLimit"),0)||void 0,inputLimit:oe(ve(o?.inputLimit,t,s,"inputLimit"),0)||void 0,maxOutput:oe(ve(o?.maxOutput,t,s,"maxOutput"),0)||void 0}}function K(n,e){const t=e.replace(/\s+/g," ").trim();t&&n.push({type:"text",text:t})}function No(n,e){const t=e.trim();return/^data:image\/[a-z0-9.+-]+;base64,/i.test(t)?t:`data:${n||"image/png"};base64,${t}`}function Po(n){return/^data:image\/[a-z0-9.+-]+;base64,/i.test(n.trim())}function Oo(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 Do(n){const e=await n.arrayBuffer();if(e.byteLength>ee)throw new Error(`ACode image is too large to inline: ${e.byteLength} bytes exceeds ${ee} bytes`);return Buffer.from(e).toString("base64")}async function Lo(n){const e=n.trim();if(Po(e)){if(e.slice(e.indexOf(",")+1).length*.75>ee)throw new Error(`ACode inline image exceeds the ${ee} byte size limit`);return e}Oo(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 Do(t)}`}function Bo(n){const e=O(n.base64Data??n.base64??n.data);return e?e.length*.75>ee?void 0:No(O(n.mediaType??n.mimeType)||"image/png",e):O(n.url??n.serverUrl)}function nt(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(r=>!!r).join(", ")}]`}function Uo(n){const e=/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,t=[];let o=!1,s=0,r=e.exec(n);for(;r!==null;){K(t,n.slice(s,r.index));const i=r[1],a=(r[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[l="",u="",c="",m=""]=a.split("|").map(h=>h.trim());K(t,nt(l,u,c,m))}else K(t,r[0]);s=r.index+r[0].length,r=e.exec(n)}return t.length===0?{content:n,hasImages:!1}:(K(t,n.slice(s)),{content:t,hasImages:o})}function qo(n,e){let t=!1;const o=[e.directMessages,e.groupMessages];for(const s of o)if(Array.isArray(s))for(const r of s){if(!S(r))continue;const i=O(r.content);if(!i)continue;const a=O(r.senderName);K(n,a?`Message from ${a}:`:"Message:");const l=Ee(i);Array.isArray(l.content)?n.push(...l.content):K(n,l.content),t=t||l.hasImages}return t}function Fo(n){for(const e of["directMessages","groupMessages","messages"]){const t=n[e];if(Array.isArray(t))for(const o of t){if(!S(o))continue;const s=o.content;typeof s!="string"||!s.trim()||(o.content=zo(s))}}}function zo(n){let e;try{e=JSON.parse(n)}catch{return n.replace(/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,"").trim()||n}if(S(e)&&"attachments"in e){const t={...e};return t.attachments=[],JSON.stringify(t)}return n}function jo(n){let e;try{e=JSON.parse(n)}catch{return}if(!S(e))return;const t=[];let o=qo(t,e);const s=O(e.text)||"",r=Array.isArray(e.attachments)?e.attachments:[];K(t,s);for(const i of r){if(!S(i))continue;const a=i;if(String(a.type??a.kind??"").toLowerCase()==="image"){const c=Bo(a);c?(t.push({type:"image_url",image_url:{url:c}}),o=!0):O(a.base64Data??a.base64??a.data)&&K(t,`[Image attachment omitted: ${O(a.name)||"unnamed"} exceeds the ${ee} byte inline limit]`);continue}const u=O(a.url??a.serverUrl)||"";K(t,nt(O(a.name)||"",u,O(a.mediaType??a.mimeType)||"",O(a.size)||""))}return t.length===0?{content:n,hasImages:!1}:{content:t,hasImages:o}}function Ee(n){return jo(n)??Uo(n)}async function it(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 Lo(t.image_url.url)}})}return e}function Wo(n){return typeof n=="string"?n:Array.isArray(n)?n.map(e=>e.type==="text"?e.text:"[Image]").join(" ").trim():""}function Go(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(r=>r.trim()).filter(Boolean),deny:[...t.deny??[],...s].map(r=>r.trim()).filter(Boolean)}}function Jo(n,e){return n==="*"?!0:n.endsWith("*")?e.startsWith(n.slice(0,-1)):n===e}function Ho(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 rt(n,e){return Ho(e).some(t=>Jo(n,t))}function at(n,e,t){if(e.length>0&&!e.some(o=>rt(o,n)))throw new Error(t)}function lt(n,e,t){if(e.mode!=="bypassPermissions"){if(e.deny.some(o=>rt(o,n)))throw new Error(`ACode tool denied by permission rule: ${n.exposedName}`);at(n,e.allow,`ACode tool is not in allowed permission rules: ${n.exposedName}`),at(n,t??[],`ACode slash command does not allow tool: ${n.exposedName}`)}}function Ko(n,e,t){try{return lt(n,e,t),!0}catch{return!1}}function _e(n){const e=n.replace(/\/+$/g,"");return/\/chat\/completions$/i.test(e)?e:`${e}/chat/completions`}function Yo(n){try{const e=new URL(n);e.search="",e.hash="";const t=new URL(_e(e.toString()));return`${t.origin}${t.pathname}`}catch{return _e(n).replace(/([?&](?:api[_-]?key|token|authorization)=)[^&]+/gi,"$1[redacted]")}}function Qo(n){const e=[...n].reverse().find(o=>o.role==="user"),t=Wo(e?.content??null).trim();if(t)return t.length>300?`${t.slice(0,300)}...`:t}function Vo(n){try{const e=JSON.parse(n);return pe(e)?e:{}}catch{return{}}}function Xo(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,r=typeof s=="number"?s:typeof s=="string"?Number(s):NaN;return!Number.isFinite(r)||r<=0?Math.max(t,yo):Math.min(Math.floor(r),10*6e4)+2e3}function Zo(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 G(n){if(!S(n))return String(n??"");const e=n.content;if(Array.isArray(e)){const t=e.map(o=>S(o)?typeof o.text=="string"?o.text:JSON.stringify(o):"").filter(Boolean);if(t.length>0)return t.join(`
|
|
3
|
+
`)}return JSON.stringify(n)}function ue(n){return n instanceof Error?n.message:String(n)}function es(n){const e={orphanToolMessages:0,repairedToolCalls:0,downgradedAssistants:0,relocatedInterruptions:0,reorderedToolResults:0};if(n.length===0)return e;const t=(c,m)=>{const h=typeof c.content=="string"?c.content:JSON.stringify(c.content??"");c.role="user",delete c.tool_call_id,c.content=`[\u7CFB\u7EDF\u63D0\u793A] \u4EE5\u4E0B\u4E3A\u4E00\u6B21\u5DE5\u5177\u6267\u884C\u7684\u7ED3\u679C\uFF08tool_call_id=${m}\uFF09\uFF0C\u5176\u5BF9\u5E94\u7684\u5DE5\u5177\u8C03\u7528\u4E0A\u4E0B\u6587\u5DF2\u4E0D\u5728\u4F1A\u8BDD\u4E2D\uFF0C\u4EC5\u4F9B\u53C2\u8003\uFF1A
|
|
4
|
+
${h}`,e.orphanToolMessages+=1},o=c=>{const m=new Map;for(const y of n)if(y.role==="assistant"&&Array.isArray(y.tool_calls))for(const C of y.tool_calls){const d=typeof C?.id=="string"?C.id:"";d&&!m.has(d)&&m.set(d,y)}const h=new Set;for(const y of n){if(y.role==="assistant"&&Array.isArray(y.tool_calls)){for(const f of y.tool_calls){const g=typeof f?.id=="string"?f.id:"";g&&h.add(g)}continue}if(y.role!=="tool")continue;const C=typeof y.tool_call_id=="string"?y.tool_call_id.trim():"";if(!C){t(y,"(\u7F3A\u5931)");continue}if(h.has(C))continue;const d=m.get(C);if(d){c.push({message:y,id:C,assistant:d});continue}t(y,C)}},s=c=>{if(c.length!==0){for(const m of c){const h=n.indexOf(m.message);h>=0&&n.splice(h,1)}for(const m of c){const h=n.indexOf(m.assistant);if(h<0){t(m.message,m.id);continue}let y=h+1;for(;y<n.length&&n[y].role==="tool";)y+=1;n.splice(y,0,m.message),e.reorderedToolResults+=1}}},r=[];o(r),s(r);const i=()=>{const c=new Set;for(const m of n)m.role==="tool"&&m.tool_call_id&&c.add(m.tool_call_id);return c};let a=i();const l="\uFF08\u8BE5\u5DE5\u5177\u8C03\u7528\u7ED3\u679C\u7F3A\u5931\uFF1A\u6240\u5C5E\u8F6E\u6B21\u88AB\u4E2D\u65AD\u6216\u4E0A\u4E0B\u6587\u538B\u7F29\u65F6\u5DF2\u79FB\u9664\uFF0C\u8BF7\u52FF\u57FA\u4E8E\u8BE5\u8C03\u7528\u7EE7\u7EED\u63A8\u65AD\uFF0C\u5FC5\u8981\u65F6\u91CD\u65B0\u8C03\u7528\u5DE5\u5177\u3002\uFF09";for(let c=0;c<n.length;c++){const m=n[c];if(m.role!=="assistant"||!Array.isArray(m.tool_calls))continue;const h=m.tool_calls.filter(f=>typeof f?.id=="string"&&f.id.trim().length>0);if(h.length!==m.tool_calls.length){if(e.downgradedAssistants+=1,h.length===0){delete m.tool_calls,(m.content===null||m.content===void 0)&&(m.content="");continue}m.tool_calls=h}const y=m.tool_calls.map(f=>f?.id).filter(f=>typeof f=="string"&&f.length>0&&!a.has(f));if(y.length===0)continue;let C=-1;for(let f=c+1;f<n.length;f++){if(n[f].role==="tool"){C=f+1;continue}break}if(C>c){const f=y.map(g=>({role:"tool",tool_call_id:g,content:l}));n.splice(C,0,...f),c+=f.length,e.repairedToolCalls+=y.length,a=i();continue}if(c===n.length-1){for(const f of y)n.push({role:"tool",tool_call_id:f,content:l});e.repairedToolCalls+=y.length,a=i();continue}const d=new Set(m.tool_calls.map(f=>f?.id).filter(f=>typeof f=="string"&&f.length>0));delete m.tool_calls,(m.content===null||m.content===void 0)&&(m.content="");for(const f of n)if(f.role==="tool"&&f.tool_call_id&&d.has(f.tool_call_id)){const g=typeof f.content=="string"?f.content:JSON.stringify(f.content??""),T=f.tool_call_id;f.role="user",delete f.tool_call_id,f.content=`[\u7CFB\u7EDF\u63D0\u793A] \u4EE5\u4E0B\u4E3A\u4E00\u6B21\u5DE5\u5177\u6267\u884C\u7684\u7ED3\u679C\uFF08tool_call_id=${T}\uFF09\uFF0C\u5176\u5BF9\u5E94\u7684\u5DE5\u5177\u8C03\u7528\u4E0A\u4E0B\u6587\u5DF2\u4E0D\u5728\u4F1A\u8BDD\u4E2D\uFF0C\u4EC5\u4F9B\u53C2\u8003\uFF1A
|
|
5
|
+
${g}`,e.orphanToolMessages+=1}a=i(),e.downgradedAssistants+=1}for(let c=0;c<n.length;c++){const m=n[c];if(m.role!=="assistant"||!Array.isArray(m.tool_calls))continue;const h=new Set(m.tool_calls.map(g=>g?.id).filter(g=>typeof g=="string"&&g.length>0));if(h.size===0)continue;const y=g=>g.role==="tool"&&typeof g.tool_call_id=="string"&&h.has(g.tool_call_id),C=[];for(let g=c+1;g<n.length;g++){const T=n[g];if(y(T))continue;if(T.role==="tool")break;let A=!1;for(let w=g+1;w<n.length;w++)if(y(n[w])){A=!0;break}if(!A)break;C.push(T)}if(C.length===0)continue;const d=n.filter(g=>!C.includes(g));let f=-1;for(let g=0;g<d.length;g++)y(d[g])&&(f=g);f<0||(d.splice(f+1,0,...C),n.length=0,n.push(...d),e.relocatedInterruptions+=C.length)}const u=[];return o(u),s(u),e}const ct={truncatedCount:0,strategy:"none",prunedToolMessages:0,summarizedMessages:0,freedTokens:0};async function ts(n,e,t,o,s,r){if(Oe(n)<=e)return ct;const a=await Ae(n,t,o,{llmSummarizer:s});if(a.strategy!=="none")return a.summarizedMessages>0&&r&&await r(),{truncatedCount:a.prunedToolMessages+a.summarizedMessages,strategy:a.strategy,prunedToolMessages:a.prunedToolMessages,summarizedMessages:a.summarizedMessages,freedTokens:a.freedTokens};const l=await De(n,{llmSummarizer:s,contextLimit:t});return l>0&&r&&await r(),{truncatedCount:l,strategy:l>0?"summarize":"none",prunedToolMessages:0,summarizedMessages:l,freedTokens:0}}function os(n){return be(n)}function ss(n){const e=ue(n).toLowerCase();return os(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 ns(n){if(typeof n!="object"||n===null)return!1;const e=Reflect.get(n,"code"),t=ue(n).toLowerCase();return e===-32001||t.includes("request timed out")}function is(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 ut(n,e,t){return JSON.stringify({ok:!1,tool:n.exposedName,error:{type:is(e),message:ue(e)},...t?{file_snapshot:{path:t.path,bytes:t.bytes,content:t.content}}:{}})}function rs(n){const e=JSON.stringify(n);return e.length>500?`${e.slice(0,500)}\u2026`:e}function as(n){const e=[n?.reasoning_content,n?.reasoning_text,n?.reasoning];for(const t of e){if(typeof t=="string"&&t)return t;if(S(t)){const o=t.text??t.content;if(typeof o=="string"&&o)return o}}return""}function ls(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 cs(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(`
|
|
6
|
+
`)}function us(n){if(!n||typeof n!="object")return"";const e=n,t=[],o=e.displayName,s=e.roleName,r=e.instanceName,i=e.projectId,a=e.workspacePath,l=e.runtimeMode,u=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 r=="string"&&r.trim()&&t.push(`Instance: ${r.trim()}`),typeof i=="string"&&i.trim()&&t.push(`Project: ${i.trim()}`),typeof a=="string"&&a.trim()&&t.push(`Workspace: ${a.trim()}`),typeof l=="string"&&l.trim()&&t.push(`Runtime Mode: ${l.trim()}`),typeof u=="string"&&u.trim()&&t.push(`Description: ${u.trim()}`),t.length===0?"":["[User Profile]",...t].join(`
|
|
7
|
+
`)}function mt(n){return n.map(e=>({type:"function",function:{name:e.exposedName,description:e.description||e.toolName,parameters:e.inputSchema}}))}function ms(n,e){return`${n}__${e}`.replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,64)||"mcp_tool"}function ds(n){const e={"Content-Type":"application/json"};return n.apiKey&&(e.Authorization=`Bearer ${n.apiKey}`),e}function ps(n){return Object.fromEntries(Object.entries(n).map(([e,t])=>[e,hs(e)?fs(t):t]))}function hs(n){const e=n.trim().toLowerCase();return e==="authorization"||e==="api-key"||e==="x-api-key"||e==="openai-api-key"}function fs(n){return n.trim().toLowerCase().startsWith("bearer ")?"Bearer ***":"***"}function gs(n){return n.split(/\r?\n/).filter(e=>e.startsWith("data:")).map(e=>e.slice(5).trim()).filter(Boolean)}function dt(n){if(!S(n))return null;const e=n.error;if(S(e)){const t=typeof e.message=="string"?e.message:"",o=e.code??e.status??e.type,s=o==null?"":String(o);return t||s?[s,t].filter(Boolean).join(" "):null}if(typeof e=="string"&&e)return e;if(n.type==="error"||n.object==="error"){const t=typeof n.message=="string"?n.message:"",o=n.code??n.status,s=o==null?"":String(o);if(t||s)return[s,t].filter(Boolean).join(" ")}return null}const Ts=/role 'tool'|tool calls and tool results|tool_call_sequence|\b11148\b/i;let pt=0,me="";function xe(n,e,t){if(!Ts.test(t))return null;try{const o=new Map,s=new Map;n.forEach((d,f)=>{if(d.role==="assistant"&&Array.isArray(d.tool_calls))for(const g of d.tool_calls){const T=typeof g?.id=="string"?g.id.trim():"";T&&!o.has(T)&&o.set(T,f)}else if(d.role==="tool"){const g=typeof d.tool_call_id=="string"?d.tool_call_id.trim():"";g&&!s.has(g)&&s.set(g,f)}});const r=[];n.forEach((d,f)=>{if(d.role==="tool"){const g=typeof d.tool_call_id=="string"?d.tool_call_id.trim():"",T=g?o.get(g):void 0;(g===""||T===void 0||T>f)&&r.push(f)}else if(d.role==="assistant"&&Array.isArray(d.tool_calls))for(const g of d.tool_calls){const T=typeof g?.id=="string"?g.id.trim():"";if(T===""||!s.has(T)){r.push(f);break}}});const i=d=>` [\u5DE5\u5177\u5E8F\u5217\u8BC1\u636E] \u53EF\u7591\u6D88\u606F ${r.length}/${n.length} \u6761\uFF08${d?`\u5DF2\u5199\u5165 ${d}`:"\u843D\u76D8\u5931\u8D25"}\uFF09`,a=Date.now();if(a-pt<1e4&&me)return i(me);pt=a;const l=d=>({role:d.role,tool_call_id:d.tool_call_id,tool_calls:Array.isArray(d.tool_calls)?d.tool_calls.map(f=>f?.id??null):void 0,contentPreview:typeof d.content=="string"?d.content.slice(0,300):d.content===null?null:JSON.stringify(d.content).slice(0,300)}),u=`acode-tool-seq-${new Date(a).toISOString().replace(/[:.]/g,"-")}.json`,c=String(process.env.AWS_TEST_HOME||"").trim()||String(process.env.AWS_RUNTIME_HOME_DIR||"").trim(),m=String(process.env.AWS_RUNTIME_ENV||"").trim().toLowerCase()==="development",h=c||(m?z.resolve(process.cwd(),"..",".dev-home"):z.dirname(Pt())),y=z.join(h,".aws-bridge","log"),C={timestamp:new Date(a).toISOString(),status:e,errorBody:t.slice(0,4e3),suspectIndexes:r,messages:n.map((d,f)=>({index:f,role:d.role,tool_call_id:d.tool_call_id,tool_calls:Array.isArray(d.tool_calls)?d.tool_calls.map(g=>g?.id??null):void 0})),suspectWindows:r.map(d=>{const f=Math.max(0,d-6),g=Math.min(n.length,d+7);return{center:d,range:[f,g],messages:n.slice(f,g).map((T,A)=>({index:f+A,...l(T)}))}})};return me=`.aws-bridge/log/${u}`,B.promises.mkdir(y,{recursive:!0}).then(()=>B.promises.writeFile(z.join(y,u),JSON.stringify(C,null,2),"utf-8")).then(()=>B.promises.readdir(y)).then(d=>{const f=d.filter(T=>T.startsWith("acode-tool-seq-")).sort(),g=f.length-20;return g<=0?null:Promise.all(f.slice(0,g).map(T=>B.promises.unlink(z.join(y,T)).catch(()=>{})))}).catch(()=>{me=""}),i(me)}catch{return null}}function ht(n){const e=new Set,t=Date.now();return n.map((o,s)=>{const r=typeof o?.id=="string"?o.id.trim():"";if(r&&!e.has(r))return e.add(r),o;let i=`call-${t}-${s}`,a=1;for(;e.has(i);)i=`call-${t}-${s}-${a}`,a+=1;return e.add(i),{...o,id:i}})}function ys(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 Cs(n){return ht([...n.entries()].sort(([e],[t])=>e-t).map(([,e])=>e).filter(e=>e.function.name.trim().length>0))}function _s(){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 X extends ft{hasActiveBlockingToolCall(){return this.activeBlockingToolCalls>0}static isLongBlockingMcpToolName(e){return Xt(e)}constructor(e){super(),this.config=e,this.initialConversation=[],this.state={started:!1,terminated:!1,configMcpCount:0,skills:[],provider:{model:"acode-default",stream:!1,requestTimeoutMs:Ge,requestTotalTimeoutMs:Je,requestRetryCount:Ye,requestFirstByteTimeoutMs:He,requestStreamIdleTimeoutMs:Ke,mcpToolTimeoutMs:fe,mcpPollingToolTimeoutMs:Qe,supportsImageInput:!1},permissions:{mode:"default",allow:[],deny:[]},mcpConnections:[],ownsMcpConnections:!0,exposedTools:[],commands:[],commandRegistry:new Pe([]),conversation:[],accumulatedInputTokens:0,accumulatedOutputTokens:0,accumulatedCacheHitTokens:0,accumulatedCacheMissTokens:0,toolPermissionPolicy:{...Ne}},this.abortController=null,this.exposedToolsInitialized=!1,this.recoveredToolNames=new Set,this.readFileStateTracker=new kt,this.pendingMemorySubAgents=new Map,this.memoryDelegateCooldownUntil=new Map,this.toolGroupManager=null,this.submitQueue=Promise.resolve(),this.activeTurnToken=null,this.forceSettleWaiters=new Map,this.abortForceSettleTimer=null,this.activeTurn=!1,this.activeBlockingToolCalls=0,this.forceMessagePending=!1,this.turnPromptPushed=!1,this.abortRequested=!1,this.toolSettleSlots=new Map,this.toolSettleSeq=0,this.toolResourceLock=oo(),this.toolConcurrencyScheduler=new so,this.toolReadOnlyLimiter=null,this.toolBashLimiter=null,this.toolConcurrencyEnabled=!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.permissionWaiters=new Map,this.hookBus=new Vt({sessionId:e.sessionId,onError:(r,i)=>{this.emitAcodeEvent("error",{message:`ACode hook failed: ${r.name}: ${i instanceof Error?i.message:String(i)}`})}});for(const r of e.hooks??[])this.hookBus.register(r);e.toolPermissionPolicy&&(this.state.toolPermissionPolicy={...Ne,...e.toolPermissionPolicy});const t=e.toolConcurrency;this.toolConcurrencyEnabled=t?.enabled!==!1;const o=t?.maxReadOnly??8;this.toolReadOnlyLimiter=new ze(o);const s=t?.maxBash??0;this.toolBashLimiter=s>0?new ze(s):null}getAvailableTools(){return this.state.exposedTools.map(e=>e.exposedName)}emitAcodeEvent(e,t){const o={type:e,sessionId:this.config.sessionId,timestamp:uo(),data:t};this.emit("event",o)}emitCompactionPhase(e,t,o,s,r){this.emitAcodeEvent("context_compaction",{action:"phase",compactionId:e,parentId:e,phase:t,phaseLabel:o,phaseDetail:s,...r?{trigger:r}:{}})}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(),r=Io(this.config,e);p(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 resolveProviderConfig \u7ED3\u679C: config.model=${this.config.model??"(undefined)"}, resolvedModel=${r.model}, baseURL=${r.baseURL??"(none)"}, apiKey=${r.apiKey?"[set]":"(none)"}, configPath=${this.config.configPath??"(none)"}`);const i=Go(this.config,e),a=this.config.sharedMcpConnections?this.filterSharedMcpConnectionsForSubAgent(this.config.sharedMcpConnections):await this.connectMcpServers(e.mcpServers??{},r.mcpToolTimeoutMs),l=!this.config.sharedMcpConnections;this.emitAcodeEvent("startup_phase",{phase:"fetching_profile"});const u=await this.fetchProfilePrompt(a),c=this.config.agentId||"unknown";It(c),ie.reconcileOrphans(c);const m=bt(this.config.workingDirectory,c,this.config.onFileChange,{manager:ie,emitCompleted:_=>{this.emitAcodeEvent("background_command_completed",_)}},this.createToolPermissionController(),{tracker:this.readFileStateTracker,enabled:this.config.enableStaleFileGuard!==!1}),h=Mt(this.buildAskUserQuestionDeps(),()=>this.contextVersion),y=$t(t);this.skillTool=y;const C=vt(c),d=Et(c),f=this.config.subAgentManager?xt(this.buildSubAgentToolDeps(this.config.subAgentManager)):[],g=Rt(this.buildAwaitCompleteDeps()),T=this.config.terminalManager?Ot(c,{terminalManager:this.config.terminalManager}):null,A=new Dt({stateOf:this.config.capabilityState??(()=>"disabled")});A.register({key:"pencil",label:"\u8BBE\u8BA1\u753B\u5E03(pencil)",summary:"UI design editor",collapsible:!0}),A.register({key:"draw",label:"\u7ED8\u56FE",summary:"\u7ED8\u5236 draw.io \u6D41\u7A0B\u56FE/\u6CF3\u9053\u56FE",collapsible:!0}),A.register({key:"office",label:"Office \u6587\u4EF6",summary:"\u53EF\u8FDB\u884C\u67E5\u770B/\u521B\u5EFA\u548C\u590D\u6742\u7F16\u8F91 Word/PPT/Excel",collapsible:!0}),A.register({key:"launch",label:"\u542F\u52A8\u9879\u7BA1\u7406",summary:"\u7BA1\u7406\u9879\u76EE\u4E2D\u4E1A\u52A1\u7A0B\u5E8F\u7684\u8D77\u505C\uFF0C\u82E5\u540E\u9762\u9700\u8981\u542F\u52A8\u9879\u76EE\u5E94\u4F7F\u7528\u6B64\u5DE5\u5177",collapsible:!0}),A.register({key:"hire",label:"\u62DB\u8058\u5DE5\u5177",summary:"\u62DB\u8058\u65B0\u7684\u540C\u4E8B Agent",collapsible:!0}),A.register({key:"browser",label:"\u6D4F\u89C8\u5668\u64CD\u4F5C",summary:"\u542F\u52A8\u6D4F\u89C8\u5668\u4F1A\u8BDD\u3001\u5BFC\u822A\u3001\u622A\u56FE\u4E0E\u9875\u9762\u4EA4\u4E92",collapsible:!0}),A.register({key:"desktop",label:"\u684C\u9762\u64CD\u4F5C",summary:"\u622A\u5C4F\u3001\u9F20\u6807\u952E\u76D8\u63A7\u5236\u4E0E UI \u81EA\u52A8\u5316",collapsible:!1}),A.register({key:"task",label:"\u6D41\u7A0B\u4EFB\u52A1",summary:"\u5904\u7406\u6D41\u7A0B\u7EBF\u4EFB\u52A1\uFF1A\u67E5\u770B\u5F53\u524D\u4EFB\u52A1\u3001\u63D0\u4EA4\u6267\u884C\u7ED3\u679C\u3001\u56DE\u9000\u4EFB\u52A1\u3001\u7ED9\u6D41\u7A0B\u5B9E\u4F8B\u7559\u8A00",collapsible:!0,toolNames:["my_task","submit_task_result","start_task_rollback","finish_task_rollback","create_task_instance_comment"]}),A.register({key:"meeting",label:"\u4F1A\u8BAE",summary:"\u521B\u5EFA/\u52A0\u5165\u4F1A\u8BAE\u3001\u53D1\u8A00\u3001\u67E5\u770B\u4F1A\u8BAE\u4FE1\u606F\u3001\u79BB\u5F00/\u7ED3\u675F\u4F1A\u8BAE",collapsible:!0,toolNames:["create_meeting","leave_meeting","end_meeting","meeting_speak","get_meeting_info","my_meetings"]}),A.register({key:"debug",label:"\u8C03\u8BD5\u65E5\u5FD7",summary:"\u6309\u6761\u4EF6\u5206\u9875\u67E5\u8BE2 Debug \u65E5\u5FD7\u4E0E\u83B7\u53D6\u65E5\u5FD7\u4E0A\u62A5\u914D\u7F6E",collapsible:!0,toolNames:["get_debug_log_config","query_debug_logs"]}),A.register({key:"fileHistory",label:"\u6587\u4EF6\u53D8\u66F4\u5386\u53F2",summary:"\u6309\u89D2\u8272/\u5B9E\u4F8B/\u6587\u4EF6\u8DEF\u5F84\u8FC7\u6EE4\u67E5\u8BE2\u6587\u4EF6\u53D8\u66F4\u5386\u53F2",collapsible:!0,toolNames:["query_file_changes_history"]}),A.register({key:"email",label:"\u90AE\u7BB1",summary:"\u6536\u53D1\u89D2\u8272\u5B9E\u4F8B\u57DF\u540D\u90AE\u7BB1\uFF08xxxxx@\u57DF\u540D\uFF09\uFF1A\u53D1\u4FE1\u3001\u5217\u90AE\u4EF6\u3001\u8BFB\u6B63\u6587\u4E0E\u9644\u4EF6\u3001\u56DE\u4FE1\u4FDD\u6301\u7EBF\u7A0B\u3001\u786E\u8BA4\u4E1A\u52A1\u6D88\u8D39",collapsible:!0,toolNames:["send_email","list_emails","read_email","reply_email","ack_email"]}),this.toolGroupManager=A;for(const _ of a){const P=_.spec??e.mcpServers?.[_.serverName];P&&this.registerMcpCollapsedGroup(_.serverName,P,_)}for(const _ of a)this.registerToolGroupsFromMcp(_);const w=Lt({toolGroupManager:A,getAllTools:()=>this.state.exposedTools,capabilityToolRelay:this.config.capabilityToolRelay}),v=Bt({toolGroupManager:A,pluginBridge:this.config.pluginBridge,capabilityToolRelay:this.config.capabilityToolRelay,findTool:_=>{const P=this.state.exposedTools.find(Re=>Re.exposedName===_||Re.toolName===_);if(!P)return;const ne=P.group??A.getGroupForExposedName(P.exposedName);return{kind:P.kind,group:ne,toolName:P.toolName}},dispatchTool:(_,P,ne)=>this.executeSingleToolByName(_,P,ne)}),k=[...m,h,y,C,d,...f,g,...T?[T]:[],w,v,...a.flatMap(_=>_.tools),...Fe(this.config.extraBuiltInTools??[],this.config.agentId??"")];if(this.config.subAgentAllowedTools&&this.config.subAgentAllowedTools.length>0){const _=Fe(this.config.subAgentSuiteTools??[],this.config.agentId??""),P=de(k,_);k.length=0,k.push(...P)}let M=k;const I=this.config.subAgentAllowedTools;I&&I.length>0&&(M=M.filter(_=>qe(_,I)));const x=this.resolveCommandDirs(e);let D=[...x,...this.discoverPluginCommandDirs()];if(this.config.pluginBridge?.getCommandDirs)try{const _=await this.config.pluginBridge.getCommandDirs();_.length>0&&(D=[...D,..._])}catch(_){p(`[ACodeRuntime] \u63D2\u4EF6\u547D\u4EE4\u76EE\u5F55\u83B7\u53D6\u5931\u8D25\uFF08\u5FFD\u7565\uFF09: ${_ instanceof Error?_.message:String(_)}`)}D=[...new Set(D)],this.emitAcodeEvent("startup_phase",{phase:"loading_commands"});const q=await qt(D),se=new Pe(q),Z=ls(t),b=cs(q),E=A.buildCapabilityPrompt(),N=this.config.pluginBridge?["","## \u63D2\u4EF6\u7CFB\u7EDF","\u63D2\u4EF6\u5DE5\u5177\u4E0D\u5728\u4F60\u7684\u9759\u6001\u5DE5\u5177\u5217\u8868\u4E2D\uFF1A\u7D27\u51D1\u76EE\u5F55\u968F poll_message \u7ED3\u679C\u7684 pluginCatalog \u5B57\u6BB5\u8FD4\u56DE\uFF1B",'\u7528 call_tool \u8C03\u7528\uFF08action="catalog" \u53D6\u76EE\u5F55\uFF0Caction="schema" \u53D6\u5B9A\u4E49\uFF0C','\u6216 action="call"\uFF08\u9ED8\u8BA4\uFF09+ name="\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D" + arguments={...} \u8C03\u7528\uFF09\u3002',"\u63D2\u4EF6\u4E8B\u4EF6\u5C3E\u90E8\u6709 toolHints\uFF08\u5EFA\u8BAE\u8C03\u7528\u7684\u5DE5\u5177\uFF09\uFF0C\u6309\u63D0\u793A\u7528 call_tool \u5904\u7406\u3002","\u63D2\u4EF6\u751F\u547D\u5468\u671F\uFF08\u5B89\u88C5/\u5378\u8F7D/\u91CD\u8F7D/\u542F\u505C/\u5217\u8868\uFF09\u4E5F\u662F\u63D2\u4EF6\u5DE5\u5177\uFF1A",'\u7ECF call_tool \u8C03\u7528 plugin-manager.manage\uFF0C\u5373 call_tool({name: "plugin-manager.manage", arguments:{action:"...", ...}})\u3002',"\u672A\u7ECF\u7528\u6237\u660E\u786E\u8981\u6C42\u4E0D\u8981\u5B89\u88C5\u6216\u5378\u8F7D\u63D2\u4EF6\u3002"].join(`
|
|
8
|
+
`):"",L=E+N,$=[r.systemPrompt,Z,b,L].map(_=>_?.trim()).filter(_=>!!_).join(`
|
|
9
9
|
|
|
10
|
-
`),
|
|
10
|
+
`),J=_=>_?.trim()?[{role:"system",content:_.trim()}]:[],F=[this.config.rolePrompt,u].map(_=>_?.trim()).filter(_=>!!_).join(`
|
|
11
11
|
|
|
12
|
-
`),
|
|
12
|
+
`),Q=[...J(this.config.globalPrompt),...J(F),...J(this.config.memory),...J(this.config.resumeContext),...$?[{role:"system",content:$}]:[],...J(Nt())],V=Q.map(_=>_.content).filter(Boolean).join(`
|
|
13
13
|
|
|
14
|
-
`);this.initialConversation=
|
|
15
|
-
`,"utf-8").catch(()=>{})}catch{}},5e3)}stopCompactionDebugLog(){this.compactionDebugTimer&&(clearInterval(this.compactionDebugTimer),this.compactionDebugTimer=null)}async submit(e,t){const o=this.contextVersion;d(`[ACodeRuntime] \u{1F4EC} submit() queued: contextVersion=${o}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, terminated=${this.state.terminated}, message.length=${e.length}`);const s=this.submitQueue.then(()=>(d(`[ACodeRuntime] \u25B6\uFE0F executeSubmit dequeued: contextVersion=${o}`),this.executeSubmitGuarded(e,o,t)));return this.submitQueue=s.catch(()=>{d("[ACodeRuntime] \u{1F4EC} submit() queued item rejected (catch swallowed)")}),d("[ACodeRuntime] \u{1F4EC} submit() returning queued promise"),s}executeSubmitGuarded(e,t,o){const s={};this.activeTurnToken=s;const i=this.executeSubmit(e,t,o),a=new Promise(r=>{this.forceSettleWaiters.set(s,r)});return i.finally(()=>{this.forceSettleWaiters.delete(s),this.activeTurnToken===s&&(this.abortForceSettleTimer&&(clearTimeout(this.abortForceSettleTimer),this.abortForceSettleTimer=null),this.activeTurnToken=null)}).catch(()=>{}),Promise.race([i,a])}armAbortForceSettle(){if(!this.activeTurn||!this.activeTurnToken)return;const e=this.activeTurnToken;this.abortForceSettleTimer&&clearTimeout(this.abortForceSettleTimer);const t=Qo();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.rejectAllPermissionWaiters("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,d("[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)Ut(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}addPluginCommands(e){if(!this.state||e.length===0)return;this.state.commandRegistry.addCommands(e);const t=new Set(this.state.commands.map(o=>o.name));this.state.commands=[...this.state.commands,...e.filter(o=>!t.has(o.name))]}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 d("[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=B(t);let s=[];try{const l=JSON.parse(o);Array.isArray(l?.directMessages)&&(s=l.directMessages.filter(c=>c?.force===!0))}catch{return!1}if(s.length===0)return!1;const i=JSON.stringify({directMessages:s,groupMessages:[]}),a=`forced_get_msg_${Date.now()}`,r=`${e.serverName}__get_message`;return this.state.conversation.push({role:"assistant",content:null,tool_calls:[{id:a,type:"function",function:{name:r,arguments:"{}"}}]}),this.state.conversation.push({role:"tool",tool_call_id:a,content:i}),d(`[ACodeRuntime] injectForceMessage: injected ${s.length} force message(s) into conversation`),!0}catch(t){return d(`[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=he(this.initialConversation),this.turnPromptPushed=!1,this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}isTurnSuperseded(e){return e!==this.contextVersion}async executeSubmit(e,t,o){const s=Date.now();if(d("[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"),d("[ACodeRuntime] \u25B6\uFE0F executeSubmit STARTED"),d(`[ACodeRuntime] Message: <redacted, length=${e.length}>`),d(`[ACodeRuntime] \u{1F522} Context version: ${t}`),d("[ACodeRuntime] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),!this.state.started||this.state.terminated)throw console.error(`[ACodeRuntime] \u274C Runtime not active (started: ${this.state.started}, terminated: ${this.state.terminated})`),new Error("ACode runtime is not active");this.activeTurn=!0,this.abortRequested=!1;const i=this.activeTurnToken,a=e.trim();let r=!1;const l=o?.resume===!0&&this.turnPromptPushed;l||(this.turnPromptPushed=!1),this.turnSkipProactiveCompaction=l||o?.skipProactiveCompaction===!0||this.state.skipNextCompaction,this.state.skipNextCompaction=!1;try{let c;if(l)d("[ACodeRuntime] \u{1F501} resume turn: skip UserPromptSubmit hook (already ran in failed turn)"),c=[];else{d("[ACodeRuntime] \u{1F50D} Dispatching UserPromptSubmit hook...");const y=Date.now();c=await this.hookBus.dispatch("UserPromptSubmit",{prompt:a});const _=Date.now()-y;d(`[ACodeRuntime] \u2705 UserPromptSubmit hook completed in ${_}ms, results: ${c.length}`)}if(this.isTurnSuperseded(t)){d("[ACodeRuntime] \u26A0\uFE0F Turn superseded after hook, aborting");return}const u=$e(c);if(u){console.error(`[ACodeRuntime] \u274C Prompt denied by hook: ${u.message}`),this.emitAcodeEvent("error",{message:u.message||"ACode prompt was denied by hook"}),this.emitAcodeEvent("turn_complete",{failed:!0}),r=!0,d("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (failed=true) due to hook deny");return}d("[ACodeRuntime] \u{1F50D} Expanding command if any...");const m=this.state.commandRegistry.expand(a),h=m?.prompt.trim()||a,A=m?.command.allowedTools;if(m&&!l){d(`[ACodeRuntime] \u{1F4CB} Slash command detected: ${m.command.name}`),this.emitAcodeEvent("command_status",{action:"slash_command",command:m.command.name,arguments:m.argumentsText,sourcePath:m.command.sourcePath});const y=m.command.plugin;y&&(d(`[ACodeRuntime] \u{1F4CB} Slash command belongs to plugin: ${y}`),this.config.pluginBridge?.exposePlugin?.(y))}if(!this.state.provider.baseURL){d("[ACodeRuntime] \u26A0\uFE0F No provider baseURL configured, using fallback response");const y=Mo(h,this.state);this.emitAcodeEvent("assistant_delta",{text:y}),this.emitAcodeEvent("turn_complete",{usage:{inputTokens:h.length,outputTokens:y.length}}),r=!0,d("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (fallback mode)");return}if(l){if(d("[ACodeRuntime] \u{1F501} resume turn: user message already in conversation, skipping push"),this.isTurnSuperseded(t)){d("[ACodeRuntime] \uFE0F Turn superseded before resume runModelTurn, aborting");return}}else{d("[ACodeRuntime] \u{1F4CE} Parsing attachment message...");const y=Ce(h);if(y.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.");d("[ACodeRuntime] \u{1F5BC}\uFE0F Materializing image content if any...");const _=await He(y.content);if(this.isTurnSuperseded(t)){d("[ACodeRuntime] \uFE0F Turn superseded after materializing content, aborting");return}d("[ACodeRuntime] \u{1F4AC} Adding user message to conversation"),this.state.conversation.push({role:"user",content:_}),this.turnPromptPushed=!0,d(`[ACodeRuntime] Conversation size: ${this.state.conversation.length} messages`)}d("[ACodeRuntime] Starting runModelTurn...");const f=Date.now(),p=await this.runModelTurn(A,t),k=Date.now()-f;if(d(`[ACodeRuntime] \u2705 runModelTurn completed in ${k}ms`),d(`[ACodeRuntime] \u{1F4DD} Result: text=${p.text?p.text.slice(0,80)+(p.text.length>80?"...":""):"(empty)"}, finishReason=${p.finishReason||"(none)"}`),this.isTurnSuperseded(t)){d("[ACodeRuntime] \uFE0F Turn superseded after runModelTurn, aborting");return}p.text&&!this.state.provider.stream&&(d("[ACodeRuntime] \u{1F4E4} Emitting assistant_delta (non-streaming mode)"),this.emitAcodeEvent("assistant_delta",{text:p.text})),d("[ACodeRuntime] \u{1F4E4} Emitting turn_complete..."),this.emitAcodeEvent("turn_complete",{usage:p.usage??{inputTokens:h.length,outputTokens:p.totalOutputTextLength??p.text.length},...p.responseBody?{responseBody:p.responseBody}:{},...p.finishReason?{finishReason:p.finishReason}:{}}),J(`turn_complete emitted: usage=${JSON.stringify(p.usage??{inputTokens:h.length,outputTokens:p.totalOutputTextLength??p.text.length})} (providerUsage=${p.usage?"real":"FALLBACK-text-length"}) textLength=${p.text.length} totalOutputTextLength=${p.totalOutputTextLength}`),d(`[ACodeRuntime] \u{1F4B0} Current context usage: input=${this.state.accumulatedInputTokens}, output=${this.state.accumulatedOutputTokens}`+(p.usage?"":" (estimated, no provider usage)")),r=!0,this.turnPromptPushed=!1;const T=Date.now()-s;d("[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"),d(`[ACodeRuntime] \u2705 executeSubmit COMPLETED in ${T}ms`),d("[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(c){const u=Date.now()-s;if(console.error(`[ACodeRuntime] \u274C executeSubmit FAILED after ${u}ms:`,c instanceof Error?c.message:String(c)),console.error("[ACodeRuntime] \u{1F50D} Error stack:",c instanceof Error?c.stack:"(no stack)"),this.isTurnSuperseded(t)){d("[ACodeRuntime] \uFE0F Turn superseded in error handler, skipping recovery");return}if(this.abortRequested){d("[ACodeRuntime] \u26A0\uFE0F Abort requested, emitting aborted turn_complete"),this.emitAcodeEvent("turn_complete",{aborted:!0}),r=!0;return}d("[ACodeRuntime] Emitting error and failed turn_complete..."),this.emitAcodeEvent("error",{message:c instanceof Error?c.message:String(c)}),this.emitAcodeEvent("turn_complete",{failed:!0}),r=!0}finally{const c=Date.now()-s;d(`[ACodeRuntime] \u{1F51A} executeSubmit finally block entered after ${c}ms`),d(`[ACodeRuntime] \u{1F50D} turnCompleted=${r}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, contextVersion=${t}, currentContextVersion=${this.contextVersion}`),this.activeTurnToken===i&&(this.activeTurn=!1,this.abortRequested=!1,this.turnSkipProactiveCompaction=!1),!r&&!this.isTurnSuperseded(t)&&(console.error(`[ACodeRuntime] \u{1F6A8} CRITICAL: executeSubmit finally block reached without turn_complete event! Duration: ${c}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}),d("[ACodeRuntime] Emergency turn_complete (failed=true) emitted"))}}markSkipNextCompaction(){this.state.skipNextCompaction=!0}async abort(){const e=this.abortController!==null,t=this.activeTurn;this.abortRequested=this.activeTurn,this.abortController?(d(`[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.rejectAllPermissionWaiters("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,i=this.config;return{spawnSubAgent:async a=>{let r=this.config.subAgentSuiteTools;if(a.allowedTools&&a.allowedTools.length>0&&this.config.subAgentSuiteToolProvider)try{const c=await this.config.subAgentSuiteToolProvider(a.allowedTools);c.length>0&&(r=r?ne(r,c):c)}catch{}const l=await e.spawn({parentAgentId:t,parentSessionId:o,subagentType:a.subagentType,description:a.description,prompt:a.prompt,...a.allowedTools&&a.allowedTools.length>0?{allowedTools:a.allowedTools}:{},workingDirectory:s,parentConfig:{...i,sharedMcpConnections:this.state?.mcpConnections,...r&&r.length>0?{subAgentSuiteTools:r}:{}}});return await e.start(l),{subId:l}},listSubAgentToolCatalog:async()=>xe(await this.buildAllocatableToolList()),listSubAgents:async()=>{const a=e.listByParent(t),r=[],l=[];for(const c of a){const u={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"?r.push(u):l.push(u)}return l.sort((c,u)=>(u.endedAt??0)-(c.endedAt??0)),{running:r,history:l}},getSubAgentStatus:async a=>{const r=e.getSubAgent(a);return r?{subId:r.subId,subagentType:r.subagentType,description:r.description,status:r.status,startedAt:r.startedAt,endedAt:r.endedAt,durationMs:r.durationMs,prompt:r.prompt,result:r.result,errorMessage:r.errorMessage,contextSnapshot:r.contextSnapshot}:null},awaitSubAgents:async(a,r)=>{const l=new Set;for(const c of a)this.pendingAwaitedSubIds.add(c),l.add(c);try{return await e.awaitCompletion(a,r)}finally{for(const c of l)this.pendingAwaitedSubIds.delete(c)}},abortSubAgent:a=>e.abort(a)}}buildAwaitCompleteDeps(){const e=this.config.agentId??"unknown",t=this.config.subAgentManager;return{agentId:e,awaitSubAgents:t?(o,s)=>{for(const i of o)this.pendingAwaitedSubIds.add(i);try{return this.buildSubAgentToolDeps(t).awaitSubAgents(o,s)}finally{for(const i of o)this.pendingAwaitedSubIds.delete(i)}}:null,awaitBgCommands:(o,s)=>{for(const i of o)this.pendingAwaitedBgTaskIds.add(i);try{return Y.awaitCompletion(e,o,s)}finally{for(const i of o)this.pendingAwaitedBgTaskIds.delete(i)}}}}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()}}createToolPermissionController(){return{getLevel:e=>this.state.toolPermissionPolicy[e]??"allow",requestPermission:(e,t)=>this.requestToolPermission(e,t)}}requestToolPermission(e,t){const o=st();return new Promise(s=>{this.permissionWaiters.set(o,{capability:e,detail:t,resolve:s}),this.emitAcodeEvent("tool_permission_request",{requestId:o,capability:e,agentId:this.config.agentId,...t})})}submitToolPermissionDecision(e,t){const o=this.permissionWaiters.get(e);return o?(this.permissionWaiters.delete(e),o.resolve(t),!0):!1}rejectAllPermissionWaiters(e){if(this.permissionWaiters.size!==0){for(const[,t]of this.permissionWaiters)t.resolve(!1);this.permissionWaiters.clear(),P("tool-permission",`waiters rejected: ${e}`)}}setToolPermissionPolicy(e){this.state.toolPermissionPolicy={...this.state.toolPermissionPolicy,...e}}cancelPendingAwaitedSubAgents(){if(this.pendingAwaitedSubIds.size===0)return;const e=this.config.subAgentManager;if(!e)return;const t=Array.from(this.pendingAwaitedSubIds);d(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited sub-agent(s): ${t.join(", ")}`);for(const o of t)e.abort(o).catch(s=>{d(`[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);d(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited background command(s): ${t.join(", ")}`),Y.interruptAwaits(e,t)}detachCurrentToolExecution(e){const t=e?this.toolSettleSlots.get(e):this.pickSettleCandidate();return!t||!t.settlable||t.settled?!1:(t.settled=!0,t.resolveSettle?.(),d(`[ACodeRuntime] \u{1F680} detachCurrentToolExecution: settling tool ${t.toolName} (toolCallId=${t.toolCallId}) to background`),!0)}pickSettleCandidate(){let e=null;for(const t of this.toolSettleSlots.values())!t.settlable||t.settled||(e===null||t.order<e.order)&&(e=t);return e}beginToolSettle(e,t,o){const s=e.toolName==="Bash",i=++this.toolSettleSeq;let a;const r=s?new Promise(l=>{a=l}):void 0;return this.toolSettleSlots.set(o,{seq:i,toolName:e.toolName,toolCallId:o,settlable:s,settled:!1,resolveSettle:a??null,order:i}),{seq:i,signal:r}}clearToolSettle(e,t){if(t!==void 0){this.toolSettleSlots.get(t)?.seq===e&&this.toolSettleSlots.delete(t);return}for(const[o,s]of this.toolSettleSlots)if(s.seq===e){this.toolSettleSlots.delete(o);return}}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.rejectAllPermissionWaiters("session terminated"),this.readFileStateTracker.clear(),this.cancelPendingAwaitedSubAgents(),this.cancelPendingAwaitedBgTasks(),await X("ACode active turn shutdown",this.submitQueue,t=>{this.emitAcodeEvent("error",{message:t})}),await this.disconnectMcpServers();const e=this.config.agentId||"unknown";if(await X("ACode background commands shutdown",Y.disposeAgent(e),t=>{this.emitAcodeEvent("error",{message:t})}),X("ACode agent PTY sessions shutdown",Promise.resolve(this.config.terminalManager?.killByAgent?.(e)),t=>{this.emitAcodeEvent("error",{message:t})}),await X("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{D.promises.appendFile(We,`[${new Date().toISOString()}] runtime stopped | ---
|
|
16
|
-
`,"utf-8").catch(()=>{})}catch{}}discoverPluginCommandDirs(){const e=this.config.pluginsDir;if(!e)return[];let t;try{t=
|
|
14
|
+
`);this.initialConversation=re(Q),this.state={started:!0,terminated:!1,configMcpCount:Object.keys(e.mcpServers??{}).length,skills:t,provider:r,permissions:i,mcpConnections:a,ownsMcpConnections:l,exposedTools:M,commands:q,commandRegistry:se,conversation:re(Q),accumulatedInputTokens:0,accumulatedOutputTokens:0,accumulatedCacheHitTokens:0,accumulatedCacheMissTokens:0,toolPermissionPolicy:this.state.toolPermissionPolicy},this.exposedToolsInitialized=!0,this.emitAcodeEvent("startup_phase",{phase:"session_start_hook"}),await this.hookBus.dispatch("SessionStart",{workingDirectory:this.config.workingDirectory,model:r.model,commandCount:q.length});const H=Ce(r);this.emitAcodeEvent("session_started",{workingDirectory:this.config.workingDirectory,model:r.model,commandCount:q.length,estimatedContextTokens:vo(V,M),contextLimit:H.contextLimit,maxOutput:H.maxOutput,...H.inputLimit!==void 0?{inputLimit:H.inputLimit}:{},compactionThreshold:H.threshold}),this.emitAcodeEvent("mcp_status",{configPath:this.config.configPath,installedCount:this.state.configMcpCount,servers:Object.keys(e.mcpServers??{}),connectedCount:a.length,builtInToolCount:m.length,toolCount:M.length,permissionMode:i.mode,allowedToolRules:i.allow,deniedToolRules:i.deny,tools:M.map(_=>({name:_.exposedName,source:_.kind==="mcp"?`${_.serverName}.${_.toolName}`:`builtin.${_.toolName}`,description:_.description||""}))}),this.emitAcodeEvent("skill_status",{skillsDir:this.config.skillsDir,installedCount:t.length,skills:t.map(_=>({name:_.name,description:_.description,directory:_.directory})),skillGroups:o.map(_=>({dir:_.dir,exists:_.exists,skills:_.skills.map(P=>({name:P.name,description:P.description,directory:P.directory}))}))}),this.emitAcodeEvent("command_status",{action:"commands_loaded",installedCommandCount:q.length,commandDirs:x,commands:q.map(_=>({name:_.name,description:_.description}))}),this.config.initialPrompt&&await this.submit(this.config.initialPrompt),this.startCompactionDebugLog(),this.startSkillWatchers(s)}async loadAllSkills(){const e=this.config.skillsDir??"",t=z.join(this.config.workingDirectory,".acode","skills"),o=z.join(this.config.workingDirectory,".agentswork","skills"),s=new Set,r=[],i=[];for(const u of[e,t,o]){if(!u)continue;const c=z.resolve(u);if(!s.has(c)){s.add(c),r.push(await Qt(u));try{await B.promises.access(c),i.push(c)}catch{}}}const a=new Map;for(const u of r)for(const c of u.skills)a.set(c.name,c);return{skills:[...a.values()],skillGroups:r,watchedDirs:i}}startSkillWatchers(e){for(const t of e){let o=null;try{o=B.watch(t,{recursive:!0},()=>{this.scheduleSkillRefresh()})}catch{try{o=B.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()},X.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}))}))}),p(`[skill-watch] Skills refreshed: ${e.length} skills (${e.map(o=>o.name).join(", ")||"none"})`,{sessionId:this.config.sessionId})}catch(e){console.error("[skill-watch] Failed to refresh skills:",e instanceof Error?e.message:e)}}stopSkillWatchers(){this.skillRefreshTimer&&(clearTimeout(this.skillRefreshTimer),this.skillRefreshTimer=null);for(const e of this.skillWatchers)try{e.close()}catch{}this.skillWatchers=[]}startCompactionDebugLog(){if(!Te||this.compactionDebugTimer)return;const e=this.state.provider,{contextLimit:t,maxOutput:o,inputLimit:s,threshold:r}=Ce(e);this.compactionDebugTimer=setInterval(()=>{try{const i=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,a=j(this.state.conversation)+ce(this.state.exposedTools),l=Math.max(i,a),u=Y(this.state.conversation),c=this.state.started&&!this.state.terminated,m=[`[${new Date().toISOString()}]`,`started=${this.state.started}`,`terminated=${this.state.terminated}`,`activeTurn=${this.activeTurn}`,`conversationSize=${this.state.conversation.length}msgs`,`sizeKB=${u}KB`,`estimation=${a} tokens`,`actualInput=${this.state.accumulatedInputTokens}`,`actualOutput=${this.state.accumulatedOutputTokens}`,`actualUsed=${i}`,`contextLimit=${t}`,`inputLimit=${s??"n/a"}`,`maxOutput=${o}`,`triggerThreshold=${r}`,`remainingToTrigger=${Math.max(0,r-i)}`,`isRunning=${c}`,`shouldCompact=${c?l>=r:!1}`,"---"].join(" | ");B.promises.appendFile(tt,m+`
|
|
15
|
+
`,"utf-8").catch(()=>{})}catch{}},5e3)}stopCompactionDebugLog(){this.compactionDebugTimer&&(clearInterval(this.compactionDebugTimer),this.compactionDebugTimer=null)}async submit(e,t){const o=this.contextVersion;p(`[ACodeRuntime] \u{1F4EC} submit() queued: contextVersion=${o}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, terminated=${this.state.terminated}, message.length=${e.length}`);const s=this.submitQueue.then(()=>(p(`[ACodeRuntime] \u25B6\uFE0F executeSubmit dequeued: contextVersion=${o}`),this.executeSubmitGuarded(e,o,t)));return this.submitQueue=s.catch(()=>{p("[ACodeRuntime] \u{1F4EC} submit() queued item rejected (catch swallowed)")}),p("[ACodeRuntime] \u{1F4EC} submit() returning queued promise"),s}executeSubmitGuarded(e,t,o){const s={};this.activeTurnToken=s;const r=this.executeSubmit(e,t,o),i=new Promise(a=>{this.forceSettleWaiters.set(s,a)});return r.finally(()=>{this.forceSettleWaiters.delete(s),this.activeTurnToken===s&&(this.abortForceSettleTimer&&(clearTimeout(this.abortForceSettleTimer),this.abortForceSettleTimer=null),this.activeTurnToken=null)}).catch(()=>{}),Promise.race([r,i])}armAbortForceSettle(){if(!this.activeTurn||!this.activeTurnToken)return;const e=this.activeTurnToken;this.abortForceSettleTimer&&clearTimeout(this.abortForceSettleTimer);const t=_s();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.rejectAllPermissionWaiters("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,p("[ACodeRuntime] \u{1F514} Force message pending flag set")}exportConversation(){return re(this.state.conversation)}async importTranscript(e){if(!Array.isArray(e)||e.length===0)return console.log("[HIBERNATE-REPLAY][runtime] \u7A7A\u8F93\u5165\uFF0C\u8DF3\u8FC7\u91CD\u653E"),0;if(!this.state.started)return console.log(`[HIBERNATE-REPLAY][runtime] \u4F1A\u8BDD\u672A start()\uFF0C\u8DF3\u8FC7\u91CD\u653E\uFF08${e.length}\u6761\u88AB\u4E22\u5F03\uFF09`),0;const t=e.filter(u=>u.role!=="system");if(t.length===0)return 0;const{contextLimit:o,maxOutput:s,inputLimit:r}=Ce(this.state.provider),i=Gt(o,r),a=j(this.state.conversation)+j(t)+ce(this.state.exposedTools);let l=t;if(console.log(`[HIBERNATE-REPLAY][runtime] \u9884\u68C0: \u53EF\u91CD\u653E=${t.length}\u6761 projectedTokens=${a} hardWindow=${i} \u9700\u8981\u9884\u538B\u7F29=${a>=i}`),a>=i){p(`[ACodeRuntime] \u{1F4E6} importTranscript pre-compaction: projected=${a} >= hardWindow=${i}`);try{const u=await Ae(t,o,s,{llmSummarizer:c=>this.summarizeConversationWithLLM(c)});if(u.strategy!=="none"){const c=j(t);p(`[ACodeRuntime] \u{1F4E6} importTranscript pre-compaction done: strategy=${u.strategy}, tokensBefore=${a}, tokensAfter=${c}`)}}catch(u){p(`[ACodeRuntime] \u26A0\uFE0F importTranscript pre-compaction failed, replaying raw: ${u instanceof Error?u.message:String(u)}`)}l=t}return this.state.conversation.push(...re(l)),console.log(`[HIBERNATE-REPLAY][runtime] \u91CD\u653E\u5B8C\u6210: \u62FC\u5165=${l.length}\u6761 conversation\u603B\u957F=${this.state.conversation.length}\u6761 \u603Btoken\u4F30\u7B97=${j(this.state.conversation)+ce(this.state.exposedTools)}`),this.emitAcodeEvent("context_compaction",{action:"end",compactionId:`transcript-replay-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,sizeKB:Y(this.state.conversation),estimatedTokens:j(this.state.conversation)+ce(this.state.exposedTools),actualInputTokens:this.state.accumulatedInputTokens,actualOutputTokens:this.state.accumulatedOutputTokens,messageCount:this.state.conversation.length,replayedMessageCount:l.length,model:this.state.provider.model,trigger:"hibernation_replay"}),l.length}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)no(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}addPluginCommands(e){if(!this.state||e.length===0)return;this.state.commandRegistry.addCommands(e);const t=new Set(this.state.commands.map(o=>o.name));this.state.commands=[...this.state.commands,...e.filter(o=>!t.has(o.name))]}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 p("[ACodeRuntime] injectForceMessage: no connection with get_message found"),!1;try{const t=await R(e.client.callTool({name:"get_message",arguments:{_aws_force_inject:!0}},void 0,{timeout:1e4}),1e4,"injectForceMessage get_message"),o=G(t);let s=[];try{const l=JSON.parse(o);Array.isArray(l?.directMessages)&&(s=l.directMessages.filter(u=>u?.force===!0))}catch{return!1}if(s.length===0)return!1;const r=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:r}),p(`[ACodeRuntime] injectForceMessage: injected ${s.length} force message(s) into conversation`),!0}catch(t){return p(`[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=re(this.initialConversation),this.turnPromptPushed=!1,this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}isTurnSuperseded(e){return e!==this.contextVersion}async executeSubmit(e,t,o){const s=Date.now();if(p("[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"),p("[ACodeRuntime] \u25B6\uFE0F executeSubmit STARTED"),p(`[ACodeRuntime] Message: <redacted, length=${e.length}>`),p(`[ACodeRuntime] \u{1F522} Context version: ${t}`),p("[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 r=this.activeTurnToken,i=e.trim();let a=!1;const l=o?.resume===!0&&this.turnPromptPushed;l||(this.turnPromptPushed=!1);try{let u;if(l)p("[ACodeRuntime] \u{1F501} resume turn: skip UserPromptSubmit hook (already ran in failed turn)"),u=[];else{p("[ACodeRuntime] \u{1F50D} Dispatching UserPromptSubmit hook...");const T=Date.now();u=await this.hookBus.dispatch("UserPromptSubmit",{prompt:i});const A=Date.now()-T;p(`[ACodeRuntime] \u2705 UserPromptSubmit hook completed in ${A}ms, results: ${u.length}`)}if(this.isTurnSuperseded(t)){p("[ACodeRuntime] \u26A0\uFE0F Turn superseded after hook, aborting");return}const c=Le(u);if(c){console.error(`[ACodeRuntime] \u274C Prompt denied by hook: ${c.message}`),this.emitAcodeEvent("error",{message:c.message||"ACode prompt was denied by hook"}),this.emitAcodeEvent("turn_complete",{failed:!0}),a=!0,p("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (failed=true) due to hook deny");return}p("[ACodeRuntime] \u{1F50D} Expanding command if any...");const m=this.state.commandRegistry.expand(i),h=m?.prompt.trim()||i,y=m?.command.allowedTools;if(m&&!l){p(`[ACodeRuntime] \u{1F4CB} Slash command detected: ${m.command.name}`),this.emitAcodeEvent("command_status",{action:"slash_command",command:m.command.name,arguments:m.argumentsText,sourcePath:m.command.sourcePath});const T=m.command.plugin;T&&(p(`[ACodeRuntime] \u{1F4CB} Slash command belongs to plugin: ${T}`),this.config.pluginBridge?.exposePlugin?.(T))}if(!this.state.provider.baseURL){p("[ACodeRuntime] \u26A0\uFE0F No provider baseURL configured, using fallback response");const T=Zo(h,this.state);this.emitAcodeEvent("assistant_delta",{text:T}),this.emitAcodeEvent("turn_complete",{usage:{inputTokens:h.length,outputTokens:T.length}}),a=!0,p("[ACodeRuntime] \u{1F4E4} Emitted turn_complete (fallback mode)");return}if(l){if(p("[ACodeRuntime] \u{1F501} resume turn: user message already in conversation, skipping push"),this.isTurnSuperseded(t)){p("[ACodeRuntime] \uFE0F Turn superseded before resume runModelTurn, aborting");return}}else{p("[ACodeRuntime] \u{1F4CE} Parsing attachment message...");const T=Ee(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.");p("[ACodeRuntime] \u{1F5BC}\uFE0F Materializing image content if any...");const A=await it(T.content);if(this.isTurnSuperseded(t)){p("[ACodeRuntime] \uFE0F Turn superseded after materializing content, aborting");return}p("[ACodeRuntime] \u{1F4AC} Adding user message to conversation"),this.state.conversation.push({role:"user",content:A}),this.turnPromptPushed=!0,p(`[ACodeRuntime] Conversation size: ${this.state.conversation.length} messages`)}p("[ACodeRuntime] Starting runModelTurn...");const C=Date.now(),d=await this.runModelTurn(y,t),f=Date.now()-C;if(p(`[ACodeRuntime] \u2705 runModelTurn completed in ${f}ms`),p(`[ACodeRuntime] \u{1F4DD} Result: text=${d.text?d.text.slice(0,80)+(d.text.length>80?"...":""):"(empty)"}, finishReason=${d.finishReason||"(none)"}`),this.isTurnSuperseded(t)){p("[ACodeRuntime] \uFE0F Turn superseded after runModelTurn, aborting");return}d.text&&!this.state.provider.stream&&(p("[ACodeRuntime] \u{1F4E4} Emitting assistant_delta (non-streaming mode)"),this.emitAcodeEvent("assistant_delta",{text:d.text})),p("[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}:{}}),te(`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}`),p(`[ACodeRuntime] \u{1F4B0} Current context usage: input=${this.state.accumulatedInputTokens}, output=${this.state.accumulatedOutputTokens}`+(d.usage?"":" (estimated, no provider usage)")),a=!0,this.turnPromptPushed=!1;const g=Date.now()-s;p("[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"),p(`[ACodeRuntime] \u2705 executeSubmit COMPLETED in ${g}ms`),p("[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(u){const c=Date.now()-s;if(console.error(`[ACodeRuntime] \u274C executeSubmit FAILED after ${c}ms:`,u instanceof Error?u.message:String(u)),console.error("[ACodeRuntime] \u{1F50D} Error stack:",u instanceof Error?u.stack:"(no stack)"),this.isTurnSuperseded(t)){p("[ACodeRuntime] \uFE0F Turn superseded in error handler, skipping recovery");return}if(this.abortRequested){p("[ACodeRuntime] \u26A0\uFE0F Abort requested, emitting aborted turn_complete"),this.emitAcodeEvent("turn_complete",{aborted:!0}),a=!0;return}p("[ACodeRuntime] Emitting error and failed turn_complete..."),this.emitAcodeEvent("error",{message:u instanceof Error?u.message:String(u)}),this.emitAcodeEvent("turn_complete",{failed:!0}),a=!0}finally{const u=Date.now()-s;p(`[ACodeRuntime] \u{1F51A} executeSubmit finally block entered after ${u}ms`),p(`[ACodeRuntime] \u{1F50D} turnCompleted=${a}, activeTurn=${this.activeTurn}, abortRequested=${this.abortRequested}, contextVersion=${t}, currentContextVersion=${this.contextVersion}`),this.activeTurnToken===r&&(this.activeTurn=!1,this.abortRequested=!1),!a&&!this.isTurnSuperseded(t)&&(console.error(`[ACodeRuntime] \u{1F6A8} CRITICAL: executeSubmit finally block reached without turn_complete event! Duration: ${u}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}),p("[ACodeRuntime] Emergency turn_complete (failed=true) emitted"))}}async abort(){const e=this.abortController!==null,t=this.activeTurn;this.abortRequested=this.activeTurn,this.abortController?(p(`[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.rejectAllPermissionWaiters("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 de(e,de(t,o))}buildSubAgentToolDeps(e){const t=this.config.agentId??"unknown",o=this.config.sessionId,s=this.config.workingDirectory,r=this.config;return{spawnSubAgent:async i=>{let a=this.config.subAgentSuiteTools;if(i.allowedTools&&i.allowedTools.length>0&&this.config.subAgentSuiteToolProvider)try{const u=await this.config.subAgentSuiteToolProvider(i.allowedTools);u.length>0&&(a=a?de(a,u):u)}catch{}const l=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:{...r,sharedMcpConnections:this.state?.mcpConnections,...a&&a.length>0?{subAgentSuiteTools:a}:{}}});return await e.start(l),{subId:l}},listSubAgentToolCatalog:async()=>Ue(await this.buildAllocatableToolList()),listSubAgents:async()=>{const i=e.listByParent(t),a=[],l=[];for(const u of i){const c={subId:u.subId,subagentType:u.subagentType,description:u.description,status:u.status,startedAt:u.startedAt,endedAt:u.endedAt,durationMs:u.durationMs};u.status==="pending"||u.status==="running"?a.push(c):l.push(c)}return l.sort((u,c)=>(c.endedAt??0)-(u.endedAt??0)),{running:a,history:l}},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 l=new Set;for(const u of i)this.pendingAwaitedSubIds.add(u),l.add(u);try{return await e.awaitCompletion(i,a)}finally{for(const u of l)this.pendingAwaitedSubIds.delete(u)}},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 r of o)this.pendingAwaitedSubIds.add(r);try{return this.buildSubAgentToolDeps(t).awaitSubAgents(o,s)}finally{for(const r of o)this.pendingAwaitedSubIds.delete(r)}}:null,awaitBgCommands:(o,s)=>{for(const r of o)this.pendingAwaitedBgTaskIds.add(r);try{return ie.awaitCompletion(e,o,s)}finally{for(const r of o)this.pendingAwaitedBgTaskIds.delete(r)}}}}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()}}createToolPermissionController(){return{getLevel:e=>this.state.toolPermissionPolicy[e]??"allow",requestPermission:(e,t)=>this.requestToolPermission(e,t)}}requestToolPermission(e,t){const o=gt();return new Promise(s=>{this.permissionWaiters.set(o,{capability:e,detail:t,resolve:s}),this.emitAcodeEvent("tool_permission_request",{requestId:o,capability:e,agentId:this.config.agentId,...t})})}submitToolPermissionDecision(e,t){const o=this.permissionWaiters.get(e);return o?(this.permissionWaiters.delete(e),o.resolve(t),!0):!1}rejectAllPermissionWaiters(e){if(this.permissionWaiters.size!==0){for(const[,t]of this.permissionWaiters)t.resolve(!1);this.permissionWaiters.clear(),U("tool-permission",`waiters rejected: ${e}`)}}setToolPermissionPolicy(e){this.state.toolPermissionPolicy={...this.state.toolPermissionPolicy,...e}}cancelPendingAwaitedSubAgents(){if(this.pendingAwaitedSubIds.size===0)return;const e=this.config.subAgentManager;if(!e)return;const t=Array.from(this.pendingAwaitedSubIds);p(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited sub-agent(s): ${t.join(", ")}`);for(const o of t)e.abort(o).catch(s=>{p(`[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);p(`[ACodeRuntime] \u26D4 Cancelling ${t.length} pending awaited background command(s): ${t.join(", ")}`),ie.interruptAwaits(e,t)}detachCurrentToolExecution(e){const t=e?this.toolSettleSlots.get(e):this.pickSettleCandidate();return!t||!t.settlable||t.settled?!1:(t.settled=!0,t.resolveSettle?.(),p(`[ACodeRuntime] \u{1F680} detachCurrentToolExecution: settling tool ${t.toolName} (toolCallId=${t.toolCallId}) to background`),!0)}pickSettleCandidate(){let e=null;for(const t of this.toolSettleSlots.values())!t.settlable||t.settled||(e===null||t.order<e.order)&&(e=t);return e}beginToolSettle(e,t,o){const s=e.toolName==="Bash",r=++this.toolSettleSeq;let i;const a=s?new Promise(l=>{i=l}):void 0;return this.toolSettleSlots.set(o,{seq:r,toolName:e.toolName,toolCallId:o,settlable:s,settled:!1,resolveSettle:i??null,order:r}),{seq:r,signal:a}}clearToolSettle(e,t){if(t!==void 0){this.toolSettleSlots.get(t)?.seq===e&&this.toolSettleSlots.delete(t);return}for(const[o,s]of this.toolSettleSlots)if(s.seq===e){this.toolSettleSlots.delete(o);return}}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.rejectAllPermissionWaiters("session terminated"),this.readFileStateTracker.clear(),this.cancelPendingAwaitedSubAgents(),this.cancelPendingAwaitedBgTasks(),await ae("ACode active turn shutdown",this.submitQueue,t=>{this.emitAcodeEvent("error",{message:t})}),await this.disconnectMcpServers();const e=this.config.agentId||"unknown";if(await ae("ACode background commands shutdown",ie.disposeAgent(e),t=>{this.emitAcodeEvent("error",{message:t})}),ae("ACode agent PTY sessions shutdown",Promise.resolve(this.config.terminalManager?.killByAgent?.(e)),t=>{this.emitAcodeEvent("error",{message:t})}),await ae("ACode Stop hooks",this.hookBus.dispatch("Stop",{reason:"session_stop"}),t=>{this.emitAcodeEvent("error",{message:t})}),this.state.terminated=!0,this.sessionCompleteEmitted||(this.sessionCompleteEmitted=!0,this.emitAcodeEvent("session_complete",{exitCode:0})),this.stopCompactionDebugLog(),this.stopSkillWatchers(),Te)try{B.promises.appendFile(tt,`[${new Date().toISOString()}] runtime stopped | ---
|
|
16
|
+
`,"utf-8").catch(()=>{})}catch{}}discoverPluginCommandDirs(){const e=this.config.pluginsDir;if(!e)return[];let t;try{t=B.readdirSync(e)}catch{return[]}const o=[];for(const s of t){if(s.startsWith("."))continue;const r=z.join(e,s);let i;try{i=B.statSync(r)}catch{continue}if(!i.isDirectory())continue;const a=z.join(r,"commands");let l;try{B.existsSync(a)&&(l=B.statSync(a))}catch{l=void 0}l?.isDirectory()&&o.push(a)}return o}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,r,i,a="",l=0;this.lastIterationUsage=void 0,p(`[ACodeRuntime] \u25B6\uFE0F runModelTurn started (contextVersion: ${t})`);const u=50;for(let c=0;c<u;c+=1){if(p(`[ACodeRuntime] \u{1F504} Iteration ${c+1} starting...`),this.isTurnSuperseded(t))return p(`[ACodeRuntime] \u26A0\uFE0F Turn superseded at iteration ${c+1}, aborting`),{text:"",totalOutputTextLength:a.length};await this.injectForceMessage();const m=Date.now(),h=await this.requestChatCompletion(e),y=Date.now()-m;if(p(`[ACodeRuntime] \u{1F916} AI request completed in ${y}ms, choices: ${h.choices?.length||0}`),this.isTurnSuperseded(t))return p(`[ACodeRuntime] \u26A0\uFE0F Turn superseded after AI response at iteration ${c+1}`),{text:"",totalOutputTextLength:a.length};if(this.state.terminated)throw p(`[ACodeRuntime] Runtime terminated at iteration ${c+1}`),new Error("ACode runtime was stopped during the active turn");const C=h.choices?.[0];r=JSON.stringify(h,null,2),i=typeof C?.finish_reason=="string"?C.finish_reason:void 0;const d=C?.message,f=typeof d?.content=="string"?d.content:"",g=Array.isArray(d?.tool_calls)?ht(d.tool_calls):[];if(p(`[ACodeRuntime] AI response: content=${f?f.slice(0,100)+(f.length>100?"...":""):"(empty)"}, toolCalls=${g.length}, finishReason=${i||"(none)"}`),h.usage){const v=W(h.usage.prompt_tokens??h.usage.input_tokens),k=W(h.usage.completion_tokens??h.usage.output_tokens),M=v!==void 0,I=k!==void 0;if(te(`provider usage parsed: raw=${JSON.stringify(h.usage)} input=${v} output=${k} hasInput=${M} hasOutput=${I} iteration=${c+1}`),M||I){const x=lo(h.usage,v),D=s?.outputTokens??a.length+f.length;this.state.accumulatedCacheHitTokens+=x?.cacheHitTokens??0,this.state.accumulatedCacheMissTokens+=x?.cacheMissTokens??0,s={inputTokens:M?v:s?.inputTokens??0,outputTokens:I?k:D,cacheHitTokens:this.state.accumulatedCacheHitTokens,cacheMissTokens:this.state.accumulatedCacheMissTokens},this.lastIterationUsage=s,this.emitAcodeEvent("iteration_usage",{inputTokens:s.inputTokens,outputTokens:s.outputTokens,cacheHitTokens:s.cacheHitTokens,cacheMissTokens:s.cacheMissTokens}),l+=M?v:0,this.state.accumulatedInputTokens=M?v:this.state.accumulatedInputTokens,this.state.accumulatedOutputTokens=I?k:this.state.accumulatedOutputTokens,te(`finalUsage updated: ${JSON.stringify(s)} (cacheUsage=${JSON.stringify(x??null)})`),p(`[ACodeRuntime] \u{1F4B0} Token usage: input=${s.inputTokens}, output=${s.outputTokens} (turn accumulated cost: input=${l})`),p(x?`[ACodeRuntime] \u{1F4B0} Cache usage (provider reported): hit=${x.cacheHitTokens}, miss=${x.cacheMissTokens}`:'[ACodeRuntime] \u{1F4B0} Cache usage: provider usage \u4E2D\u65E0\u7F13\u5B58\u5B57\u6BB5\uFF08\u9762\u677F\u5C06\u663E\u793A "-"\uFF09')}}else te(`provider response has NO usage field (fallback to text-length estimate), iteration=${c+1}`);if(this.state.conversation.push({role:"assistant",content:f||null,tool_calls:g.length>0?g:void 0}),f&&(o=f,a+=f,p(`[ACodeRuntime] \u2728 Captured assistant text: ${f.slice(0,80)}...`)),g.length===0)return p(`[ACodeRuntime] \u2705 No tool calls at iteration ${c+1}, completing turn`),{text:o,usage:s,responseBody:r,finishReason:i,totalOutputTextLength:a.length};const T=g.map(v=>v.function.name).join(", ");p(`[ACodeRuntime] \u{1F527} Executing ${g.length} tool(s) at iteration ${c+1}: ${T}`);const A=Date.now();await this.handleToolCalls(g,e,t);const w=Date.now()-A;if(p(`[ACodeRuntime] \u2699\uFE0F Tool execution completed in ${w}ms at iteration ${c+1}`),this.isTurnSuperseded(t))return p(`[ACodeRuntime] \u26A0\uFE0F Turn superseded after tool execution at iteration ${c+1}`),{text:"",totalOutputTextLength:a.length};p(`[ACodeRuntime] \u{1F504} Preparing iteration ${c+2}...`)}return console.error(`[ACodeRuntime] \u{1F6A8} CRITICAL: Reached safety limit of ${u} iterations! This indicates a potential infinite loop. Forcing turn completion.`),{text:o||`ACode \u5DF2\u8FBE\u5230\u5B89\u5168\u8FED\u4EE3\u4E0A\u9650\uFF08${u}\u6B21\uFF09\uFF0C\u5F3A\u5236\u7ED3\u675F\u672C\u8F6E\u5BF9\u8BDD\u3002`,usage:s,responseBody:r,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 r={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).
|
|
17
17
|
|
|
18
18
|
--- Conversation Start ---
|
|
19
19
|
${e.conversationText}
|
|
20
20
|
--- Conversation End ---
|
|
21
21
|
|
|
22
|
-
`+$t}]},a=new AbortController;this.abortController=a;let r=!1;try{return await E((async()=>{const l=await E(fetch(ce(o),{method:"POST",headers:s,body:JSON.stringify(i),signal:a.signal}),t.requestTotalTimeoutMs,"ACode LLM summarization",()=>{r=!0,a.abort()});if(!l.ok){const m=await E(l.text(),t.requestTimeoutMs,"ACode LLM summarization error response body",()=>{r=!0,a.abort()}),h=m.length>500?`${m.slice(0,500)}...(truncated, total ${m.length} chars)`:m;throw new Error(`ACode LLM summarization request failed: ${l.status} ${h}`)}const u=(await E(l.json(),t.requestTimeoutMs,"ACode LLM summarization response body",()=>{r=!0,a.abort()})).choices?.[0]?.message?.content;if(!u||u.trim().length===0)throw new Error("ACode LLM summarization returned empty content");return u})(),t.requestTotalTimeoutMs,"ACode LLM summarization total",()=>{a.abort()})}catch(l){throw l instanceof Error&&l.name==="AbortError"?r?new Error(`ACode LLM summarization timed out after ${t.requestTimeoutMs}ms`):new Error("ACode LLM summarization aborted"):l}finally{this.abortController===a&&(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:i,inputLimit:a,threshold:r}=ge(t),l=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,c=se(this.state.conversation)+Ge(this.state.exposedTools),u=Math.max(l,c);if(this.turnSkipProactiveCompaction||this.state.skipNextCompaction)this.state.skipNextCompaction=!1,d("[ACodeRuntime] \u{1F507} Compaction skipped: retry turn flagged skipProactiveCompaction (timeout/request retries must not mutate context, incl. byte-cap truncation)");else{const C=u>=r;if(d(`[ACodeRuntime] \u{1F50D} Compaction check: actualUsed=${l}, estimation=${c}, effectiveUsed=${u}, contextLimit=${s}, inputLimit=${a??"n/a"}, maxOutput=${i}, triggerThreshold=${r}, shouldCompact=${C}`),C){const M=V(this.state.conversation),v=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:v,sizeKB:M,estimatedTokens:c,actualInputTokens:this.state.accumulatedInputTokens,actualOutputTokens:this.state.accumulatedOutputTokens,messageCount:this.state.conversation.length,model:t.model,trigger:l>=r?"actual_usage":"estimated_overflow"}),this.emitCompactionPhase(v,"detect","\u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6709\u6548\u7528\u91CF: ${u} tokens, \u9608\u503C: ${r}, \u89E6\u53D1: ${l>=r?"\u5B9E\u9645\u7528\u91CF":"\u4F30\u7B97\u6EA2\u51FA"}`);const w=await ke(this.state.conversation,s,i,{llmSummarizer:N=>this.summarizeConversationWithLLM(N),onPhase:N=>this.handleCompactionPhase(v,N),actualUsedTokens:u}),q=V(this.state.conversation);this.emitAcodeEvent("context_compaction",{action:"end",compactionId:v,sizeBeforeKB:M,sizeAfterKB:q,freedKB:Math.round((M-q)*10)/10,strategy:w.strategy,freedTokens:w.freedTokens,tokensBefore:w.tokensBefore,tokensAfter:w.tokensAfter,prunedToolMessages:w.prunedToolMessages,summarizedMessages:w.summarizedMessages,messageCountBefore:w.messageCountBefore,messageCountAfter:w.messageCountAfter}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}const b=await Eo(this.state.conversation,je,s,i,M=>this.summarizeConversationWithLLM(M));b>0&&(this.emitAcodeEvent("warning",{message:`Conversation truncated: removed ${b} older messages to fit within ${je} byte request size limit`}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0)}const m=xo(this.state.conversation);(m.orphanToolMessages>0||m.repairedToolCalls>0||m.downgradedAssistants>0)&&(d(`[ACodeRuntime] \u{1FA79} sanitizeToolCallSequence: orphanTools=${m.orphanToolMessages} repairedCalls=${m.repairedToolCalls} downgradedAssistants=${m.downgradedAssistants}`),this.emitAcodeEvent("warning",{message:`\u68C0\u6D4B\u5230\u5DE5\u5177\u8C03\u7528\u5E8F\u5217\u4E0D\u5B8C\u6574\uFF0C\u5DF2\u81EA\u52A8\u4FEE\u590D\uFF08\u5B64\u513F\u5DE5\u5177\u7ED3\u679C ${m.orphanToolMessages} \u6761\u3001\u8865\u5360\u4F4D\u7ED3\u679C ${m.repairedToolCalls} \u4E2A\u3001\u964D\u7EA7 assistant \u6D88\u606F ${m.downgradedAssistants} \u6761\uFF09\uFF0C\u907F\u514D provider 400 (tool_call_sequence_broken) \u6B7B\u5FAA\u73AF\u3002`}));const h=this.state.exposedTools.filter(C=>this.toolGroupManager&&!this.toolGroupManager.shouldShowToLLMByName(C.exposedName)?!1:bo(C,this.state.permissions,e)),A=()=>{const C={model:t.model,messages:this.state.conversation,stream:t.stream};return t.effort&&(C.reasoning_effort=t.effort),t.stream&&(C.stream_options={include_usage:!0}),h.length>0&&(C.tools=Xe(h),C.tool_choice="auto"),C},f="POST",p=wo(o),k=zo(t),T=jo(k),y=C=>{const b=JSON.stringify(C,null,2);d(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 emitAiRequest: \u53D1\u9001\u8BF7\u6C42 model=${t.model}, endpoint=${p}, messageCount=${this.state.conversation.length}`),this.emitAcodeEvent("ai_request",{model:t.model,endpoint:p,requestMethod:f,requestUrl:p,requestHeaders:T,stream:t.stream,messageCount:this.state.conversation.length,toolCount:h.length,lastUserMessagePreview:ko(this.state.conversation),estimatedContextTokens:Te(b),requestBody:b,...this.lastIterationUsage?{lastUsage:this.lastIterationUsage}:{}}),J(`ai_request emitted: model=${t.model} stream=${t.stream} messageCount=${this.state.conversation.length} toolCount=${h.length} estimatedContextTokens=${Te(b)} lastUsage=${JSON.stringify(this.lastIterationUsage??null)}`)};let _=A();y(_);const R=t.requestRetryCount===fe,x=R?1/0:t.requestRetryCount+1;let S=!1;for(let C=1;R||C<=x;C+=1){this.state.terminated||(this.abortRequested=!1),C>1&&y(_);const b=new AbortController;this.abortController=b;let M=!1;try{const v=await E((async()=>{const q=t.stream?t.requestFirstByteTimeoutMs:t.requestTotalTimeoutMs,N=await E(fetch(ce(o),{method:f,headers:k,body:JSON.stringify(_),signal:b.signal}),q,"ACode provider request",()=>{M=!0,b.abort()});if(!N.ok){const j=await E(N.text(),t.requestStreamIdleTimeoutMs,"ACode provider error response body",()=>{M=!0,b.abort()}),te=j.length>500?`${j.slice(0,500)}...(truncated, total ${j.length} chars)`:j;throw new Error(`ACode provider request failed: ${N.status} ${te}`)}const H=N.headers?.get?.("content-type")||"";if(t.stream&&H.toLowerCase().includes("text/event-stream"))return await this.readChatCompletionStream(N,t.requestStreamIdleTimeoutMs,b,t.requestFirstByteTimeoutMs);const F=await E(N.json(),t.requestStreamIdleTimeoutMs,"ACode provider response body",()=>{M=!0,b.abort()});if(!$(F))return this.emitAcodeEvent("warning",{message:`ACode provider returned invalid response format (expected object, got ${typeof F}); treating as empty response`}),{};const ee=Ze(F);if(ee)throw new Error(`ACode provider request failed: ${ee}`);return F})(),t.requestTotalTimeoutMs,"ACode provider request total",()=>{b.abort()}),w=vt({finishReason:v.choices?.[0]?.finish_reason,stopReason:v.choices?.[0]?.stop_reason});if(w.kind==="context_overflow"){if(!S&&await this.compactForContextOverflow({contextLimit:s,trigger:"finish_reason_context_overflow",warningMessage:`ACode provider reported context overflow via ${w.source} (${w.marker}); summarized older messages and rebuilt the request instead of accepting the truncated payload`})>0){S=!0,_=A(),y(_),C-=1;continue}this.emitAcodeEvent("warning",{message:`ACode provider reported context overflow via ${w.source} (${w.marker}), but no further compaction was possible`})}return v}catch(v){let w;if(v instanceof Error&&v.name==="AbortError"?M?w=new Error(`ACode provider request timed out (firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):this.state.terminated?w=new Error("ACode provider request aborted by user"):w=new Error(`ACode provider request timed out (watchdog abort, firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):w=v instanceof Error?v:new Error(String(v)),!S&&!this.abortRequested&&!this.state.terminated&&(pe(v)||pe(w))){if(await this.compactForContextOverflow({contextLimit:s,trigger:"provider_overflow_error",warningMessage:"ACode provider context limit exceeded; summarized older messages and rebuilt the request instead of retrying the same oversized payload"})===0)throw w;S=!0,_=A(),y(_),C-=1;continue}if(!((R||C<x)&&!this.abortRequested&&!this.state.terminated&&Io(w)))throw w;this.emitAcodeEvent("error",{message:`ACode provider request attempt ${C}${R?"":`/${x}`} failed; retrying: ${w.message}`,nonFatal:!0});const N=Math.min(Gt,Jt*Math.pow(2,C-1)),H=Math.random()*1e3;await oo(N+H)}finally{this.abortController===b&&(this.abortController=null)}}throw new Error("ACode provider request failed after all retries")}async compactForContextOverflow(e){const{contextLimit:t,trigger:o,warningMessage:s}=e,i=V(this.state.conversation),a=se(this.state.conversation),r=this.state.conversation.length,l=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:l,sizeKB:i,estimatedTokens:a,messageCount:r,model:this.state.provider.model,trigger:o}),this.emitCompactionPhase(l,"detect","\u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6D88\u606F: ${r}\u6761, \u5927\u5C0F: ${i}KB`),this.emitCompactionPhase(l,"prune","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA","\u6B63\u5728\u88C1\u526A...");const c=Mt(this.state.conversation,t);this.emitCompactionPhase(l,"prune_done","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA",`\u88C1\u526A\u4E86 ${c.prunedCount} \u6761\u5DE5\u5177\u8F93\u51FA, \u91CA\u653E ${c.freedTokens} tokens`),this.emitCompactionPhase(l,"summarize","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD","\u6B63\u5728\u6458\u8981...");const u=await Se(this.state.conversation,{llmSummarizer:p=>this.summarizeConversationWithLLM(p),contextLimit:t});this.emitCompactionPhase(l,"summarize_done","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD",`\u6458\u8981\u5316\u4E86 ${u} \u6761\u6D88\u606F`);const m=V(this.state.conversation),h=se(this.state.conversation),A=this.state.conversation.length,f=c.prunedCount+u;return this.emitAcodeEvent("context_compaction",{action:"end",compactionId:l,sizeBeforeKB:i,sizeAfterKB:m,freedKB:Math.round((i-m)*10)/10,tokensBefore:a,tokensAfter:h,messageCountBefore:r,messageCountAfter:A,strategy:u>0?"summarize":"prune",freedTokens:c.freedTokens,prunedToolMessages:c.prunedCount,summarizedMessages:u,trigger:o}),f===0?0:(this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0,this.emitAcodeEvent("warning",{message:s}),f)}async readChatCompletionStream(e,t,o,s){if(!e.body)throw new Error("ACode provider stream response has no body");const i=e.body.getReader(),a=new TextDecoder,r=new Map;let l="",c="",u,m,h;const A=p=>{for(const k of Go(p)){if(k==="[DONE]")continue;const T=JSON.parse(k);if(!$(T))continue;const y=Ze(T);if(y)throw o?.abort(),new Error(`ACode provider request failed: ${y}`);const _=T.usage;_&&(u=jt(u,_),J(`stream usage chunk received: ${JSON.stringify(_)} -> merged: ${JSON.stringify(u)}`));const R=T.choices?.[0];typeof R?.finish_reason=="string"&&R.finish_reason&&(m=R.finish_reason),typeof R?.stop_reason=="string"&&R.stop_reason&&(h=R.stop_reason);const x=R?.delta,S=Lo(x);S&&this.emitAcodeEvent("thinking_delta",{text:S});const C=typeof x?.content=="string"?x.content:"";C&&(l+=C,this.emitAcodeEvent("assistant_delta",{text:C}));const b=Array.isArray(x?.tool_calls)?x.tool_calls:[];for(const M of b)Ko(r,M)}};let f=!0;for(;;){const p=f&&s?s:t,{done:k,value:T}=await E(i.read(),p,f?"ACode provider stream first byte":"ACode provider stream idle",()=>o?.abort());if(f=!1,k)break;c+=a.decode(T,{stream:!0});const y=c.split(/\r?\n\r?\n/);c=y.pop()??"";for(const _ of y)A(_)}return c+=a.decode(),c.trim()&&A(c),{choices:[{message:{content:l||null,tool_calls:Ho(r)},...m?{finish_reason:m}:{},...h?{stop_reason:h}:{}}],...u?{usage:u}:{}}}async handleToolCalls(e,t,o=this.contextVersion){d(`[ACodeRuntime] handleToolCalls started with ${e.length} tool(s)`);const s=[];for(const i of e){if(this.isTurnSuperseded(o))break;s.push(await this.prepareToolCall(i,t,o))}for(let i=s.length;i<e.length;i++)s.push({toolCall:e[i],tool:void 0,arguments:{},mode:"blocking",scope:"unknown",access:"exclusive",claims:[],immediateError:void 0});this.toolConcurrencyEnabled&&s.length>1?await this.executePreparedToolCallsConcurrently(s,o):await this.executePreparedToolCallsSerially(s,o),d(`[ACodeRuntime] handleToolCalls completed for all ${e.length} tool(s)`)}async executePreparedToolCallsConcurrently(e,t){const o=e.map(u=>({toolCallId:u.toolCall.id,toolName:u.tool?.exposedName??u.toolCall.function.name,mode:u.mode,scope:u.scope,claims:u.claims})),s=this.toolConcurrencyScheduler.schedule(o),i=`toolbatch-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`,a=new Ne(i);for(const u of e)a.register({toolCallId:u.toolCall.id,toolName:u.tool?.exposedName??u.toolCall.function.name,mode:u.mode,resourceKeys:(s.plans.get(u.toolCall.id)?.claims??[]).map(m=>m.key)});const r=new Map,l=new Map(e.map(u=>[u.toolCall.id,u]));for(const u of s.waves){if(this.isTurnSuperseded(t))break;const m=u.planIds.map(A=>l.get(A)).filter(A=>A!==void 0);if(m.length===0)continue;(await Promise.allSettled(m.map(A=>this.executeOnePreparedTool(A,a,t)))).forEach((A,f)=>{const p=m[f];r.set(p.toolCall.id,A.status==="fulfilled"?A.value:{toolCallId:p.toolCall.id,status:"failed",error:A.reason})})}await this.commitPreparedToolOutcomes(e,r,a,t);const c=a.finalize();d(`[ACodeRuntime] \u26A1 Tool batch ${i}: tools=${c.toolCount} speedup=${c.speedup}x parallelism=${c.parallelism}x wall=${c.wallClockMs}ms contentions=${c.contentionCount} failures=${c.failureCount}`),this.emitAcodeEvent("mcp_status",{action:"tool_batch_metrics",server:"builtin",batchId:i,toolCount:c.toolCount,parallelism:c.parallelism,speedup:c.speedup,wallClockMs:c.wallClockMs,totalWaitMs:c.totalWaitMs,contentionCount:c.contentionCount,failureCount:c.failureCount,maxConcurrentObserved:c.maxConcurrentObserved,traces:c.traces.map(u=>({toolCallId:u.toolCallId,toolName:u.toolName,mode:u.mode,resourceKeys:u.resourceKeys,waitMs:u.waitDurationMs,runMs:u.executionDurationMs,status:u.status}))})}async executePreparedToolCallsSerially(e,t){const o=new Ne(`toolbatch-serial-${Date.now().toString(36)}`),s=new Map;for(const i of e)o.register({toolCallId:i.toolCall.id,toolName:i.tool?.exposedName??i.toolCall.function.name,mode:i.mode,resourceKeys:i.claims.map(a=>a.key)}),!this.isTurnSuperseded(t)&&s.set(i.toolCall.id,await this.executeOnePreparedTool(i,o,t));await this.commitPreparedToolOutcomes(e,s,o,t)}async commitPreparedToolOutcomes(e,t,o,s){for(const i of e){if(this.isTurnSuperseded(s)){this.commitSupersededToolResult(i),o.transition(i.toolCall.id,"superseded");continue}const a=t.get(i.toolCall.id);if(!a){await this.commitToolOutcome(i,{toolCallId:i.toolCall.id,status:"failed",error:i.immediateError??new Error("Tool was not executed")},s),o.transition(i.toolCall.id,"committed");continue}o.transition(i.toolCall.id,"committing"),await this.commitToolOutcome(i,a,s),o.transition(i.toolCall.id,"committed")}}async executeOnePreparedTool(e,t,o){if(e.immediateError!==void 0||!e.tool){t.transition(e.toolCall.id,"failed");const r=e.immediateError??new Error("Tool not found");return t.setError(e.toolCall.id,r instanceof Error?r.message:String(r)),{toolCallId:e.toolCall.id,status:"failed",error:r}}t.transition(e.toolCall.id,"waiting_resource");const s=await this.toolResourceLock.acquire(e.claims,e.access),i=this.resolveToolLimiter(e),a=i?await i.acquire():()=>{};try{if(this.isTurnSuperseded(o))return{toolCallId:e.toolCall.id,status:"superseded"};t.transition(e.toolCall.id,"running");const r=e.tool.kind==="builtin"?await this.runBuiltInToolCall(e,o):await this.runMcpToolCall(e,o);return t.transition(e.toolCall.id,r.status),r.error!==void 0&&t.setError(e.toolCall.id,r.error instanceof Error?r.error.message:String(r.error)),r}catch(r){const l=r instanceof Error?r.message:String(r);return d(`[ACodeRuntime] \u274C Tool ${e.tool.exposedName} threw unexpectedly: ${l}`),t.transition(e.toolCall.id,"failed"),t.setError(e.toolCall.id,l),{toolCallId:e.toolCall.id,status:"failed",error:r}}finally{a(),s()}}resolveToolLimiter(e){return e.tool?.kind!=="builtin"?null:e.mode==="read"?this.toolReadOnlyLimiter:e.tool.toolName==="Bash"?this.toolBashLimiter:null}async prepareToolCall(e,t,o){const s=e.function.name;let i=this.state.exposedTools.find(c=>c.exposedName===s);i||(i=this.state.exposedTools.find(c=>c.toolName===s),i&&d(`[ACodeRuntime] \u21A9\uFE0F \u88F8\u540D\u56DE\u9000\u5339\u914D: ${s} -> ${i.exposedName}`));const a=So(e.function.arguments),r={toolCall:e,tool:i,arguments:a,mode:"exclusive",scope:"exact",access:"exclusive",claims:[],immediateError:void 0};if(!i)return console.error(`[ACodeRuntime] \u274C Tool not found: ${s}, available tools: ${this.state.exposedTools.map(c=>c.exposedName).join(", ")}`),r.immediateError=`ACode MCP tool not found: ${s}`,r;if(i.kind==="mcp"&&!this.state.mcpConnections.find(u=>u.serverName===i.serverName))return console.error(`[ACodeRuntime] \u274C MCP server not connected: ${i.serverName}, connected servers: ${this.state.mcpConnections.map(u=>u.serverName).join(", ")}`),r.immediateError=`ACode MCP server not connected: ${i.serverName}`,r;try{Ve(i,this.state.permissions,t);const c=await this.hookBus.dispatch("PreToolUse",{source:i.kind==="mcp"?"mcp":"builtin",...i.kind==="mcp"?{serverName:i.serverName}:{},toolName:i.toolName,exposedName:i.exposedName,arguments:a}),u=$e(c);if(u)throw console.error(`[ACodeRuntime] \u274C Tool denied by hook: ${i.exposedName}: ${u.message}`),new Error(u.message||`ACode tool denied by hook: ${i.exposedName}`)}catch(c){return r.immediateError=c,r}if(this.isTurnSuperseded(o))return r;const l=this.resolveToolConcurrencyDeclaration(i,a);return r.mode=l.mode,r.scope=l.scope,r.access=l.access,r.claims=l.claims,this.emitAcodeEvent("mcp_status",{action:"call_tool",server:i.kind==="mcp"?i.serverName:"builtin",tool:i.toolName,exposedName:i.exposedName,toolUseId:e.id,arguments:a,argumentsPreview:Do(a)}),r}resolveToolConcurrencyDeclaration(e,t){if(e.kind!=="builtin")return ve(e.toolName)==="poll_message"||Me(e.toolName)?{mode:"blocking",scope:"unknown",access:"exclusive",claims:[]}:{mode:"exclusive",scope:"unknown",access:"exclusive",claims:[]};const o=e.concurrencyMode,s=e.resourceScope??"exact";if(!o)return{mode:"exclusive",scope:s,access:"exclusive",claims:[]};if(o==="blocking")return{mode:"blocking",scope:s,access:"exclusive",claims:[]};const i=o;let a=[];if(e.resourceKeys)try{a=e.resourceKeys(t)??[]}catch(r){d(`[ACodeRuntime] \u26A0\uFE0F resourceKeys() threw for ${e.exposedName}, falling back to exclusive: ${r instanceof Error?r.message:String(r)}`),a=[]}return a.length===0&&s==="unknown"?{mode:"exclusive",scope:s,access:"exclusive",claims:[]}:{mode:o,scope:s,access:i,claims:a}}async runBuiltInToolCall(e,t){const o=e.tool;if(o.kind!=="builtin")return{toolCallId:e.toolCall.id,status:"failed",error:new Error("not builtin")};const s=e.arguments,i=$o(o,s,this.state.provider.mcpToolTimeoutMs);i<=0&&console.warn(`[ACodeRuntime] \u26A0\uFE0F Built-in tool ${o.exposedName} has NO timeout (timeoutMs=${i})!`);const a=this.beginToolSettle(o,s,e.toolCall.id);try{const r=await E(o.execute(s,{onOutput:l=>{this.emitAcodeEvent("command_output",{server:"builtin",tool:o.toolName,exposedName:o.exposedName,toolUseId:e.toolCall.id,stream:l.stream,text:l.text,sequence:l.sequence,cwd:l.cwd,commandLineCount:l.commandLineCount,...l.commandFilePath?{commandFilePath:l.commandFilePath}:{}})},toolCallId:e.toolCall.id,...a.signal?{settleSignal:a.signal}:{}}),i,`ACode built-in tool ${o.toolName}`);return{toolCallId:e.toolCall.id,status:"completed",resultText:B(r)}}catch(r){return this.classifyToolError(e,r)}finally{this.clearToolSettle(a.seq,e.toolCall.id)}}async runMcpToolCall(e,t){const o=e.tool;if(o.kind!=="mcp")return{toolCallId:e.toolCall.id,status:"failed",error:new Error("not mcp")};const s=this.state.mcpConnections.find(c=>c.serverName===o.serverName);if(!s)return{toolCallId:e.toolCall.id,status:"failed",error:new Error(`ACode MCP server not connected: ${o.serverName}`)};const i=e.arguments,a=It(o.toolName),r=Me(o.toolName),l=a?this.state.provider.mcpPollingToolTimeoutMs:r?0:this.state.provider.mcpToolTimeoutMs;try{const c=a&&ve(o.toolName)==="poll_message"?await this.callPollMessageWithSubAgentRace(s,o,i,l):await this.callMcpToolWithTimeout(s,o,i,l,a);let u=B(c);return a&&(u=this.expandCommandsInPolledResult(u)),{toolCallId:e.toolCall.id,status:"completed",resultText:u}}catch(c){return this.classifyToolError(e,c)}}classifyToolError(e,t){const s=(t instanceof Error?t.message:String(t)).includes("timed out after")?"timeout":t instanceof Error&&t.name==="AbortError"?"aborted":"failed";return{toolCallId:e.toolCall.id,status:s,error:t}}async commitToolOutcome(e,t,o){const s=e.tool,i=s?.kind==="mcp"?s.serverName:"builtin",a=s?.toolName??e.toolCall.function.name;if(t.status==="completed"&&t.resultText!==void 0){const c=t.resultText;s&&await this.hookBus.dispatch("PostToolUse",{source:s.kind==="mcp"?"mcp":"builtin",...s.kind==="mcp"?{serverName:s.serverName}:{},toolName:s.toolName,exposedName:s.exposedName,result:c}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:i,tool:a,toolUseId:e.toolCall.id,result:c}),this.state.conversation.push({role:"tool",tool_call_id:e.toolCall.id,content:c}),await this.appendSyntheticMultimodalUserMessage(c,e.toolCall.id,o);return}if(t.status==="superseded"){this.commitSupersededToolResult(e);return}const r=t.error??new Error("Tool execution failed"),l=r instanceof Error?r.message:String(r);if(this.abortRequested||this.state.terminated){this.emitAcodeEvent("mcp_status",{action:"tool_result",server:i,tool:a,toolUseId:e.toolCall.id,result:`[aborted] ${l}`,failed:!0,aborted:!0}),this.state.conversation.push({role:"tool",tool_call_id:e.toolCall.id,content:`[aborted] ${l}`});return}if(!s){this.state.conversation.push({role:"tool",tool_call_id:e.toolCall.id,content:l}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:i,tool:a,toolUseId:e.toolCall.id,result:l,failed:!0});return}this.appendToolFailureResult(e.toolCall,s,r)}commitSupersededToolResult(e){const t=e.immediateError!==void 0?`[cancelled] ${e.immediateError instanceof Error?e.immediateError.message:String(e.immediateError)}`:"[cancelled] Tool execution was superseded by a newer turn.";this.state.conversation.push({role:"tool",tool_call_id:e.toolCall.id,content:t}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:e.tool?.kind==="mcp"?e.tool.serverName:"builtin",tool:e.tool?.toolName??e.toolCall.function.name,toolUseId:e.toolCall.id,result:t,failed:!0,aborted:!0})}async executeSingleToolByName(e,t,o){let s=this.state.exposedTools.find(a=>a.exposedName===e);if(s||(s=this.state.exposedTools.find(a=>a.toolName===e)),!s)throw new Error(`Tool not found: ${e}`);if(s.kind==="builtin")return s.execute(t,{toolCallId:o?.toolCallId});const i=this.state.mcpConnections.find(a=>a.serverName===s.serverName);if(!i)throw new Error(`MCP server not found: ${s.serverName}`);return this.callMcpToolWithTimeout(i,s,t,this.state.provider.mcpToolTimeoutMs,!1)}async callMcpToolWithTimeout(e,t,o,s,i,a){const r=s>0?s:Kt,c=!!this.config.sharedMcpConnections?{...o,_aws_sub_agent:!0}:o;for(;;){const u=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:r,...a?{signal:a}:{}}),u.promise]),s,`ACode MCP tool ${t.serverName}/${t.toolName}`)}catch(m){if(a?.aborted||!i||s>0||!No(m))throw m;this.emitAcodeEvent("warning",{message:`ACode MCP polling tool ${t.serverName}/${t.toolName} reached the MCP SDK timeout window and will continue polling.`})}finally{u.cancel()}}}static formatSubAgentCompletionAsPollResult(e){const t=e.map(o=>{const s=o.error?`Sub-agent ${o.subId} [${o.status}]: ${o.description}
|
|
22
|
+
`+zt}]},i=new AbortController;this.abortController=i;let a=!1;try{return await R((async()=>{const l=await R(fetch(_e(o),{method:"POST",headers:s,body:JSON.stringify(r),signal:i.signal}),t.requestTotalTimeoutMs,"ACode LLM summarization",()=>{a=!0,i.abort()});if(!l.ok){const m=await R(l.text(),t.requestTimeoutMs,"ACode LLM summarization error response body",()=>{a=!0,i.abort()}),h=m.length>500?`${m.slice(0,500)}...(truncated, total ${m.length} chars)`:m;throw new Error(`ACode LLM summarization request failed: ${l.status} ${h}`)}const c=(await R(l.json(),t.requestTimeoutMs,"ACode LLM summarization response body",()=>{a=!0,i.abort()})).choices?.[0]?.message?.content;if(!c||c.trim().length===0)throw new Error("ACode LLM summarization returned empty content");return c})(),t.requestTotalTimeoutMs,"ACode LLM summarization total",()=>{i.abort()})}catch(l){throw l instanceof Error&&l.name==="AbortError"?a?new Error(`ACode LLM summarization timed out after ${t.requestTimeoutMs}ms`):new Error("ACode LLM summarization aborted"):l}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:r,inputLimit:i,threshold:a}=Ce(t),l=this.state.accumulatedInputTokens+this.state.accumulatedOutputTokens,u=j(this.state.conversation)+ce(this.state.exposedTools),c=Math.max(l,u),m=c>=a;if(p(`[ACodeRuntime] \u{1F50D} Compaction check: actualUsed=${l}, estimation=${u}, effectiveUsed=${c}, contextLimit=${s}, inputLimit=${i??"n/a"}, maxOutput=${r}, triggerThreshold=${a}, shouldCompact=${m}`),m){const b=Y(this.state.conversation),E=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:E,sizeKB:b,estimatedTokens:u,actualInputTokens:this.state.accumulatedInputTokens,actualOutputTokens:this.state.accumulatedOutputTokens,messageCount:this.state.conversation.length,model:t.model,trigger:l>=a?"actual_usage":"estimated_overflow"}),this.emitCompactionPhase(E,"detect","\u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6709\u6548\u7528\u91CF: ${c} tokens, \u9608\u503C: ${a}, \u89E6\u53D1: ${l>=a?"\u5B9E\u9645\u7528\u91CF":"\u4F30\u7B97\u6EA2\u51FA"}`);const N=await Ae(this.state.conversation,s,r,{llmSummarizer:$=>this.summarizeConversationWithLLM($),onPhase:$=>this.handleCompactionPhase(E,$),actualUsedTokens:c}),L=Y(this.state.conversation);this.emitAcodeEvent("context_compaction",{action:"end",compactionId:E,sizeBeforeKB:b,sizeAfterKB:L,freedKB:Math.round((b-L)*10)/10,strategy:N.strategy,freedTokens:N.freedTokens,tokensBefore:N.tokensBefore,tokensAfter:N.tokensAfter,prunedToolMessages:N.prunedToolMessages,summarizedMessages:N.summarizedMessages,messageCountBefore:N.messageCountBefore,messageCountAfter:N.messageCountAfter}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0,N.summarizedMessages>0&&await this.rebuildRuntimeResourcesMessage()}const h=wo(s);let y=bo()||m;if(!y){const b=Oe(this.state.conversation);b>Ze?y=!0:b>h&&p(`[ACodeRuntime] \u23ED\uFE0F Byte-cap truncation skipped: body ${b}B > cap ${h}B, but effectiveUsed ${c} < threshold ${a} (aligned with frontend compression marker; rely on provider 413/overflow fallback)`)}let C=ct,d=0,f=0,g=0;if(y&&(d=Y(this.state.conversation),f=j(this.state.conversation),g=this.state.conversation.length,C=await ts(this.state.conversation,h,s,r,b=>this.summarizeConversationWithLLM(b),()=>this.rebuildRuntimeResourcesMessage())),C.truncatedCount>0){const b=`compaction-bytes-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:b,sizeKB:d,estimatedTokens:f,actualInputTokens:this.state.accumulatedInputTokens,actualOutputTokens:this.state.accumulatedOutputTokens,messageCount:g,model:t.model,trigger:"request_body_byte_limit"}),this.emitCompactionPhase(b,"byte_limit_detect","\u68C0\u6D4B\u5230\u8BF7\u6C42\u4F53\u8D85\u9650",`\u8BF7\u6C42\u4F53\u8D85\u8FC7 ${h} \u5B57\u8282\u4E0A\u9650\uFF0C\u5373\u5C06\u88C1\u526A\u5386\u53F2`,"request_body_byte_limit");const E=Y(this.state.conversation),N=j(this.state.conversation);this.emitAcodeEvent("context_compaction",{action:"end",compactionId:b,sizeBeforeKB:d,sizeAfterKB:E,freedKB:Math.round((d-E)*10)/10,strategy:C.strategy,freedTokens:C.freedTokens,tokensBefore:f,tokensAfter:N,prunedToolMessages:C.prunedToolMessages,summarizedMessages:C.summarizedMessages,messageCountBefore:g,messageCountAfter:this.state.conversation.length,trigger:"request_body_byte_limit"}),this.emitAcodeEvent("warning",{message:`Conversation truncated: removed ${C.truncatedCount} older messages to fit within ${h} byte request size limit`}),this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0}const T=()=>{const b=es(this.state.conversation);(b.orphanToolMessages>0||b.repairedToolCalls>0||b.downgradedAssistants>0||b.relocatedInterruptions>0||b.reorderedToolResults>0)&&(p(`[ACodeRuntime] \u{1FA79} sanitizeToolCallSequence: orphanTools=${b.orphanToolMessages} repairedCalls=${b.repairedToolCalls} downgradedAssistants=${b.downgradedAssistants} relocatedInterruptions=${b.relocatedInterruptions} reorderedToolResults=${b.reorderedToolResults}`),this.emitAcodeEvent("warning",{message:`\u68C0\u6D4B\u5230\u5DE5\u5177\u8C03\u7528\u5E8F\u5217\u4E0D\u5B8C\u6574\uFF0C\u5DF2\u81EA\u52A8\u4FEE\u590D\uFF08\u5B64\u513F\u5DE5\u5177\u7ED3\u679C ${b.orphanToolMessages} \u6761\u3001\u8865\u5360\u4F4D\u7ED3\u679C ${b.repairedToolCalls} \u4E2A\u3001\u964D\u7EA7 assistant \u6D88\u606F ${b.downgradedAssistants} \u6761\u3001\u56DE\u6B63\u7A7F\u63D2\u6D88\u606F ${b.relocatedInterruptions} \u6761\u3001\u56DE\u6B63\u9519\u5E8F\u7ED3\u679C ${b.reorderedToolResults} \u6761\uFF09\uFF0C\u907F\u514D provider 400 (tool_call_sequence_broken) \u6B7B\u5FAA\u73AF\u3002`}))};T();const A=this.state.exposedTools.filter(b=>this.toolGroupManager&&!this.toolGroupManager.shouldShowToLLMByName(b.exposedName)?!1:Ko(b,this.state.permissions,e)),w=()=>{const b={model:t.model,messages:this.state.conversation,stream:t.stream};return t.effort&&(b.reasoning_effort=t.effort),t.stream&&(b.stream_options={include_usage:!0}),A.length>0&&(b.tools=mt(A),b.tool_choice="auto"),b},v="POST",k=Yo(o),M=ds(t),I=ps(M),x=b=>{const E=JSON.stringify(b,null,2);p(`[ACodeRuntime] \u2605\u2605\u2605 DEBUG \u2605\u2605\u2605 emitAiRequest: \u53D1\u9001\u8BF7\u6C42 model=${t.model}, endpoint=${k}, messageCount=${this.state.conversation.length}`),this.emitAcodeEvent("ai_request",{model:t.model,endpoint:k,requestMethod:v,requestUrl:k,requestHeaders:I,stream:t.stream,messageCount:this.state.conversation.length,toolCount:A.length,lastUserMessagePreview:Qo(this.state.conversation),estimatedContextTokens:$e(E),...this.lastIterationUsage?{lastUsage:this.lastIterationUsage}:{}}),te(`ai_request emitted: model=${t.model} stream=${t.stream} messageCount=${this.state.conversation.length} toolCount=${A.length} estimatedContextTokens=${$e(E)} lastUsage=${JSON.stringify(this.lastIterationUsage??null)}`)};let D=w();x(D);const q=t.requestRetryCount===Me,se=q?1/0:t.requestRetryCount+1;let Z=!1;for(let b=1;q||b<=se;b+=1){this.state.terminated||(this.abortRequested=!1),b>1&&x(D);const E=new AbortController;this.abortController=E;let N=!1;try{const L=await R((async()=>{const J=t.stream?t.requestFirstByteTimeoutMs:t.requestTotalTimeoutMs,F=await R(fetch(_e(o),{method:v,headers:M,body:JSON.stringify(D),signal:E.signal}),J,"ACode provider request",()=>{N=!0,E.abort()});if(!F.ok){const _=await R(F.text(),t.requestStreamIdleTimeoutMs,"ACode provider error response body",()=>{N=!0,E.abort()}),P=_.length>500?`${_.slice(0,500)}...(truncated, total ${_.length} chars)`:_,ne=xe(this.state.conversation,F.status,_)??"";throw new Error(`ACode provider request failed: ${F.status} ${P}${ne}`)}const Q=F.headers?.get?.("content-type")||"";if(t.stream&&Q.toLowerCase().includes("text/event-stream"))return await this.readChatCompletionStream(F,t.requestStreamIdleTimeoutMs,E,t.requestFirstByteTimeoutMs);const V=await R(F.json(),t.requestStreamIdleTimeoutMs,"ACode provider response body",()=>{N=!0,E.abort()});if(!S(V))return this.emitAcodeEvent("warning",{message:`ACode provider returned invalid response format (expected object, got ${typeof V}); treating as empty response`}),{};const H=dt(V);if(H){const _=xe(this.state.conversation,F.status,H)??"";throw new Error(`ACode provider request failed: ${H}${_}`)}return V})(),t.requestTotalTimeoutMs,"ACode provider request total",()=>{E.abort()}),$=Kt({finishReason:L.choices?.[0]?.finish_reason,stopReason:L.choices?.[0]?.stop_reason});if($.kind==="context_overflow"){if(!Z&&await this.compactForContextOverflow({contextLimit:s,trigger:"finish_reason_context_overflow",warningMessage:`ACode provider reported context overflow via ${$.source} (${$.marker}); summarized older messages and rebuilt the request instead of accepting the truncated payload`})>0){Z=!0,T(),D=w(),x(D),b-=1;continue}this.emitAcodeEvent("warning",{message:`ACode provider reported context overflow via ${$.source} (${$.marker}), but no further compaction was possible`})}return L}catch(L){let $;if(L instanceof Error&&L.name==="AbortError"?N?$=new Error(`ACode provider request timed out (firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):this.state.terminated?$=new Error("ACode provider request aborted by user"):$=new Error(`ACode provider request timed out (watchdog abort, firstByte=${t.requestFirstByteTimeoutMs}ms, idle=${t.requestStreamIdleTimeoutMs}ms)`):$=L instanceof Error?L:new Error(String(L)),!Z&&!this.abortRequested&&!this.state.terminated&&(be(L)||be($))){if(await this.compactForContextOverflow({contextLimit:s,trigger:"provider_overflow_error",warningMessage:"ACode provider context limit exceeded; summarized older messages and rebuilt the request instead of retrying the same oversized payload"})===0)throw $;Z=!0,T(),D=w(),x(D),b-=1;continue}if(!((q||b<se)&&!this.abortRequested&&!this.state.terminated&&ss($)))throw $;this.emitAcodeEvent("error",{message:`ACode provider request attempt ${b}${q?"":`/${se}`} failed; retrying: ${$.message}`,nonFatal:!0});const F=Math.min(fo,ho*Math.pow(2,b-1)),Q=Math.random()*1e3;await Eo(F+Q)}finally{this.abortController===E&&(this.abortController=null)}}throw new Error("ACode provider request failed after all retries")}async compactForContextOverflow(e){const{contextLimit:t,trigger:o,warningMessage:s}=e,r=Y(this.state.conversation),i=j(this.state.conversation),a=this.state.conversation.length,l=`compaction-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;this.emitAcodeEvent("context_compaction",{action:"start",compactionId:l,sizeKB:r,estimatedTokens:i,messageCount:a,model:this.state.provider.model,trigger:o}),this.emitCompactionPhase(l,"detect","\u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u6EA2\u51FA",`\u6D88\u606F: ${a}\u6761, \u5927\u5C0F: ${r}KB`),this.emitCompactionPhase(l,"prune","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA","\u6B63\u5728\u88C1\u526A...");const u=Jt(this.state.conversation,t);this.emitCompactionPhase(l,"prune_done","\u9636\u6BB51: \u88C1\u526A\u5DE5\u5177\u8F93\u51FA",`\u88C1\u526A\u4E86 ${u.prunedCount} \u6761\u5DE5\u5177\u8F93\u51FA, \u91CA\u653E ${u.freedTokens} tokens`),this.emitCompactionPhase(l,"summarize","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD","\u6B63\u5728\u6458\u8981...");const c=await De(this.state.conversation,{llmSummarizer:d=>this.summarizeConversationWithLLM(d),contextLimit:t});this.emitCompactionPhase(l,"summarize_done","\u9636\u6BB52: \u6458\u8981\u5316\u5BF9\u8BDD",`\u6458\u8981\u5316\u4E86 ${c} \u6761\u6D88\u606F`);const m=Y(this.state.conversation),h=j(this.state.conversation),y=this.state.conversation.length,C=u.prunedCount+c;return this.emitAcodeEvent("context_compaction",{action:"end",compactionId:l,sizeBeforeKB:r,sizeAfterKB:m,freedKB:Math.round((r-m)*10)/10,tokensBefore:i,tokensAfter:h,messageCountBefore:a,messageCountAfter:y,strategy:c>0?"summarize":"prune",freedTokens:u.freedTokens,prunedToolMessages:u.prunedCount,summarizedMessages:c,trigger:o}),C===0?0:(this.state.accumulatedInputTokens=0,this.state.accumulatedOutputTokens=0,c>0&&await this.rebuildRuntimeResourcesMessage(),this.emitAcodeEvent("warning",{message:s}),C)}async rebuildRuntimeResourcesMessage(){const e=this.config.runtimeResourcesProvider;if(!e)return;const t=this.state.conversation;for(let l=t.length-1;l>=0;l--)Wt(t[l])&&t.splice(l,1);let o;try{o=await e()}catch(l){p(`[ACodeRuntime] runtime resources provider failed, snapshot skipped: ${ue(l)}`);return}const s=typeof o=="string"?o.trim():"";if(!s)return;let r=0,i=-1;for(let l=0;l<t.length;l++){const u=t[l];if(u.role!=="system")break;jt(u)&&(i=l),r=l+1}const a=i>=0?i+1:r;t.splice(a,0,{role:"system",content:`${Ht}
|
|
23
|
+
${s}`})}async readChatCompletionStream(e,t,o,s){if(!e.body)throw new Error("ACode provider stream response has no body");const r=e.body.getReader(),i=new TextDecoder,a=new Map;let l="",u="",c,m,h;const y=d=>{for(const f of gs(d)){if(f==="[DONE]")continue;const g=JSON.parse(f);if(!S(g))continue;const T=dt(g);if(T){o?.abort();const x=xe(this.state.conversation,200,T)??"";throw new Error(`ACode provider request failed: ${T}${x}`)}const A=g.usage;A&&(c=co(c,A),te(`stream usage chunk received: ${JSON.stringify(A)} -> merged: ${JSON.stringify(c)}`));const w=g.choices?.[0];typeof w?.finish_reason=="string"&&w.finish_reason&&(m=w.finish_reason),typeof w?.stop_reason=="string"&&w.stop_reason&&(h=w.stop_reason);const v=w?.delta,k=as(v);k&&this.emitAcodeEvent("thinking_delta",{text:k});const M=typeof v?.content=="string"?v.content:"";M&&(l+=M,this.emitAcodeEvent("assistant_delta",{text:M}));const I=Array.isArray(v?.tool_calls)?v.tool_calls:[];for(const x of I)ys(a,x)}};let C=!0;for(;;){const d=C&&s?s:t,{done:f,value:g}=await R(r.read(),d,C?"ACode provider stream first byte":"ACode provider stream idle",()=>o?.abort());if(C=!1,f)break;u+=i.decode(g,{stream:!0});const T=u.split(/\r?\n\r?\n/);u=T.pop()??"";for(const A of T)y(A)}return u+=i.decode(),u.trim()&&y(u),{choices:[{message:{content:l||null,tool_calls:Cs(a)},...m?{finish_reason:m}:{},...h?{stop_reason:h}:{}}],...c?{usage:c}:{}}}async handleToolCalls(e,t,o=this.contextVersion){p(`[ACodeRuntime] handleToolCalls started with ${e.length} tool(s)`);const s=e.filter(l=>!ke(l.function.name)),r=l=>!ke(l.function.name),i=this.toolConcurrencyEnabled&&s.length>1?{batchId:ot(),toolCount:s.length}:void 0;i&&!this.isTurnSuperseded(o)&&this.emitToolBatchStart(i,s);const a=[];for(const l of e){if(this.isTurnSuperseded(o))break;a.push(await this.prepareToolCall(l,t,o,r(l)?i:void 0))}for(let l=a.length;l<e.length;l++){const u=e[l];a.push({toolCall:u,batchId:r(u)?i?.batchId:void 0,tool:void 0,arguments:{},mode:"blocking",scope:"unknown",access:"exclusive",claims:[],immediateError:void 0})}this.toolConcurrencyEnabled&&a.length>1?await this.executePreparedToolCallsConcurrently(a,o,i):await this.executePreparedToolCallsSerially(a,o),p(`[ACodeRuntime] handleToolCalls completed for all ${e.length} tool(s)`)}emitToolBatchStart(e,t){const o=t.map(s=>s.function.name);p(`[ACodeRuntime] \u{1F9E9} Tool batch ${e.batchId} started: tools=${e.toolCount} [${o.join(", ")}]`),this.emitAcodeEvent("mcp_status",{action:"tool_batch_start",server:"builtin",batchId:e.batchId,toolCount:e.toolCount,toolNames:o})}async executePreparedToolCallsConcurrently(e,t,o){const s=e.map(h=>({toolCallId:h.toolCall.id,toolName:h.tool?.exposedName??h.toolCall.function.name,mode:h.mode,scope:h.scope,claims:h.claims})),r=this.toolConcurrencyScheduler.schedule(s),i=o?.batchId??ot(),a=new je(i),l=new Set(e.filter(h=>!ke(h.toolCall.function.name)).map(h=>h.toolCall.id));for(const h of e)l.has(h.toolCall.id)&&a.register({toolCallId:h.toolCall.id,toolName:h.tool?.exposedName??h.toolCall.function.name,mode:h.mode,resourceKeys:(r.plans.get(h.toolCall.id)?.claims??[]).map(y=>y.key)});const u=new Map,c=new Map(e.map(h=>[h.toolCall.id,h]));for(const h of r.waves){if(this.isTurnSuperseded(t))break;const y=h.planIds.map(d=>c.get(d)).filter(d=>d!==void 0);if(y.length===0)continue;(await Promise.allSettled(y.map(d=>this.executeOnePreparedTool(d,a,t)))).forEach((d,f)=>{const g=y[f];u.set(g.toolCall.id,d.status==="fulfilled"?d.value:{toolCallId:g.toolCall.id,status:"failed",error:d.reason})})}if(await this.commitPreparedToolOutcomes(e,u,a,t),!o)return;const m=a.finalize();p(`[ACodeRuntime] \u26A1 Tool batch ${i}: tools=${m.toolCount} speedup=${m.speedup}x parallelism=${m.parallelism}x wall=${m.wallClockMs}ms contentions=${m.contentionCount} failures=${m.failureCount}`),this.emitAcodeEvent("mcp_status",{action:"tool_batch_metrics",server:"builtin",batchId:i,toolCount:m.toolCount,parallelism:m.parallelism,speedup:m.speedup,wallClockMs:m.wallClockMs,totalWaitMs:m.totalWaitMs,contentionCount:m.contentionCount,failureCount:m.failureCount,maxConcurrentObserved:m.maxConcurrentObserved,traces:m.traces.map(h=>({toolCallId:h.toolCallId,toolName:h.toolName,mode:h.mode,resourceKeys:h.resourceKeys,waitMs:h.waitDurationMs,runMs:h.executionDurationMs,status:h.status}))})}async executePreparedToolCallsSerially(e,t){const o=new je(`toolbatch-serial-${Date.now().toString(36)}`),s=new Map;for(const r of e)o.register({toolCallId:r.toolCall.id,toolName:r.tool?.exposedName??r.toolCall.function.name,mode:r.mode,resourceKeys:r.claims.map(i=>i.key)}),!this.isTurnSuperseded(t)&&s.set(r.toolCall.id,await this.executeOnePreparedTool(r,o,t));await this.commitPreparedToolOutcomes(e,s,o,t)}async commitPreparedToolOutcomes(e,t,o,s){const r=[];for(const i of e){if(this.isTurnSuperseded(s)){this.commitSupersededToolResult(i),o.transition(i.toolCall.id,"superseded");continue}const a=t.get(i.toolCall.id);if(!a){await this.commitToolOutcome(i,{toolCallId:i.toolCall.id,status:"failed",error:i.immediateError??new Error("Tool was not executed")},s,r),o.transition(i.toolCall.id,"committed");continue}o.transition(i.toolCall.id,"committing"),await this.commitToolOutcome(i,a,s,r),o.transition(i.toolCall.id,"committed")}r.length>0&&this.state.conversation.push(...r)}async executeOnePreparedTool(e,t,o){if(e.immediateError!==void 0||!e.tool){t.transition(e.toolCall.id,"failed");const a=e.immediateError??new Error("Tool not found");return t.setError(e.toolCall.id,a instanceof Error?a.message:String(a)),{toolCallId:e.toolCall.id,status:"failed",error:a}}t.transition(e.toolCall.id,"waiting_resource");const s=await this.toolResourceLock.acquire(e.claims,e.access),r=this.resolveToolLimiter(e),i=r?await r.acquire():()=>{};try{if(this.isTurnSuperseded(o))return{toolCallId:e.toolCall.id,status:"superseded"};t.transition(e.toolCall.id,"running");const a=e.tool.kind==="builtin"?await this.runBuiltInToolCall(e,o):await this.runMcpToolCall(e,o);return t.transition(e.toolCall.id,a.status),a.error!==void 0&&t.setError(e.toolCall.id,a.error instanceof Error?a.error.message:String(a.error)),a}catch(a){const l=a instanceof Error?a.message:String(a);return p(`[ACodeRuntime] \u274C Tool ${e.tool.exposedName} threw unexpectedly: ${l}`),t.transition(e.toolCall.id,"failed"),t.setError(e.toolCall.id,l),{toolCallId:e.toolCall.id,status:"failed",error:a}}finally{i(),s()}}resolveToolLimiter(e){return e.tool?.kind!=="builtin"?null:e.mode==="read"?this.toolReadOnlyLimiter:e.tool.toolName==="Bash"?this.toolBashLimiter:null}async prepareToolCall(e,t,o,s){const r=e.function.name;let i=this.state.exposedTools.find(c=>c.exposedName===r);i||(i=this.state.exposedTools.find(c=>c.toolName===r),i&&p(`[ACodeRuntime] \u21A9\uFE0F \u88F8\u540D\u56DE\u9000\u5339\u914D: ${r} -> ${i.exposedName}`));const a=Vo(e.function.arguments),l={toolCall:e,batchId:s?.batchId,tool:i,arguments:a,mode:"exclusive",scope:"exact",access:"exclusive",claims:[],immediateError:void 0};if(i||await this.recoverHiddenMcpTool(r)&&(i=this.state.exposedTools.find(c=>c.exposedName===r)??this.state.exposedTools.find(c=>c.toolName===r),l.tool=i),!i){const c=this.state.exposedTools.map(h=>h.exposedName);console.error(`[ACodeRuntime] \u274C Tool not found: ${r}, available tools: ${c.join(", ")}`);const m=c.slice(0,40).join(", ")+(c.length>40?` \u2026(+${c.length-40} more)`:"");return l.immediateError=`ACode MCP tool not found: ${r}. Available tools: ${m}`,l}if(i.kind==="mcp"&&!this.state.mcpConnections.find(m=>m.serverName===i.serverName))return console.error(`[ACodeRuntime] \u274C MCP server not connected: ${i.serverName}, connected servers: ${this.state.mcpConnections.map(m=>m.serverName).join(", ")}`),l.immediateError=`ACode MCP server not connected: ${i.serverName}`,l;try{lt(i,this.state.permissions,t);const c=await this.hookBus.dispatch("PreToolUse",{source:i.kind==="mcp"?"mcp":"builtin",...i.kind==="mcp"?{serverName:i.serverName}:{},toolName:i.toolName,exposedName:i.exposedName,arguments:a}),m=Le(c);if(m)throw console.error(`[ACodeRuntime] \u274C Tool denied by hook: ${i.exposedName}: ${m.message}`),new Error(m.message||`ACode tool denied by hook: ${i.exposedName}`)}catch(c){return l.immediateError=c,l}if(this.isTurnSuperseded(o))return l;const u=this.resolveToolConcurrencyDeclaration(i,a);return l.mode=u.mode,l.scope=u.scope,l.access=u.access,l.claims=u.claims,this.emitAcodeEvent("mcp_status",{action:"call_tool",server:i.kind==="mcp"?i.serverName:"builtin",tool:i.toolName,exposedName:i.exposedName,toolUseId:e.id,arguments:a,argumentsPreview:rs(a),...l.batchId?{batchId:l.batchId}:{}}),l}resolveToolConcurrencyDeclaration(e,t){if(e.kind!=="builtin")return Se(e.toolName)==="poll_message"||we(e.toolName)?{mode:"blocking",scope:"unknown",access:"exclusive",claims:[]}:{mode:"exclusive",scope:"unknown",access:"exclusive",claims:[]};const o=e.concurrencyMode,s=e.resourceScope??"exact";if(!o)return{mode:"exclusive",scope:s,access:"exclusive",claims:[]};if(o==="blocking")return{mode:"blocking",scope:s,access:"exclusive",claims:[]};const r=o;let i=[];if(e.resourceKeys)try{i=e.resourceKeys(t)??[]}catch(a){p(`[ACodeRuntime] \u26A0\uFE0F resourceKeys() threw for ${e.exposedName}, falling back to exclusive: ${a instanceof Error?a.message:String(a)}`),i=[]}return i.length===0&&s==="unknown"?{mode:"exclusive",scope:s,access:"exclusive",claims:[]}:{mode:o,scope:s,access:r,claims:i}}async runBuiltInToolCall(e,t){const o=e.tool;if(o.kind!=="builtin")return{toolCallId:e.toolCall.id,status:"failed",error:new Error("not builtin")};const s=e.arguments,r=Xo(o,s,this.state.provider.mcpToolTimeoutMs);r<=0&&console.warn(`[ACodeRuntime] \u26A0\uFE0F Built-in tool ${o.exposedName} has NO timeout (timeoutMs=${r})!`);const i=this.beginToolSettle(o,s,e.toolCall.id);try{const a=await R(o.execute(s,{onOutput:l=>{this.emitAcodeEvent("command_output",{server:"builtin",tool:o.toolName,exposedName:o.exposedName,toolUseId:e.toolCall.id,stream:l.stream,text:l.text,sequence:l.sequence,cwd:l.cwd,commandLineCount:l.commandLineCount,...l.commandFilePath?{commandFilePath:l.commandFilePath}:{}})},toolCallId:e.toolCall.id,...i.signal?{settleSignal:i.signal}:{}}),r,`ACode built-in tool ${o.toolName}`);return{toolCallId:e.toolCall.id,status:"completed",resultText:G(a)}}catch(a){return this.classifyToolError(e,a)}finally{this.clearToolSettle(i.seq,e.toolCall.id)}}async runMcpToolCall(e,t){const o=e.tool;if(o.kind!=="mcp")return{toolCallId:e.toolCall.id,status:"failed",error:new Error("not mcp")};const s=this.state.mcpConnections.find(u=>u.serverName===o.serverName);if(!s)return{toolCallId:e.toolCall.id,status:"failed",error:new Error(`ACode MCP server not connected: ${o.serverName}`)};const r=e.arguments,i=Be(o.toolName),a=we(o.toolName),l=i?this.state.provider.mcpPollingToolTimeoutMs:a?0:this.state.provider.mcpToolTimeoutMs;try{const u=await this.withBlockingToolCallTracking(o.toolName,()=>i&&Se(o.toolName)==="poll_message"?this.callPollMessageWithSubAgentRace(s,o,r,l):this.callMcpToolWithTimeout(s,o,r,l,i));let c=G(u);return i&&(c=this.expandCommandsInPolledResult(c)),{toolCallId:e.toolCall.id,status:"completed",resultText:c}}catch(u){return this.classifyToolError(e,u)}}async withBlockingToolCallTracking(e,t){if(!X.isLongBlockingMcpToolName(e))return await t();this.activeBlockingToolCalls+=1;try{return await t()}finally{this.activeBlockingToolCalls-=1}}classifyToolError(e,t){const s=(t instanceof Error?t.message:String(t)).includes("timed out after")?"timeout":t instanceof Error&&t.name==="AbortError"?"aborted":"failed";return{toolCallId:e.toolCall.id,status:s,error:t}}async commitToolOutcome(e,t,o,s=[]){const r=e.tool,i=r?.kind==="mcp"?r.serverName:"builtin",a=r?.toolName??e.toolCall.function.name;if(t.status==="completed"&&t.resultText!==void 0){const c=t.resultText;r&&await this.hookBus.dispatch("PostToolUse",{source:r.kind==="mcp"?"mcp":"builtin",...r.kind==="mcp"?{serverName:r.serverName}:{},toolName:r.toolName,exposedName:r.exposedName,result:c}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:i,tool:a,toolUseId:e.toolCall.id,result:c,...e.batchId?{batchId:e.batchId}:{}}),this.state.conversation.push({role:"tool",tool_call_id:e.toolCall.id,content:c});const m=await this.appendSyntheticMultimodalUserMessage(c,e.toolCall.id,o);m&&s.push(m);return}if(t.status==="superseded"){this.commitSupersededToolResult(e);return}const l=t.error??new Error("Tool execution failed"),u=l instanceof Error?l.message:String(l);if(this.abortRequested||this.state.terminated){this.emitAcodeEvent("mcp_status",{action:"tool_result",server:i,tool:a,toolUseId:e.toolCall.id,result:`[aborted] ${u}`,failed:!0,aborted:!0,...e.batchId?{batchId:e.batchId}:{}}),this.state.conversation.push({role:"tool",tool_call_id:e.toolCall.id,content:`[aborted] ${u}`});return}if(!r){this.state.conversation.push({role:"tool",tool_call_id:e.toolCall.id,content:u}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:i,tool:a,toolUseId:e.toolCall.id,result:u,failed:!0,...e.batchId?{batchId:e.batchId}:{}});return}this.appendToolFailureResult(e.toolCall,r,l,e.batchId)}commitSupersededToolResult(e){const t=e.immediateError!==void 0?`[cancelled] ${e.immediateError instanceof Error?e.immediateError.message:String(e.immediateError)}`:"[cancelled] Tool execution was superseded by a newer turn.";this.state.conversation.push({role:"tool",tool_call_id:e.toolCall.id,content:t}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:e.tool?.kind==="mcp"?e.tool.serverName:"builtin",tool:e.tool?.toolName??e.toolCall.function.name,toolUseId:e.toolCall.id,result:t,failed:!0,aborted:!0,...e.batchId?{batchId:e.batchId}:{}})}async executeSingleToolByName(e,t,o){let s=this.state.exposedTools.find(l=>l.exposedName===e);if(s||(s=this.state.exposedTools.find(l=>l.toolName===e)),!s)throw new Error(`Tool not found: ${e}`);if(s.kind==="builtin")return s.execute(t,{toolCallId:o?.toolCallId});const r=this.state.mcpConnections.find(l=>l.serverName===s.serverName);if(!r)throw new Error(`MCP server not found: ${s.serverName}`);const i=Be(s.toolName),a=i?this.state.provider.mcpPollingToolTimeoutMs:we(s.toolName)?0:this.state.provider.mcpToolTimeoutMs;if(i&&Se(s.toolName)==="poll_message"){const l=await this.withBlockingToolCallTracking(s.toolName,()=>this.callPollMessageWithSubAgentRace(r,s,t,a,{allowRepoll:!1}));return this.expandCommandsInPolledResult(G(l))}return this.withBlockingToolCallTracking(s.toolName,()=>this.callMcpToolWithTimeout(r,s,t,a,i))}async callMcpToolWithTimeout(e,t,o,s,r,i){const a=s>0?s:go,u=!!this.config.sharedMcpConnections?{...o,_aws_sub_agent:!0}:o;for(;;){const c=this.createRuntimeStopWaiter(`ACode MCP tool ${t.serverName}/${t.toolName}`);try{return await R(Promise.race([e.client.callTool({name:t.toolName,arguments:u},void 0,{timeout:a,...i?{signal:i}:{}}),c.promise]),s,`ACode MCP tool ${t.serverName}/${t.toolName}`)}catch(m){if(i?.aborted||!r||s>0||!ns(m))throw m;this.emitAcodeEvent("warning",{message:`ACode MCP polling tool ${t.serverName}/${t.toolName} reached the MCP SDK timeout window and will continue polling.`})}finally{c.cancel()}}}static formatSubAgentCompletionAsPollResult(e){const t=e.map(o=>{const s=o.error?`Sub-agent ${o.subId} [${o.status}]: ${o.description}
|
|
23
24
|
Error: ${o.error}`:`Sub-agent ${o.subId} [${o.status}]: ${o.description}
|
|
24
|
-
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=
|
|
25
|
-
Error: ${
|
|
26
|
-
Output: ${
|
|
27
|
-
`);return
|
|
25
|
+
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=G(e);let s;try{s=JSON.parse(o)}catch{return e}const i=[...t.map(a=>{const l=a.error?`Sub-agent ${a.subId} [${a.status}]: ${a.description}
|
|
26
|
+
Error: ${a.error}`:`Sub-agent ${a.subId} [${a.status}]: ${a.description}
|
|
27
|
+
Output: ${a.output.length>500?a.output.slice(0,500)+"... (truncated)":a.output}`;return{msgId:`subagent-completion-${a.subId}-${Date.now()}`,senderId:"ACode-Runtime",senderName:"\u7CFB\u7EDF",content:l,requireReply:!1,prompt:`Sub-agent ${a.subId} (${a.description}) has reached terminal state: ${a.status}. Review its output and decide next steps.`,timestamp:new Date().toISOString()}}),...s.directMessages??[]];return{content:[{type:"text",text:JSON.stringify({...s,directMessages:i},null,2)}]}}async recheckMemoryDelegate(e,t,o,s){const r=this.state.mcpConnections.find(i=>i.serverName==="aws-client-agent-mcp");if(!r)return p("[ACodeRuntime] recheckMemoryDelegate: aws-client-agent-mcp connection not found, treating as done"),{done:!0};try{return e==="memory_file_change"?await this.recheckMemoryFileChange(r,t):e==="memory_expiration"?await this.recheckMemoryExpiration(r,t):await this.recheckMemoryCleanup(r,t)}catch(i){return p(`[ACodeRuntime] recheckMemoryDelegate failed (type=${e}, turn=${s}): ${i instanceof Error?i.message:String(i)}, treating as NOT done (retry via recheck loop)`),{done:!1,continueMessage:`\u7ECF\u68C0\u67E5\uFF0C\u65E0\u6CD5\u786E\u8BA4\u4EE5\u4E0B memory \u662F\u5426\u5DF2\u5904\u7406\uFF08\u6821\u9A8C\u5F02\u5E38\uFF1A${i instanceof Error?i.message:String(i)}\uFF09\u3002\u8BF7\u91CD\u65B0\u6267\u884C\u9A8C\u8BC1\u6B65\u9AA4\uFF08read_memory / get_memory_stats\uFF09\u786E\u8BA4\u771F\u5B9E\u72B6\u6001\u540E\u518D\u7EE7\u7EED\u3002`}}}async readMemoryViaMcp(e,t){try{const o=await R(e.client.callTool({name:"read_memory",arguments:{uri:t,_aws_sub_agent:!0}},void 0,{timeout:3e4}),3e4,`recheck read_memory ${t}`),s=G(o),r=JSON.parse(s);return r==null||typeof r!="object"||Array.isArray(r)?null:r}catch(o){throw o}}async recheckMemoryFileChange(e,t){const o=[];if(await Promise.all(t.map(async r=>{const i=await this.readMemoryViaMcp(e,r);i&&i.memory_status==="updating"&&o.push(r)})),o.length===0)return p(`[ACodeRuntime] recheck memory_file_change: all ${t.length} URIs done (memory_status=normal or deleted)`),{done:!0};const s=o.map(r=>`- ${r}`).join(`
|
|
28
|
+
`);return p(`[ACodeRuntime] recheck memory_file_change: ${o.length}/${t.length} URIs still updating`),{done:!1,continueMessage:`\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5BF9\u4EE5\u4E0B memory \u7684\u66F4\u65B0\uFF0C\u8BF7\u7EE7\u7EED\uFF1A
|
|
28
29
|
${s}
|
|
29
30
|
|
|
30
|
-
\u8FD9\u4E9B memory \u7684 memory_status \u4ECD\u4E3A "updating"\u3002\u8BF7\u91CD\u65B0 read_memory \u67E5\u770B\u5185\u5BB9\uFF0C\u67E5\u770B\u7ED1\u5B9A\u6587\u4EF6\u6700\u65B0\u5185\u5BB9\uFF0C\u5E76\u8C03\u7528 update_memory \u5B8C\u6210\u66F4\u65B0\u3002`}}async recheckMemoryExpiration(e,t){const o=[],s=Date.now();if(await Promise.all(t.map(async
|
|
31
|
-
`);return
|
|
32
|
-
${
|
|
31
|
+
\u8FD9\u4E9B memory \u7684 memory_status \u4ECD\u4E3A "updating"\u3002\u8BF7\u91CD\u65B0 read_memory \u67E5\u770B\u5185\u5BB9\uFF0C\u67E5\u770B\u7ED1\u5B9A\u6587\u4EF6\u6700\u65B0\u5185\u5BB9\uFF0C\u5E76\u8C03\u7528 update_memory \u5B8C\u6210\u66F4\u65B0\u3002`}}async recheckMemoryExpiration(e,t){const o=[],s=Date.now();if(await Promise.all(t.map(async i=>{const a=await this.readMemoryViaMcp(e,i);if(!a)return;const l=a.expiresAt??a.expires_at,u=a.memory_status==="recalling",c=typeof l=="string"&&new Date(l).getTime()<s;(u||c)&&o.push(i)})),o.length===0)return p(`[ACodeRuntime] recheck memory_expiration: all ${t.length} URIs done (renewed, cleaned, or no longer expired)`),{done:!0};const r=o.map(i=>`- ${i}`).join(`
|
|
32
|
+
`);return p(`[ACodeRuntime] recheck memory_expiration: ${o.length}/${t.length} URIs still expired or recalling`),{done:!1,continueMessage:`\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5BF9\u4EE5\u4E0B memory \u7684\u5904\u7406\uFF0C\u8BF7\u7EE7\u7EED\uFF1A
|
|
33
|
+
${r}
|
|
33
34
|
|
|
34
|
-
\u8FD9\u4E9B memory \u4ECD\u5904\u4E8E\u8FC7\u671F\u6216\u56DE\u5FC6\u4E2D\u72B6\u6001\u3002\u8BF7\u8C03\u7528 memory_recurrence \u83B7\u53D6\u5185\u5BB9\uFF0C\u5BF9\u9700\u8981\u4FDD\u7559\u7684\u8C03\u7528 update_memory \u7EED\u671F\uFF0C\u5BF9\u65E0\u4EF7\u503C\u7684\u8C03\u7528 memory_recurrence_complete \u6E05\u7406\u3002`}}async recheckMemoryCleanup(e,t){let o;try{const
|
|
35
|
-
`);return
|
|
36
|
-
${
|
|
35
|
+
\u8FD9\u4E9B memory \u4ECD\u5904\u4E8E\u8FC7\u671F\u6216\u56DE\u5FC6\u4E2D\u72B6\u6001\u3002\u8BF7\u8C03\u7528 memory_recurrence \u83B7\u53D6\u5185\u5BB9\uFF0C\u5BF9\u9700\u8981\u4FDD\u7559\u7684\u8C03\u7528 update_memory \u7EED\u671F\uFF0C\u5BF9\u65E0\u4EF7\u503C\u7684\u8C03\u7528 memory_recurrence_complete \u6E05\u7406\u3002`}}async recheckMemoryCleanup(e,t){let o;try{const a=await R(e.client.callTool({name:"get_memory_stats",arguments:{_aws_sub_agent:!0}},void 0,{timeout:3e4}),3e4,"recheck get_memory_stats"),l=G(a);o=JSON.parse(l)}catch{return{done:!1,continueMessage:"get_memory_stats \u67E5\u8BE2\u5931\u8D25\uFF0C\u65E0\u6CD5\u786E\u8BA4\u5BB9\u91CF\u662F\u5426\u5DF2\u8FBE\u6807\uFF0C\u8BF7\u91CD\u65B0\u9A8C\u8BC1\u540E\u518D\u7EE7\u7EED\u3002"}}const s=o.by_type??{},r=[];for(const a of t){const l=a.indexOf("/");if(l<0)continue;const u=a.slice(0,l),c=a.slice(l+1),h=s[u]?.by_domain?.[c];h?.exceeded&&r.push(`${u}/${c} (\u5F53\u524D ${h.count??"?"} \u6761\uFF0C\u5EFA\u8BAE\u4E0A\u9650 ${h.limit??"?"})`)}if(r.length===0)return p(`[ACodeRuntime] recheck memory_cleanup: all ${t.length} type/domain pairs within limits`),{done:!0};const i=r.map(a=>`- ${a}`).join(`
|
|
36
|
+
`);return p(`[ACodeRuntime] recheck memory_cleanup: ${r.length}/${t.length} type/domain pairs still exceeded`),{done:!1,continueMessage:`\u7ECF\u68C0\u67E5\uFF0C\u4EE5\u4E0B\u7C7B\u578B/\u57DF\u5C1A\u672A\u6574\u7406\u5B8C\u6210\uFF0C\u8BF7\u7EE7\u7EED\uFF1A
|
|
37
|
+
${i}
|
|
37
38
|
|
|
38
39
|
\u8BF7\u8C03\u7528 list_memories \u67E5\u770B\u8D85\u9650\u8BB0\u5FC6\uFF0C\u5220\u9664\u4E0D\u518D\u9700\u8981\u7684 recently_memory \u6216\u5BF9 agent_memory \u8C03\u7528 update_memory \u7EED\u671F\u3002`}}buildMemoryDelegatePrompt(e){const t=e.uris.map(o=>`- ${o}`).join(`
|
|
39
40
|
`);return e.type==="memory_expiration"?`\u4F60\u662F\u4E00\u6761\u4E13\u95E8\u5904\u7406 memory \u8FC7\u671F\u6574\u7406\u7684\u5B50 agent\u3002
|
|
@@ -87,11 +88,11 @@ ${t}
|
|
|
87
88
|
\u5B8C\u6210\u540E\u7CFB\u7EDF\u4F1A\u901A\u8FC7\u67E5\u8BE2\u670D\u52A1\u7AEF\u771F\u5B9E\u72B6\u6001\u8FDB\u884C\u4E8C\u6B21\u9A8C\u8BC1\uFF08\u4E0D\u4F9D\u8D56\u4F60\u7684\u81EA\u62A5\u7ED3\u679C\uFF09\u3002\u82E5\u9A8C\u8BC1\u53D1\u73B0\u4ECD\u6709\u7C7B\u578B/\u57DF\u8D85\u8FC7\u5BB9\u91CF\u4E0A\u9650\uFF0C\u4F1A\u53D1\u9001 "\u7ECF\u68C0\u67E5\uFF0C\u4EE5\u4E0B\u7C7B\u578B/\u57DF\u5C1A\u672A\u6574\u7406\u5B8C\u6210\uFF0C\u8BF7\u7EE7\u7EED" \u6D88\u606F\u8BA9\u4F60\u7EE7\u7EED\u5904\u7406\u3002`:`\u4F60\u662F\u4E00\u6761\u4E13\u95E8\u5904\u7406\u6C38\u4E45\u8BB0\u5FC6\u6587\u4EF6\u53D8\u66F4\u66F4\u65B0\u7684\u5B50 agent\u3002
|
|
88
89
|
|
|
89
90
|
\u4EE5\u4E0B ${e.uris.length} \u4E2A\u6C38\u4E45\u8BB0\u5FC6\u7ED1\u5B9A\u7684\u6587\u4EF6\u5DF2\u53D1\u751F\u53D8\u66F4\uFF1A
|
|
90
|
-
${e.uris.map(o=>{const s=e.fileChanges?.find(l=>l.uri===o);if(!s)return`- ${o}`;const
|
|
91
|
+
${e.uris.map(o=>{const s=e.fileChanges?.find(l=>l.uri===o);if(!s)return`- ${o}`;const r={no_change:"\u65E0\u53D8\u66F4",content_changed:"\u5185\u5BB9\u53D8\u66F4",not_found:"\u6587\u4EF6\u627E\u4E0D\u5230"},i=s.fileStatuses&&s.fileStatuses.length>0?s.fileStatuses:[],a=i.length>0?i.map(l=>{if(l.status==="no_change")return` \xB7 ${l.path}`;const u=r[l.status]??l.status,c=l.status==="content_changed"&&l.localMd5&&l.serverMd5?` \u672C\u5730: ${l.localMd5} Server: ${l.serverMd5}`:l.status==="not_found"&&l.serverMd5?` Server: ${l.serverMd5}`:"";return` \xB7 ${l.path}\uFF08${u}${c}\uFF09`}).join(`
|
|
91
92
|
`):s.boundFiles&&s.boundFiles.length>0?s.boundFiles.map(l=>` \xB7 ${l}`).join(`
|
|
92
93
|
`):" \u65E0\uFF08\u8BF7\u901A\u8FC7 read_memory \u67E5\u770B bound_files\uFF09";return`- ${o}
|
|
93
94
|
- \u7ED1\u5B9A\u6587\u4EF6:
|
|
94
|
-
${
|
|
95
|
+
${a}`}).join(`
|
|
95
96
|
`)}
|
|
96
97
|
|
|
97
98
|
\u8BF7\u6267\u884C\u4EE5\u4E0B\u6B65\u9AA4\uFF08\u6838\u5FC3\u903B\u8F91\uFF1A\u66F4\u65B0 \u2192 \u9A8C\u8BC1 \u2192 \u672A\u5B8C\u6210\u5219\u7EE7\u7EED\uFF09\uFF1A
|
|
@@ -109,5 +110,5 @@ ${r}`}).join(`
|
|
|
109
110
|
- \u2705 \u82E5\u5168\u90E8 memory_status \u4E3A "normal"\uFF1A\u9759\u9ED8\u7ED3\u675F
|
|
110
111
|
|
|
111
112
|
\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
|
|
112
|
-
\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=B(e)}catch{return e}let s;try{s=JSON.parse(o)}catch{return e}const i=s.directMessages;if(!Array.isArray(i)||i.length===0)return e;const a=[];let r=0;for(const c of i){const u=c._acodeAutoDelegate;if(u&&(u.type==="memory_expiration"||u.type==="memory_file_change"||u.type==="memory_cleanup")){r++;const m=Date.now(),h=u.uris.filter(T=>this.pendingMemorySubAgents.has(T)).length,A=u.uris.filter(T=>{const y=this.memoryDelegateCooldownUntil.get(T);return y!==void 0&&m<y}).length,f=u.uris.filter(T=>{if(this.pendingMemorySubAgents.has(T))return!1;const y=this.memoryDelegateCooldownUntil.get(T);return!(y!==void 0&&m<y)});if(f.length===0){d(`[ACodeRuntime] Memory ${u.type} skipped: ${h} in-progress, ${A} in cooldown (total ${u.uris.length} URIs)`);continue}const p=Array.isArray(u.fileChanges)?u.fileChanges.filter(T=>f.includes(T.uri)):void 0,k=this.buildMemoryDelegatePrompt({type:u.type,uris:f,fileChanges:p});try{const T=Pt("explore",[],xe(await this.buildAllocatableToolList())).patterns,y=await t.spawn({parentAgentId:this.config.agentId||"unknown",parentSessionId:this.config.sessionId,subagentType:Nt,description:`Memory ${u.type} auto-delegate (${f.length} items)`,prompt:k,...T.length>0?{allowedTools:T}:{},workingDirectory:this.config.workingDirectory,parentConfig:{...this.config,sharedMcpConnections:this.state?.mcpConnections},silent:!0});for(const S of f)this.pendingMemorySubAgents.set(S,y);const _=new Set(f);t.subscribe(y,()=>{const S=t.getSubAgent(y);if(S&&(S.status==="completed"||S.status==="failed"||S.status==="cancelled")){const C=Date.now();for(const b of _)this.pendingMemorySubAgents.get(b)===y&&this.pendingMemorySubAgents.delete(b),this.memoryDelegateCooldownUntil.set(b,C+ze);for(const[b,M]of this.memoryDelegateCooldownUntil)M<=C&&this.memoryDelegateCooldownUntil.delete(b);d(`[ACodeRuntime] Memory delegate sub-agent ${y} finished (${S.status}), ${_.size} URI(s) entered ${ze}ms cooldown`)}});const R=u.type,x=async(S,C)=>this.recheckMemoryDelegate(R,f,S,C);await t.startWithRecheck(y,x,3),d(`[ACodeRuntime] Auto-delegated memory ${u.type} to sub-agent ${y} (${f.length} URIs, ${u.uris.length-f.length} already in progress)`)}catch(T){for(const y of f)this.pendingMemorySubAgents.delete(y);d(`[ACodeRuntime] Failed to auto-delegate memory ${u.type} (suppressed, will retry next poll): ${T instanceof Error?T.message:String(T)}`)}}else a.push(c)}if(r===0)return e;if(a.length===0)return null;const l={...s,directMessages:a};return{content:[{type:"text",text:JSON.stringify(l,null,2)}]}}async callPollMessageWithSubAgentRace(e,t,o,s){const i=this.config.subAgentManager;if(!i)return P("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 a=i.takeCompletedSubAgents();if(a.length>0)return d(`[ACodeRuntime] poll_message: ${a.length} sub-agent(s) already completed, returning synthetic result`),P("runtime.poll.subagent-synthetic",`${a.length} \u4E2A\u5B50 agent \u5DF2\u5B8C\u6210\uFF0C\u76F4\u63A5\u8FD4\u56DE\u5408\u6210\u7ED3\u679C\uFF08\u4E0D\u8C03 MCP\uFF09`),K.formatSubAgentCompletionAsPollResult(a);let r=!1,l=0;for(;;){l++,P("runtime.poll.round-start",`\u7B2C ${l} \u8F6E race \u5F00\u59CB: timeoutMs=${s} silent=${r}`);const c=new AbortController,u=i.waitForAnyCompletion(),m=r?{...o,_aws_silent_poll:!0}:o,h=Date.now(),A=this.callMcpToolWithTimeout(e,t,m,s,!0,c.signal);try{const f=await Promise.race([A.then(T=>({type:"mcp",result:T})),u.promise.then(T=>({type:"subagent",notif:T}))]);if(f.type==="subagent"){P("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(),A.catch(()=>{});const T=i.takeCompletedSubAgents();return T.length===0&&T.push(f.notif),d(`[ACodeRuntime] poll_message: sub-agent ${f.notif.subId} completed during race, returning synthetic result (${T.length} notification(s))`),K.formatSubAgentCompletionAsPollResult(T)}P("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 p=i.takeCompletedSubAgents();if(p.length>0){d(`[ACodeRuntime] poll_message: MCP returned, merging ${p.length} sub-agent completion(s)`);const T=K.mergeSubAgentCompletionsIntoMcpResult(f.result,p),y=await this.processMemoryAutoDelegates(T);if(P("runtime.poll.delegate-check",`\u5408\u5E76 ${p.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 P("runtime.poll.final-return",`\u7B2C ${l} \u8F6E\uFF1A\u8FD4\u56DE\uFF08MCP+\u5B50agent\u5408\u5E76\u7ED3\u679C\uFF09`),y;P("runtime.poll.empty-repoll",`\u7B2C ${l} \u8F6E\uFF1A\u5408\u5E76\u7ED3\u679C\u4E3A\u7A7A\uFF0C\u7B49\u5F85 ${re}ms \u540E\u91CD\u65B0 poll`)}await this.waitForDelegateRepoll(),r=!0;continue}const k=await this.processMemoryAutoDelegates(f.result);if(P("runtime.poll.delegate-check",`\u59D4\u6258\u68C0\u67E5: processed=${k===null?"\u5168\u90E8\u88AB\u59D4\u6258(null)":"\u6709\u53EF\u4EA4\u4ED8"}`),k!==null){if(this.pollResultHasMessages(k)){const T=this.summarizePollResultForDebug(k);return P("runtime.poll.final-return",`\u7B2C ${l} \u8F6E\uFF1A\u8FD4\u56DE poll \u7ED3\u679C\u7ED9 LLM: ${T}`),k}P("runtime.poll.empty-repoll",`\u7B2C ${l} \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(),r=!0}catch(f){throw P("runtime.poll.error",`\u7B2C ${l} \u8F6E MCP \u8C03\u7528\u5F02\u5E38: ${f instanceof Error?f.message:String(f)}`),f}finally{u.cancel()}}}summarizePollResultForDebug(e){try{const t=B(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages:[],i=Array.isArray(o.groupMessages)?o.groupMessages:[];return`dm=${s.length}${s.length>0?JSON.stringify(s.map(a=>({id:a.msgId,ch:a.channel}))):""} gm=${i.length}`}catch{return"(\u65E0\u6CD5\u89E3\u6790\u4E3A JSON)"}}pollResultHasMessages(e){try{const t=B(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages.length:0,i=Array.isArray(o.groupMessages)?o.groupMessages.length:0;return s>0||i>0}catch{return!0}}async waitForDelegateRepoll(){d(`[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,i)=>{t=()=>{i(new Error(`${e} interrupted because ACode runtime stopped`))}});return t?(this.stopWaiters.add(t),{promise:o,cancel:()=>{t&&this.stopWaiters.delete(t)}}):{promise:o,cancel:()=>{}}}notifyRuntimeStop(){const e=[...this.stopWaiters];this.stopWaiters.clear();for(const t of e)t()}async appendSyntheticMultimodalUserMessage(e,t,o=this.contextVersion){const s=Ce(e);{const a=e.slice(0,200);let r="unknown";try{const l=JSON.parse(e);l&&typeof l=="object"&&!Array.isArray(l)?r=`keys=[${Object.keys(l).join(",")}]`:Array.isArray(l)?r="array":r=typeof l}catch{r="non-json"}le({stage:"entry",toolCallId:t.slice(0,12),contentLen:e.length,topLevelShape:r,prefix:a})}if(!s.hasImages){let a=null;try{const r=JSON.parse(e);if(r&&typeof r=="object"&&!Array.isArray(r)){const l=[r.directMessages,r.groupMessages];a=[];for(const c of l)if(Array.isArray(c))for(const u of c){if(!u||typeof u!="object")continue;const m=u,h=typeof m.content=="string"?m.content:"",A={senderName:typeof m.senderName=="string"?m.senderName:"",msgId:typeof m.msgId=="string"?m.msgId:"",contentLen:h.length};let f=null;try{const p=JSON.parse(h);p&&typeof p=="object"&&!Array.isArray(p)&&(f=p)}catch{}f?(A.contentKind="json",A.hasAttachmentsField=Array.isArray(f.attachments),A.attachmentCount=Array.isArray(f.attachments)?f.attachments.length:0,A.attachmentKinds=Array.isArray(f.attachments)?f.attachments.map(p=>String(p.type??p.kind??"").toLowerCase()||"(empty)"):[],A.attachmentBase64Lens=Array.isArray(f.attachments)?f.attachments.map(p=>(typeof p.base64Data=="string"?p.base64Data:typeof p.base64=="string"?p.base64:typeof p.data=="string"?p.data:"").length):[]):(A.contentKind="non-json",A.contentPrefix=h.slice(0,60)),a.push(A)}}}catch{}le({stage:"hasImages_false",toolCallId:t.slice(0,12),contentLen:e.length,parsedContentKind:Array.isArray(s.content)?"parts":typeof s.content,partsCount:Array.isArray(s.content)?s.content.length:null,dmProbe:a});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."}),le({stage:"supportsImageInput_false",toolCallId:t.slice(0,12),providerSupportsImageInput:this.state.provider.supportsImageInput,partsCount:Array.isArray(s.content)?s.content.length:null}),this.cleanToolMessageAttachments(t,"[Tool result contained images; skipped because the current model does not support image input]");return}let i;try{i=await He(s.content)}catch(a){const r=a instanceof Error?a.message:String(a),l=Array.isArray(s.content)?s.content.filter(c=>c.type==="image_url").map(c=>{const u=c.image_url.url,m=u.indexOf(",");return{urlHead:u.slice(0,Math.min(30,u.length)),base64Len:m>=0?u.length-m-1:null,isDataUrl:/^data:image\//i.test(u)}}):null;le({stage:"materialize_threw",toolCallId:t.slice(0,12),errMessage:r,imagePartsCount:l?l.length:0,imageParts:l}),this.emitAcodeEvent("error",{message:`ACode skipped image content from tool result: ${r}`}),i=Array.isArray(s.content)?s.content.map(c=>c.type==="text"?c:{type:"text",text:`[Image omitted: ${r}]`}):s.content}this.isTurnSuperseded(o)||(this.state.conversation.push({role:"user",content:i}),this.cleanToolMessageAttachments(t,"[Tool result contained images; see user message above]"))}expandCommandsInPolledResult(e){const t=this.state.commandRegistry;if(!t||t.list().length===0)return e;let o;try{o=JSON.parse(e)}catch{return e}if(!$(o))return e;let s=!1;for(const i of["directMessages","groupMessages"]){const a=o[i];if(Array.isArray(a))for(const r of a){if(!$(r))continue;const l=I(r.content);if(!l)continue;const c=t.expand(l);c&&(r.content=c.prompt,s=!0)}}return s?JSON.stringify(o):e}cleanToolMessageAttachments(e,t){const o=this.state.conversation.find(i=>i.role==="tool"&&i.tool_call_id===e);if(!o||typeof o.content!="string")return;let s;try{const i=JSON.parse(o.content);if(typeof i=="object"&&i!==null){const a={...i};"attachments"in a&&delete a.attachments,fo(a),s=JSON.stringify(a)}}catch{}if(s===void 0){const i=o.content.replace(/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,"").trim();i!==o.content&&(s=i)}s!==void 0&&(o.content=s.length>0?s:t)}appendToolFailureResult(e,t,o){const s=Oo(t,o);d(`[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}: ${ue(o)}`,nonFatal:!0}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:t.kind==="mcp"?t.serverName:"builtin",tool:t.toolName,toolUseId:e.id,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?Ee(s,t):Ot.has(s.toolName))}))}async connectMcpServers(e,t){const o=[];for(const[s,i]of Object.entries(e))try{const a=new nt({name:"acode",version:"0.1.0"}),r=this.createMcpTransport(i);await E(a.connect(r),t,`ACode MCP server ${s} connect`);const l={serverName:s,client:a,transport:r,tools:[]};a.setNotificationHandler(lt,()=>{this.refreshMcpConnectionTools(l,t)});const{tools:c}=await E(a.listTools(),t,`ACode MCP server ${s} listTools`);l.tools=Oe(s,c),o.push(l)}catch(a){this.emitAcodeEvent("error",{message:`ACode MCP server failed to connect: ${s}: ${a instanceof Error?a.message:String(a)}`})}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 recoverHiddenMcpTool(e){if(this.recoveredToolNames.has(e)||this.recoveredToolNames.size>=Ht)return!1;this.recoveredToolNames.add(e);const t=this.state.mcpConnections.filter(o=>o.tools.some(s=>s.toolName==="expand_tools"||s.exposedName==="expand_tools"||s.exposedName.endsWith("__expand_tools")));if(t.length===0)return!1;for(const o of t)await this.refreshMcpConnectionTools(o,this.state.provider.mcpToolTimeoutMs);return this.state.exposedTools.some(o=>o.toolName===e||o.exposedName===e)}async refreshMcpConnectionTools(e,t){try{const{tools:s}=await E(e.client.listTools(),t,`ACode MCP server ${e.serverName} listTools refresh`);e.tools=Oe(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 rt({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 it(new URL(e.url),{requestInit:t}):new at(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"),i=this.extractProfileFromToolResult(s);return qo(i)}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(!$(e))return null;const t=e.content;if(Array.isArray(t)){for(const o of t)if($(o)&&typeof o.text=="string"&&o.text.trim())try{const s=JSON.parse(o.text);if($(s))return s}catch{}}return $(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=>X(`ACode MCP server ${t.serverName} close`,t.transport.close(),o=>{this.emitAcodeEvent("error",{message:o})},this.state.provider.mcpToolTimeoutMs)))}}K.SKILL_REFRESH_DEBOUNCE_MS=500;export{K as ACodeRuntime};
|
|
113
|
+
\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=G(e)}catch{return e}let s;try{s=JSON.parse(o)}catch{return e}const r=s.directMessages;if(!Array.isArray(r)||r.length===0)return e;const i=[];let a=0;for(const u of r){const c=u._acodeAutoDelegate;if(c&&(c.type==="memory_expiration"||c.type==="memory_file_change"||c.type==="memory_cleanup")){a++;const m=Date.now(),h=c.uris.filter(g=>this.pendingMemorySubAgents.has(g)).length,y=c.uris.filter(g=>{const T=this.memoryDelegateCooldownUntil.get(g);return T!==void 0&&m<T}).length,C=c.uris.filter(g=>{if(this.pendingMemorySubAgents.has(g))return!1;const T=this.memoryDelegateCooldownUntil.get(g);return!(T!==void 0&&m<T)});if(C.length===0){p(`[ACodeRuntime] Memory ${c.type} skipped: ${h} in-progress, ${y} in cooldown (total ${c.uris.length} URIs)`);continue}const d=Array.isArray(c.fileChanges)?c.fileChanges.filter(g=>C.includes(g.uri)):void 0,f=this.buildMemoryDelegatePrompt({type:c.type,uris:C,fileChanges:d});try{const g=eo("explore",[],Ue(await this.buildAllocatableToolList())).patterns,T=await t.spawn({parentAgentId:this.config.agentId||"unknown",parentSessionId:this.config.sessionId,subagentType:Zt,description:`Memory ${c.type} auto-delegate (${C.length} items)`,prompt:f,...g.length>0?{allowedTools:g}:{},workingDirectory:this.config.workingDirectory,parentConfig:{...this.config,sharedMcpConnections:this.state?.mcpConnections},silent:!0});for(const k of C)this.pendingMemorySubAgents.set(k,T);const A=new Set(C);t.subscribe(T,()=>{const k=t.getSubAgent(T);if(k&&(k.status==="completed"||k.status==="failed"||k.status==="cancelled")){const M=Date.now();for(const I of A)this.pendingMemorySubAgents.get(I)===T&&this.pendingMemorySubAgents.delete(I),this.memoryDelegateCooldownUntil.set(I,M+Ve);for(const[I,x]of this.memoryDelegateCooldownUntil)x<=M&&this.memoryDelegateCooldownUntil.delete(I);p(`[ACodeRuntime] Memory delegate sub-agent ${T} finished (${k.status}), ${A.size} URI(s) entered ${Ve}ms cooldown`)}});const w=c.type,v=async(k,M)=>this.recheckMemoryDelegate(w,C,k,M);await t.startWithRecheck(T,v,3),p(`[ACodeRuntime] Auto-delegated memory ${c.type} to sub-agent ${T} (${C.length} URIs, ${c.uris.length-C.length} already in progress)`)}catch(g){for(const T of C)this.pendingMemorySubAgents.delete(T);p(`[ACodeRuntime] Failed to auto-delegate memory ${c.type} (suppressed, will retry next poll): ${g instanceof Error?g.message:String(g)}`)}}else i.push(u)}if(a===0)return e;if(i.length===0)return null;const l={...s,directMessages:i};return{content:[{type:"text",text:JSON.stringify(l,null,2)}]}}async callPollMessageWithSubAgentRace(e,t,o,s,r={}){const i=this.config.subAgentManager;if(!i)return U("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 a=r.allowRepoll!==!1,l=i.takeCompletedSubAgents();if(l.length>0)return p(`[ACodeRuntime] poll_message: ${l.length} sub-agent(s) already completed, returning synthetic result`),U("runtime.poll.subagent-synthetic",`${l.length} \u4E2A\u5B50 agent \u5DF2\u5B8C\u6210\uFF0C\u76F4\u63A5\u8FD4\u56DE\u5408\u6210\u7ED3\u679C\uFF08\u4E0D\u8C03 MCP\uFF09`),X.formatSubAgentCompletionAsPollResult(l);let u=!1,c=0;for(;;){c++,U("runtime.poll.round-start",`\u7B2C ${c} \u8F6E race \u5F00\u59CB: timeoutMs=${s} silent=${u}`);const m=new AbortController,h=i.waitForAnyCompletion(),y=u?{...o,_aws_silent_poll:!0}:o,C=Date.now(),d=this.callMcpToolWithTimeout(e,t,y,s,!0,m.signal);try{const f=await Promise.race([d.then(A=>({type:"mcp",result:A})),h.promise.then(A=>({type:"subagent",notif:A}))]);if(f.type==="subagent"){U("runtime.poll.race-winner-subagent",`\u5B50 agent \u5148\u5B8C\u6210\uFF0Cabort MCP \u8C03\u7528\uFF08\u5DF2\u7B49\u5F85 ${Date.now()-C}ms\uFF09\u540E\u8FD4\u56DE\u5408\u6210\u7ED3\u679C`),m.abort(),d.catch(()=>{});const A=i.takeCompletedSubAgents();return A.length===0&&A.push(f.notif),p(`[ACodeRuntime] poll_message: sub-agent ${f.notif.subId} completed during race, returning synthetic result (${A.length} notification(s))`),X.formatSubAgentCompletionAsPollResult(A)}U("runtime.poll.mcp-returned",`MCP \u5148\u8FD4\u56DE\uFF08\u8017\u65F6 ${Date.now()-C}ms\uFF09\uFF0C\u68C0\u67E5\u5F85\u5408\u5E76\u7684\u5B50 agent \u5B8C\u6210`);const g=i.takeCompletedSubAgents();if(g.length>0){p(`[ACodeRuntime] poll_message: MCP returned, merging ${g.length} sub-agent completion(s)`);const A=X.mergeSubAgentCompletionsIntoMcpResult(f.result,g),w=await this.processMemoryAutoDelegates(A);if(U("runtime.poll.delegate-check",`\u5408\u5E76 ${g.length} \u4E2A\u5B50 agent \u5B8C\u6210\u540E\u59D4\u6258\u68C0\u67E5: processed=${w===null?"\u5168\u90E8\u88AB\u59D4\u6258(null)":"\u6709\u53EF\u4EA4\u4ED8"}`),w!==null){if(this.pollResultHasMessages(w))return U("runtime.poll.final-return",`\u7B2C ${c} \u8F6E\uFF1A\u8FD4\u56DE\uFF08MCP+\u5B50agent\u5408\u5E76\u7ED3\u679C\uFF09`),w;U("runtime.poll.empty-repoll",`\u7B2C ${c} \u8F6E\uFF1A\u5408\u5E76\u7ED3\u679C\u4E3A\u7A7A\uFF0C\u7B49\u5F85 ${ge}ms \u540E\u91CD\u65B0 poll`)}if(!a)return w;await this.waitForDelegateRepoll(),u=!0;continue}const T=await this.processMemoryAutoDelegates(f.result);if(U("runtime.poll.delegate-check",`\u59D4\u6258\u68C0\u67E5: processed=${T===null?"\u5168\u90E8\u88AB\u59D4\u6258(null)":"\u6709\u53EF\u4EA4\u4ED8"}`),T!==null){if(this.pollResultHasMessages(T)){const A=this.summarizePollResultForDebug(T);return U("runtime.poll.final-return",`\u7B2C ${c} \u8F6E\uFF1A\u8FD4\u56DE poll \u7ED3\u679C\u7ED9 LLM: ${A}`),T}U("runtime.poll.empty-repoll",`\u7B2C ${c} \u8F6E\uFF1Apoll \u7ED3\u679C\u65E0\u5B9E\u9645\u6D88\u606F\uFF08directMessages/groupMessages \u5747\u7A7A\uFF09\uFF0C\u7B49\u5F85 ${ge}ms \u540E\u91CD\u65B0 poll`)}if(!a)return U("runtime.poll.delegate-return-no-repoll","\u975E\u9876\u5C42\u8F6E\u8BE2\u5165\u53E3\uFF1A\u59D4\u6258\u5DF2\u5B8C\u6210\uFF0C\u8FD4\u56DE\u539F\u59CB poll \u7ED3\u679C\uFF08\u4E0D\u91CD\u65B0 poll\uFF09"),f.result;await this.waitForDelegateRepoll(),u=!0}catch(f){throw U("runtime.poll.error",`\u7B2C ${c} \u8F6E MCP \u8C03\u7528\u5F02\u5E38: ${f instanceof Error?f.message:String(f)}`),f}finally{h.cancel()}}}summarizePollResultForDebug(e){try{const t=G(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages:[],r=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=${r.length}`}catch{return"(\u65E0\u6CD5\u89E3\u6790\u4E3A JSON)"}}pollResultHasMessages(e){try{const t=G(e),o=JSON.parse(t),s=Array.isArray(o.directMessages)?o.directMessages.length:0,r=Array.isArray(o.groupMessages)?o.groupMessages.length:0;return s>0||r>0}catch{return!0}}async waitForDelegateRepoll(){p(`[ACodeRuntime] poll_message: all messages delegated, waiting ${ge}ms before re-poll`);const e=this.createRuntimeStopWaiter("delegate re-poll delay");try{await Promise.race([new Promise(t=>{const o=setTimeout(t,ge);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,r)=>{t=()=>{r(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=Ee(e);{const i=e.slice(0,200);let a="unknown";try{const l=JSON.parse(e);l&&typeof l=="object"&&!Array.isArray(l)?a=`keys=[${Object.keys(l).join(",")}]`:Array.isArray(l)?a="array":a=typeof l}catch{a="non-json"}ye({stage:"entry",toolCallId:t.slice(0,12),contentLen:e.length,topLevelShape:a,prefix:i})}if(!s.hasImages){let i=null;try{const a=JSON.parse(e);if(a&&typeof a=="object"&&!Array.isArray(a)){const l=[a.directMessages,a.groupMessages];i=[];for(const u of l)if(Array.isArray(u))for(const c of u){if(!c||typeof c!="object")continue;const m=c,h=typeof m.content=="string"?m.content:"",y={senderName:typeof m.senderName=="string"?m.senderName:"",msgId:typeof m.msgId=="string"?m.msgId:"",contentLen:h.length};let C=null;try{const d=JSON.parse(h);d&&typeof d=="object"&&!Array.isArray(d)&&(C=d)}catch{}C?(y.contentKind="json",y.hasAttachmentsField=Array.isArray(C.attachments),y.attachmentCount=Array.isArray(C.attachments)?C.attachments.length:0,y.attachmentKinds=Array.isArray(C.attachments)?C.attachments.map(d=>String(d.type??d.kind??"").toLowerCase()||"(empty)"):[],y.attachmentBase64Lens=Array.isArray(C.attachments)?C.attachments.map(d=>(typeof d.base64Data=="string"?d.base64Data:typeof d.base64=="string"?d.base64:typeof d.data=="string"?d.data:"").length):[]):(y.contentKind="non-json",y.contentPrefix=h.slice(0,60)),i.push(y)}}}catch{}return ye({stage:"hasImages_false",toolCallId:t.slice(0,12),contentLen:e.length,parsedContentKind:Array.isArray(s.content)?"parts":typeof s.content,partsCount:Array.isArray(s.content)?s.content.length:null,dmProbe:i}),null}if(!this.state.provider.supportsImageInput)return this.emitAcodeEvent("error",{message:"ACode skipped image content from tool result because the provider/model is not configured for image input."}),ye({stage:"supportsImageInput_false",toolCallId:t.slice(0,12),providerSupportsImageInput:this.state.provider.supportsImageInput,partsCount:Array.isArray(s.content)?s.content.length:null}),this.cleanToolMessageAttachments(t,"[Tool result contained images; skipped because the current model does not support image input]"),null;let r;try{r=await it(s.content)}catch(i){const a=i instanceof Error?i.message:String(i),l=Array.isArray(s.content)?s.content.filter(u=>u.type==="image_url").map(u=>{const c=u.image_url.url,m=c.indexOf(",");return{urlHead:c.slice(0,Math.min(30,c.length)),base64Len:m>=0?c.length-m-1:null,isDataUrl:/^data:image\//i.test(c)}}):null;ye({stage:"materialize_threw",toolCallId:t.slice(0,12),errMessage:a,imagePartsCount:l?l.length:0,imageParts:l}),this.emitAcodeEvent("error",{message:`ACode skipped image content from tool result: ${a}`}),r=Array.isArray(s.content)?s.content.map(u=>u.type==="text"?u:{type:"text",text:`[Image omitted: ${a}]`}):s.content}return this.isTurnSuperseded(o)?null:(this.cleanToolMessageAttachments(t,"[Tool result contained images; see user message above]"),{role:"user",content:r})}expandCommandsInPolledResult(e){const t=this.state.commandRegistry;if(!t||t.list().length===0)return e;let o;try{o=JSON.parse(e)}catch{return e}if(!S(o))return e;let s=!1;for(const r of["directMessages","groupMessages"]){const i=o[r];if(Array.isArray(i))for(const a of i){if(!S(a))continue;const l=O(a.content);if(!l)continue;const u=t.expand(l);u&&(a.content=u.prompt,s=!0)}}return s?JSON.stringify(o):e}cleanToolMessageAttachments(e,t){const o=this.state.conversation.find(r=>r.role==="tool"&&r.tool_call_id===e);if(!o||typeof o.content!="string")return;let s;try{const r=JSON.parse(o.content);if(typeof r=="object"&&r!==null){const i={...r};"attachments"in i&&delete i.attachments,Fo(i),s=JSON.stringify(i)}}catch{}if(s===void 0){const r=o.content.replace(/\[(图片|文件)\s*:\s*([^\]\n]*?)\s*\]/gi,"").trim();r!==o.content&&(s=r)}s!==void 0&&(o.content=s.length>0?s:t)}appendToolFailureResult(e,t,o,s){const r=ut(t,o),i=wt(o),a=i?ut(t,o,i):r;p(`[ACodeRuntime] \u{1F4E4} appendToolFailureResult: emitting mcp_status tool_result (failed: true) for ${t.exposedName}, result length: ${r.length} chars`+(i?`, conversation snapshot: ${i.bytes} bytes`:"")),this.emitAcodeEvent("error",{message:`ACode tool failed: ${t.exposedName}: ${ue(o)}`,nonFatal:!0}),this.emitAcodeEvent("mcp_status",{action:"tool_result",server:t.kind==="mcp"?t.serverName:"builtin",tool:t.toolName,toolUseId:e.id,result:r,failed:!0,...s?{batchId:s}:{}}),this.state.conversation.push({role:"tool",tool_call_id:e.id,content:a})}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?qe(s,t):to.has(s.toolName))}))}async connectMcpServers(e,t){const o=[];for(const[s,r]of Object.entries(e))try{const i=new Tt({name:"acode",version:"0.1.0"}),a=this.createMcpTransport(r);await R(i.connect(a),t,`ACode MCP server ${s} connect`);const l={serverName:s,client:i,transport:a,tools:[]};i.setNotificationHandler(At,()=>{this.refreshMcpConnectionTools(l,t)});const{tools:u}=await R(i.listTools(),t,`ACode MCP server ${s} listTools`);l.tools=We(s,u);try{l.instructions=i.getInstructions()}catch{}l.spec=r,o.push(l)}catch(i){this.emitAcodeEvent("error",{message:`ACode MCP server failed to connect: ${s}: ${i instanceof Error?i.message:String(i)}`})}return o}registerMcpCollapsedGroup(e,t,o){if(!this.toolGroupManager||t.collapsed!==!0||o.tools.length===0)return;const s=Ut(e),r=this.toolGroupManager.getRegistration(s),i=t.description?.trim()||po(o.instructions)||`MCP \u5DE5\u5177\u96C6\uFF1A${e}`,a=this.toolGroupManager.claimedToolNamesBySubGroups(),l=o.tools.map(u=>u.toolName).filter(u=>!a.has(u));l.length!==0&&(this.toolGroupManager.register({key:s,label:t.description?.trim()||e,summary:i,collapsible:!0,toolNames:l,serverName:e}),this.emitAcodeEvent("mcp_status",{serverName:e,status:"collapsed_group_registered",toolCount:l.length,updated:!!r}))}registerToolGroupsFromMcp(e){if(!this.toolGroupManager)return!1;const t=mo(e.instructions);if(t.length===0)return!1;let o=0;for(const s of t)this.toolGroupManager.getRegistration(s.key)||(this.toolGroupManager.register({key:s.key,label:s.label,summary:"",collapsible:!0,toolNames:s.toolNames}),o+=1);return this.emitAcodeEvent("mcp_status",{serverName:e.serverName,status:"tool_groups_registered",declared:t.length,registered:o}),!0}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 recoverHiddenMcpTool(e){if(this.recoveredToolNames.has(e)||this.recoveredToolNames.size>=To)return!1;this.recoveredToolNames.add(e);const t=this.state.mcpConnections.filter(o=>o.tools.some(s=>s.toolName==="expand_tools"||s.exposedName==="expand_tools"||s.exposedName.endsWith("__expand_tools")));if(t.length===0)return!1;for(const o of t)await this.refreshMcpConnectionTools(o,this.state.provider.mcpToolTimeoutMs);return this.state.exposedTools.some(o=>o.toolName===e||o.exposedName===e)}async refreshMcpConnectionTools(e,t){try{const{tools:s}=await R(e.client.listTools(),t,`ACode MCP server ${e.serverName} listTools refresh`);e.tools=We(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 Ct({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 yt(new URL(e.url),{requestInit:t}):new _t(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 R(t.client.callTool({name:"get_profile",arguments:{}},void 0,{timeout:fe}),fe,"ACode startup get_profile"),r=this.extractProfileFromToolResult(s);return us(r)}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(!S(e))return null;const t=e.content;if(Array.isArray(t)){for(const o of t)if(S(o)&&typeof o.text=="string"&&o.text.trim())try{const s=JSON.parse(o.text);if(S(s))return s}catch{}}return S(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=>ae(`ACode MCP server ${t.serverName} close`,t.transport.close(),o=>{this.emitAcodeEvent("error",{message:o})},this.state.provider.mcpToolTimeoutMs)))}}X.SKILL_REFRESH_DEBOUNCE_MS=500;export{X as ACodeRuntime,he as TOOL_GROUP_MANIFEST_PREFIX,bo as hasExplicitRequestBodyByteCap,po as humanReadableInstructions,mo as parseToolGroupManifest,wo as resolveMaxRequestBodyBytes,ut as toToolErrorResultText};
|
|
113
114
|
|