aws-runtime-bridge 1.9.131 → 1.9.135

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +15 -0
  2. package/dist/adapter/AcodeSdkAdapter.js +5 -5
  3. package/dist/adapter/types.d.ts +9 -0
  4. package/dist/browser/built-in-browser-tools.js +1 -1
  5. package/dist/routes/system-metrics.js +1 -1
  6. package/dist/routes/terminal.js +19 -19
  7. package/dist/services/instance-features.d.ts +5 -0
  8. package/dist/services/instance-features.js +1 -1
  9. package/dist/services/process-detail.d.ts +77 -0
  10. package/dist/services/process-detail.js +32 -0
  11. package/dist/services/process-top.d.ts +53 -0
  12. package/dist/services/process-top.js +50 -0
  13. package/dist/services/session-output.d.ts +10 -0
  14. package/dist/services/session-output.js +3 -3
  15. package/package/acode/dist/built-in-file-tools.d.ts +25 -1
  16. package/package/acode/dist/built-in-file-tools.js +2 -2
  17. package/package/acode/dist/image-utils.d.ts +52 -0
  18. package/package/acode/dist/image-utils.js +2 -0
  19. package/package/acode/dist/index.d.ts +1 -0
  20. package/package/acode/dist/index.js +1 -1
  21. package/package/acode/dist/runtime.d.ts +15 -1
  22. package/package/acode/dist/runtime.js +26 -26
  23. package/package/acode/dist/types.d.ts +3 -1
  24. package/package/aws-client-agent-mcp/dist/http-client.d.ts +4 -0
  25. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  26. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +8 -0
  27. package/package/aws-client-agent-mcp/dist/mcp-server.js +28 -25
  28. package/package/aws-client-agent-mcp/dist/mcp-tools.js +6 -6
  29. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +6 -0
  30. package/package/aws-client-agent-mcp/dist/memory-tools.js +2 -2
  31. package/package/aws-client-agent-mcp/dist/types.d.ts +4 -0
  32. package/package/aws-client-agent-mcp/package.json +1 -1
  33. package/package.json +1 -1
  34. package/package/aws-client-agent-mcp/dist/agent-client.test.d.ts +0 -1
  35. package/package/aws-client-agent-mcp/dist/agent-client.test.js +0 -1066
  36. package/package/aws-client-agent-mcp/dist/config.test.d.ts +0 -1
  37. package/package/aws-client-agent-mcp/dist/config.test.js +0 -259
  38. package/package/aws-client-agent-mcp/dist/context-manager.test.d.ts +0 -2
  39. package/package/aws-client-agent-mcp/dist/context-manager.test.js +0 -312
  40. package/package/aws-client-agent-mcp/dist/http-client.test.d.ts +0 -1
  41. package/package/aws-client-agent-mcp/dist/http-client.test.js +0 -808
  42. package/package/aws-client-agent-mcp/dist/launch-config-tools.test.d.ts +0 -1
  43. package/package/aws-client-agent-mcp/dist/launch-config-tools.test.js +0 -110
  44. package/package/aws-client-agent-mcp/dist/logger.test.d.ts +0 -1
  45. package/package/aws-client-agent-mcp/dist/logger.test.js +0 -27
  46. package/package/aws-client-agent-mcp/dist/mcp-server.test.d.ts +0 -1
  47. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +0 -2798
  48. package/package/aws-client-agent-mcp/dist/mcp-tools.test.d.ts +0 -1
  49. package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +0 -152
  50. package/package/aws-client-agent-mcp/dist/memory-store.test.d.ts +0 -1
  51. package/package/aws-client-agent-mcp/dist/memory-store.test.js +0 -664
  52. package/package/aws-client-agent-mcp/dist/message-buffer.test.d.ts +0 -1
  53. package/package/aws-client-agent-mcp/dist/message-buffer.test.js +0 -142
  54. package/package/aws-client-agent-mcp/dist/parent-lifecycle.test.d.ts +0 -1
  55. package/package/aws-client-agent-mcp/dist/parent-lifecycle.test.js +0 -81
  56. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.d.ts +0 -1
  57. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +0 -201
  58. package/package/aws-client-agent-mcp/dist/status-reporter.test.d.ts +0 -1
  59. package/package/aws-client-agent-mcp/dist/status-reporter.test.js +0 -157
  60. package/package/aws-client-agent-mcp/dist/watchdog.test.d.ts +0 -1
  61. package/package/aws-client-agent-mcp/dist/watchdog.test.js +0 -124
  62. package/package/aws-client-agent-mcp/dist/websocket-client.test.d.ts +0 -1
  63. package/package/aws-client-agent-mcp/dist/websocket-client.test.js +0 -725
@@ -27,6 +27,10 @@ type ACodeRuntimeInstance = {
27
27
  removeBuiltInToolsByPrefix?(prefix: string): number;
28
28
 
29
29
  requestMcpToolsRefresh?(serverName?: string): void;
30
+
31
+ setToolPermissionPolicy?(policy: unknown): void;
32
+
33
+ submitToolPermissionDecision?(requestId: string, allowed: boolean): boolean;
30
34
  };
31
35
  type ACodeRuntimeConstructor = new (config: {
32
36
  sessionId: string;
@@ -44,6 +48,8 @@ type ACodeRuntimeConstructor = new (config: {
44
48
  subAgentManager?: SubAgentManager;
45
49
 
46
50
  terminalManager?: TerminalManager;
51
+
52
+ toolPermissionPolicy?: unknown;
47
53
  onFileChange?: (record: {
48
54
  filePath: string;
49
55
  operation: 'CREATE' | 'UPDATE' | 'DELETE';
@@ -71,6 +77,15 @@ export declare class AcodeSdkAdapter extends EventEmitter implements BaseProvide
71
77
  sendMessage(sessionId: string, message: string): Promise<void>;
72
78
  sendConfirmation(_sessionId: string, _accept: boolean): Promise<void>;
73
79
 
80
+ submitToolPermissionDecision(sessionId: string, requestId: string, allowed: boolean): boolean;
81
+
82
+ getPendingToolAuthRequests(sessionId: string): Array<{
83
+ requestId: string;
84
+ capability: string;
85
+ detail: Record<string, unknown>;
86
+ requestedAt: number;
87
+ }>;
88
+
74
89
  sendQuestionAnswer(sessionId: string, answers: Record<string, string>): Promise<void>;
75
90
  abortCurrentTurn(sessionId: string): Promise<void>;
76
91
  resetContext(sessionId: string): Promise<void>;
@@ -1,11 +1,11 @@
1
- import{EventEmitter as z}from"node:events";import I from"node:path";import Y from"node:fs/promises";import{pathToFileURL as X}from"node:url";import{v4 as U}from"uuid";import{getAcodeConfigFile as $,getAcodeSkillsDir as V}from"../config.js";import{getReleasedAcodeEntryPath as Z}from"../services/acode-package.js";import{getInstanceAiConfigDebugLogger as x}from"../utils/instance-ai-config-debug-logger.js";import{redactForLog as R}from"../services/instance-ai-config-service.js";import{subAgentManager as tt}from"../services/sub-agent-manager-instance.js";import{agentPtyManager as et}from"../services/agent-pty-manager.js";import{resolveAcodeProviderConfig as ot}from"./instance-ai-config-resolver.js";import{recordAgentFileChange as st}from"../services/workspaceTaskChangeWatcher.js";import{getBrowserTools as v,closeBrowserSession as it,registerListenerWakeHook as at,unregisterListenerWakeHook as F}from"../services/browser-session-manager.js";import{getDesktopTools as O,getDesktopToolsIfReady as nt}from"../services/desktop-mcp-manager.js";import{BROWSER_FEATURE_KEY as B,DESKTOP_FEATURE_KEY as E,isFeatureEnabled as P}from"../services/instance-features.js";import{isMessagePollingIdleCommand as L,isPollMessageToolDescriptor as rt}from"./acode-tool-names.js";import{IdlePollLoop as ut}from"./idle-poll-loop.js";import{getCanonicalMcpDetail as W,getToolActionInfo as lt}from"./types.js";const dt=process.env.ACODE_COMPACTION_DEBUG==="1";function l(...u){dt&&console.log(...u)}const ct=process.env.ACODE_TOKEN_DEBUG==="1";function w(...u){ct&&console.log("[TokenDebug][Adapter]",...u)}const q=["Continue the AgentsWork message loop now.","You MUST call the exact MCP tool named aws-mcp__poll_message as your next action and wait for the next assigned message or task.","Do not answer in plain text before calling aws-mcp__poll_message.","After handling any received work, reply through the appropriate aws-mcp messaging tool, then continue listening again."].join(" "),mt=5e3;function D(u,t){const e=process.env[u];if(e===void 0||e.trim()==="")return t;const o=Number(e.trim());return Number.isFinite(o)&&o>=0?Math.floor(o):t}const N=D("ACODE_DATA_FLOW_WATCHDOG_MS",12e4),pt=5*6e4,gt=D("ACODE_STUCK_AUTOPOLL_TIMEOUT_MS",5*6e4),ft=250,ht=2e3,H=D("ACODE_SUBMIT_TIMEOUT_MS",12e4),K=3e3,Tt="\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u6CA1\u6709\u5176\u5B83\u8981\u505A\u7684\uFF0C\u5148\u8C03\u7528 poll_message \u5DE5\u5177\u963B\u585E\u7B49\u5F85\u65B0\u6D88\u606F\u548C\u6D41\u7A0B\u7EBF\u4EFB\u52A1\u63D0\u9192\uFF1B\u6536\u5230\u6D41\u7A0B\u4EFB\u52A1\u63D0\u9192\u540E\u8C03\u7528 my_task \u67E5\u770B\u5DF2\u7531\u540E\u53F0\u9759\u9ED8\u62A2\u5360\u7684\u4EFB\u52A1\u8BE6\u60C5\u5E76\u76F4\u63A5\u5904\u7406\uFF1B\u5B8C\u6210\u4EFB\u52A1\u540E\u8C03\u7528 submit_task_result \u63D0\u4EA4\u7ED3\u679C\uFF0C\u7136\u540E\u7EE7\u7EED poll_message\u3002 \u8C03\u7528 submit_task_result \u65F6\u8BF7\u4E00\u5E76\u4F20\u5165 changeLog\uFF08\u672C\u6B21\u5904\u7406\u7684\u6587\u4EF6/\u5185\u5BB9\u53D8\u66F4\u65E5\u5FD7\uFF0C\u5305\u542B operation \u4E0E path\uFF09\uFF0C\u7528\u4E8E AI \u56DE\u9000\u3002";function _t(){return I.resolve(Z())}function At(u){return X(I.resolve(u)).href}const j=128e3,y={"claude-4":{contextLimit:2e5,maxOutput:8192},"claude-sonnet-4":{contextLimit:2e5,maxOutput:8192},"claude-3-5-sonnet":{contextLimit:2e5,maxOutput:8192},"claude-3-opus":{contextLimit:2e5,maxOutput:8192},"claude-3-haiku":{contextLimit:2e5,maxOutput:8192},"claude-2":{contextLimit:1e5,maxOutput:4096},"gpt-4o":{contextLimit:128e3,maxOutput:16384},"gpt-4-turbo":{contextLimit:128e3,maxOutput:4096},"gpt-4":{contextLimit:8192,maxOutput:4096},"gpt-3.5-turbo":{contextLimit:16384,maxOutput:4096},o1:{contextLimit:2e5,maxOutput:1e5},"o3-mini":{contextLimit:2e5,maxOutput:1e5},"gemini-2.0-flash":{contextLimit:1048576,maxOutput:8192},"gemini-2.5-pro":{contextLimit:1048576,maxOutput:8192},"gemini-1.5-pro":{contextLimit:2097152,maxOutput:8192},"gemini-1.5-flash":{contextLimit:1048576,maxOutput:8192},deepseek:{contextLimit:64e3,maxOutput:8192},"deepseek-chat":{contextLimit:64e3,maxOutput:8192},"deepseek-reasoner":{contextLimit:64e3,maxOutput:8192},"qwen-max":{contextLimit:32e3,maxOutput:8192},"qwen-plus":{contextLimit:128e3,maxOutput:8192},"qwen-turbo":{contextLimit:1e6,maxOutput:8192},"glm-4":{contextLimit:128e3,maxOutput:4096},"yi-":{contextLimit:2e5,maxOutput:4096},"llama-3":{contextLimit:8192,maxOutput:4096},"llama-2":{contextLimit:4096,maxOutput:4096},mistral:{contextLimit:32e3,maxOutput:4096},mixtral:{contextLimit:32e3,maxOutput:4096},codestral:{contextLimit:256e3,maxOutput:8192},grok:{contextLimit:131072,maxOutput:4096},"nova-":{contextLimit:2e5,maxOutput:8192}};function St(u){if(!u)return j;const t=u.toLowerCase().trim();if(y[t])return y[t].contextLimit;const e=Object.keys(y).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?y[e[0]].contextLimit:j}const Q=4096;function kt(u){if(!u)return Q;const t=u.toLowerCase().trim();if(y[t])return y[t].maxOutput;const e=Object.keys(y).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?y[e[0]].maxOutput:Q}function bt(u){if(!u||typeof u!="object")return;const t=u,e=h(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),o=h(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(e===0&&o===0)return;let s=h(t.cacheHitTokens,t.promptCacheHitTokens,t.prompt_cache_hit_tokens),n=h(t.cacheMissTokens,t.promptCacheMissTokens,t.prompt_cache_miss_tokens),i=t.cacheHitTokens!==void 0||t.cacheMissTokens!==void 0||t.promptCacheHitTokens!==void 0||t.promptCacheMissTokens!==void 0||t.prompt_cache_hit_tokens!==void 0||t.prompt_cache_miss_tokens!==void 0;if(s===0&&n===0){const a=h(t.cache_read_input_tokens),r=h(t.cache_creation_input_tokens);a>0||r>0?(s=a,n=r+h(t.input_tokens),i=!0):(s=h(t.cache_hit_tokens),n=h(t.cache_miss_tokens),i=i||t.cache_hit_tokens!==void 0||t.cache_miss_tokens!==void 0)}if(s===0&&n===0){const a=h(t.prompt_tokens_details?.cached_tokens);a>0&&(s=a,n=e>a?e-a:0,i=!0)}return{inputTokens:e,outputTokens:o,...s>0||n>0?{cacheHitTokens:s,cacheMissTokens:n}:{},...i?{hasCache:!0}:{}}}function h(...u){for(const t of u){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function G(u){return h(u.estimatedContextTokens,u.contextTokens,u.context_tokens,u.contextUsedTokens,u.context_used_tokens)}function Ct(u){return u==="stderr"||u==="mixed"?u:"stdout"}function yt(u){if(!u||typeof u!="object"||Array.isArray(u))return;const t={};for(const[e,o]of Object.entries(u))typeof o=="string"&&(t[e]=o);return Object.keys(t).length>0?t:void 0}function wt(u){return u.failed===!0}function J(u,t,e){if(!u)return e?`${t}/${e}`:t;const o=`${t}__`;return u.startsWith(o)?W(`${t}__${u.slice(o.length)}`):W(u.replace("/","__"))}function Pt(u){return u==="read_file"||u==="edit_file"||u==="write_file"||u==="bash"}function Lt(u){const t=$t(u);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof u=="string"&&u.trim().length>0}function $t(u){if(u&&typeof u=="object"&&!Array.isArray(u))return u;if(!(typeof u!="string"||!u.trim()))try{const t=JSON.parse(u);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class Jt extends z{constructor(){super(...arguments),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const o=e.mcpConfigPath||$(),{resolved:s,configContextLimit:n,supportsImage:i}=await this.resolveAcodeProvider(e,o),a=s.model,r=n??St(a),c=kt(a),p={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:r,maxOutput:c,cacheHitTokens:0,cacheMissTokens:0}};this.sessions.set(t,{adapterSession:p,config:e,runtime:await this.createRuntime(t,a,e,s,i),autoPollActive:!1}),this.emit("status-change",t,"starting");const m=this.sessions.get(t);if(!m)throw new Error("ACode session was not initialized");const d=()=>{const g=this.sessions.get(t);g&&this.getIdlePollLoop(g).start()};this.listenerWakeHooks.set(t,d),at(e.agentId,d);try{await m.runtime.start(),p.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:m.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(g){p.status="error",this.emitRuntimeErrorEvent(t,g),this.emit("status-change",t,"error");const f=this.sessions.get(t);throw f?.capabilitiesFallbackTimer&&clearTimeout(f.capabilitiesFallbackTimer),this.sessions.delete(t),F(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),g}}async sendMessage(t,e){const o=Date.now();l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l("[ACode] \u25B6\uFE0F sendMessage STARTED"),l(`[ACode] Session: ${t}`),l(`[ACode] Message: ${e.slice(0,100)}${e.length>100?"...":""}`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");const s=this.requireSession(t),n=s.adapterSession.status;l(`[ACode] Previous status: ${n}`),this.cancelScheduledAutoPoll(s),s.failedTurnRecoveryScheduled=!1,s.idlePollLoop?.stop();const i={id:U(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};s.adapterSession.messages.push(i),this.emit("conversation-message",t,i),l(`[ACode] Changing status: ${n} \u2192 thinking`),s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,s,"sendMessage");try{l("[ACode] \u25B6\uFE0F Calling runtime.submit()...");const a=Date.now();await s.runtime.submit(e);const r=Date.now()-a;this.cancelSubmitTimeoutDetection(s),l(`[ACode] \u2705 runtime.submit() completed in ${r}ms`),l(`[ACode] Current status after submit: ${s.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Calling recoverResolvedTurnWithoutTerminalEvent()..."),this.recoverResolvedTurnWithoutTerminalEvent(t),l(`[ACode] Status after recovery: ${s.adapterSession.status}`);const c=Date.now()-o;l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l(`[ACode] \u2705 sendMessage COMPLETED in ${c}ms`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}catch(a){const r=Date.now()-o;console.error(`[ACode] \u274C sendMessage FAILED after ${r}ms:`,a instanceof Error?a.message:String(a)),this.cancelSubmitTimeoutDetection(s),l("[ACode] \u25B6\uFE0F Calling emitRuntimeError with recover=true..."),this.emitRuntimeError(t,a,{recover:!0}),l(`[ACode] Status after error recovery: ${s.adapterSession.status}`)}}async sendConfirmation(t,e){}async sendQuestionAnswer(t,e){const o=this.sessions.get(t);if(!o)return;const s=o.pendingQuestionToolCallId;if(!s){l(`[AcodeSdkAdapter] sendQuestionAnswer: no pending question for session ${t}`);return}o.pendingQuestionToolCallId=void 0,o.pendingQuestions=void 0,o.runtime.submitQuestionAnswer&&o.runtime.submitQuestionAnswer(s,e),this.startSubmitTimeoutDetection(t,o,"sendQuestionAnswer")}async abortCurrentTurn(t){await this.requireSession(t).runtime.abort()}async resetContext(t){const e=this.requireSession(t);if(this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.autoPollActive=!1,e.autoPollObservedPollingTool=!1,e.autoPollObservedAssistantText=!1,e.autoPollObservedAnyTool=!1,e.stopAutoPollAfterCurrentTurn=!1,e.idlePollLoop?.stop(),!e.runtime.resetContext)throw new Error("ACode runtime does not support context reset");await e.runtime.resetContext(),e.adapterSession.messages=[];const o=e.adapterSession.totalUsage;if(e.adapterSession.totalUsage={inputTokens:0,outputTokens:0,contextLimit:o.contextLimit,maxOutput:o.maxOutput,inputLimit:o.inputLimit,compactionThreshold:o.compactionThreshold,cacheHitTokens:o.cacheHitTokens,cacheMissTokens:o.cacheMissTokens},e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),e.config.initialPrompt?.trim()){this.startInitialPromptTurn(t,e.config.initialPrompt);return}this.armIdleLoopOrAutoPoll(t)}async terminateSession(t){const e=this.sessions.get(t);if(!e)return;this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),await e.runtime.stop();const o=e.config.agentId;o&&(F(o,this.listenerWakeHooks.get(t)),it(o)),this.listenerWakeHooks.delete(t),e.adapterSession.status="terminated",this.sessions.delete(t),this.emit("status-change",t,"terminated")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.has(t)?t:void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}notifyForceMessage(t){const e=this.sessions.get(t);return e?.runtime?.notifyForceMessage?(e.runtime.notifyForceMessage(),!0):!1}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}async resolveAgentAiInfo(t){try{const e=[...this.sessions.values()].find(i=>i.config.agentId===t);if(!e)return;const o=e.config.mcpConfigPath||$(),{resolved:s,supportsImage:n}=await this.resolveAcodeProvider(e.config,o);return s?.model?{model:s.model,supportsImage:n===!0,...s.baseURL?{baseURL:s.baseURL}:{},...s.apiKey?{apiKey:s.apiKey}:{}}:void 0}catch{return}}async applyAgentFeatures(t){if(!t)return;const e=P(t,E),o=P(t,B);for(const[s,n]of this.sessions){if(n.config.agentId!==t)continue;const i=n.runtime;try{if(e){const a=await O(t,await this.resolveAgentAiInfo(t)),r=i.addBuiltInTools?.(a)??0;r>0&&l(`[acode-adapter] session ${s}: ${r} desktop tools hot-added for agent ${t}`)}else{const a=i.removeBuiltInToolsByPrefix?.("desktop_")??0;a>0&&l(`[acode-adapter] session ${s}: ${a} desktop tools hot-removed for agent ${t}`)}}catch(a){l(`[acode-adapter] session ${s}: desktop feature hot-sync failed for agent ${t}:`,a.message)}if(o)try{const a=await v(t,n.config.scopeKey,typeof n.config.browserAllowPrivate=="boolean"?{allowPrivate:n.config.browserAllowPrivate}:void 0),r=i.addBuiltInTools?.(a)??0;r>0&&l(`[acode-adapter] session ${s}: ${r} browser tools hot-added for agent ${t}`)}catch(a){l(`[acode-adapter] session ${s}: browser feature hot-sync failed for agent ${t}:`,a.message)}}this.syncMcpToolsForAgent(t)}syncMcpToolsForAgent(t){if(t){for(const[e,o]of this.sessions)if(o.config.agentId===t)try{o.runtime.requestMcpToolsRefresh?.()}catch(s){l(`[acode-adapter] session ${e}: mcp tools refresh failed for agent ${t}:`,s.message)}}}getPendingQuestion(t){const e=this.sessions.get(t);if(e?.pendingQuestionToolCallId)return{toolCallId:e.pendingQuestionToolCallId,questions:e.pendingQuestions??[]}}cleanup(){for(const t of this.sessions.keys())this.terminateSession(t)}setIdleCommands(t,e){const o=this.sessions.get(t);if(o){if(o.idleCommands=e,this.cancelScheduledAutoPoll(o),e.idleInputCommand&&L(e.idleInputCommand)){this.getIdlePollLoop(o).start();return}o.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.getIdlePollLoop(o).start()}}setRuntimeConstructorForTest(t){this.runtimeConstructor=t}async loadAcodeProviderSection(t){try{const e=await Y.readFile(t,"utf-8"),o=JSON.parse(e),n=o.provider?.default,i=n?.options,a=h(o.contextLimit),r={},c={},p=n?.models;if(p&&typeof p=="object"){for(const[m,d]of Object.entries(p))if(d&&typeof d=="object"){const g=h(d.contextLimit);g>0&&(r[m.trim()]=g);const f=d.modalities?.input,A=Array.isArray(f)&&f.includes("image")||d.supportsImageInput===!0;c[m.trim()]=A===!0}}return{...n?.model?{model:n.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...a>0?{contextLimit:a}:{},...Object.keys(r).length>0?{modelContextLimits:r}:{},...Object.keys(c).length>0?{modelImageSupport:c}:{}}}catch(e){const o=e instanceof Error?e.message:String(e);return x().log({level:"warn",category:"load",message:`loadAcodeProviderSection failed: ${t}: ${o}`,source:"bridge"}),{}}}async resolveAcodeProvider(t,e){const o=typeof t.model=="string"&&t.model.trim()?t.model.trim():void 0,s=x();s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?R(t.instanceAiConfig):null,configPath:e}});const n={...t.instanceAiConfig?.model?{model:t.instanceAiConfig.model}:{},...t.instanceAiConfig?.baseURL?{baseURL:t.instanceAiConfig.baseURL}:{},...t.instanceAiConfig?.apiKey?{apiKey:t.instanceAiConfig.apiKey}:{},...t.instanceAiConfig?.effort?{effort:t.instanceAiConfig.effort}:{},...o?{model:o}:{}},i=await this.loadAcodeProviderSection(e);let a=i.contextLimit;if(!a&&i.modelContextLimits){const c=o||t.instanceAiConfig?.model||i.model;c&&i.modelContextLimits[c]&&(a=i.modelContextLimits[c])}const r=ot(n,i,"acode-default");return s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:R(n),globalConfigModel:i?.model??null,resolvedModel:r.model,resolvedBaseURL:r.baseURL??null,resolvedApiKey:r.apiKey?"[set]":null,configContextLimit:a,resolvedSource:r.source}}),{resolved:r,configPath:e,perSessionModel:o,configContextLimit:a,supportsImage:i.modelImageSupport?.[r.model]===!0}}async createRuntime(t,e,o,s,n){const i=await this.loadRuntimeConstructor(),a=o.mcpConfigPath||$();let r=[];try{r=await v(o.agentId,o.scopeKey,typeof o.browserAllowPrivate=="boolean"?{allowPrivate:o.browserAllowPrivate}:void 0)}catch(d){l(`[acode-adapter] browser tools injection skipped for agent ${o.agentId}:`,d.message)}let c=[];if(P(o.agentId??"",B)&&(c=r),o.agentId&&P(o.agentId,E))try{const d=s?.model?{model:s.model,supportsImage:n===!0,...s.baseURL?{baseURL:s.baseURL}:{},...s.apiKey?{apiKey:s.apiKey}:{}}:void 0,g=await O(o.agentId,d);g.length>0&&(c=[...c,...g])}catch(d){l(`[acode-adapter] desktop tools injection skipped for agent ${o.agentId}:`,d.message)}const p=new i({sessionId:t,agentId:o.agentId,workingDirectory:o.workingDirectory,configPath:a,skillsDir:V(),model:e,systemPrompt:typeof o.systemPrompt=="string"?o.systemPrompt:void 0,globalPrompt:typeof o.globalPrompt=="string"?o.globalPrompt:void 0,rolePrompt:typeof o.rolePrompt=="string"?o.rolePrompt:void 0,memory:typeof o.memory=="string"?o.memory:void 0,env:o.envOverrides,subAgentManager:tt,terminalManager:et,...o.subAgentModel?{subAgentModel:o.subAgentModel}:{},...o.subAgentEffort?{subAgentEffort:o.subAgentEffort}:{},...o.instanceAiConfig?.effort?{effort:o.instanceAiConfig.effort}:{},onFileChange:d=>st({...d,agentId:o.agentId,workspacePath:o.workingDirectory}),extraBuiltInTools:c,subAgentSuiteTools:r,subAgentSuiteToolProvider:this.buildSubAgentSuiteToolProvider(o.agentId)});return x().log({level:"info",category:"resolve",message:"ACode provider resolved",source:"bridge",sessionId:t,details:{resolvedModel:e,perInstanceModel:o.instanceAiConfig?.model||null,perInstanceBaseURL:o.instanceAiConfig?.baseURL?"[set]":null,perInstanceApiKey:o.instanceAiConfig?.apiKey?"[set]":null,configPath:a}}),p.on("event",d=>this.forwardAcodeEvent(d)),p}buildSubAgentSuiteToolProvider(t){return async e=>{if(!t)return[];if(!P(t,E))return[];if(e.length===0)return nt();if(!e.some(n=>{const i=n.trim().replace(/[.*]+$/,"");return i==="desktop"||i.startsWith("desktop.")}))return[];const s=await this.resolveAgentAiInfo(t);return O(t,s)}}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=_t(),e=await import(At(t));if(!e.ACodeRuntime)throw new Error(`ACode runtime export not found: ${t}`);return this.runtimeConstructor=e.ACodeRuntime,this.runtimeConstructor}requireSession(t){const e=this.sessions.get(t);if(!e)throw new Error("ACode session not found");return e}startInitialPromptTurn(t,e){const o=this.sessions.get(t);o&&(o.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,o,"startInitialPromptTurn"),o.runtime.submit(e).then(()=>{this.cancelSubmitTimeoutDetection(o),this.recoverResolvedTurnWithoutTerminalEvent(t)}).catch(s=>{const n=this.sessions.get(t);n&&(this.cancelSubmitTimeoutDetection(n),this.emitRuntimeError(t,s,{recover:!0}))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(e.autoPollActive&&(e.autoPollLastActivityAt=Date.now()),t.type==="assistant_delta"){const o=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:U(),sessionId:t.sessionId,role:"assistant",content:o,timestamp:t.timestamp}),this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"text_delta",{text:o});return}if(t.type==="thinking_delta"){const o=typeof t.data.text=="string"?t.data.text:"";this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"thinking",{text:o});return}if(t.type==="command_output"){this.emitProviderEvent(t,"command_output",{text:typeof t.data.text=="string"?t.data.text:"",stream:Ct(t.data.stream),sequence:typeof t.data.sequence=="number"?t.data.sequence:void 0,cwd:typeof t.data.cwd=="string"?t.data.cwd:void 0,commandLineCount:typeof t.data.commandLineCount=="number"?t.data.commandLineCount:void 0,commandFilePath:typeof t.data.commandFilePath=="string"?t.data.commandFilePath:void 0});return}if(t.type==="background_command_completed"){this.emitProviderEvent(t,"background_command_completed",t.data);return}if(t.type==="ai_request"){const o=G(t.data),s=t.data.lastUsage,n=h(s?.inputTokens),i=h(s?.outputTokens),a=h(s?.cacheHitTokens),r=h(s?.cacheMissTokens),c=!!(s&&(n>0||i>0));let p;if(c&&(n>0&&(e.adapterSession.totalUsage.inputTokens=n),i>0&&(e.adapterSession.totalUsage.outputTokens=i),(s?.cacheHitTokens!==void 0||s?.cacheMissTokens!==void 0)&&(e.adapterSession.totalUsage.cacheHitTokens=a,e.adapterSession.totalUsage.cacheMissTokens=r),p={...e.adapterSession.totalUsage},w(`ai_request lastUsage applied: ${JSON.stringify(s)} -> totalUsage=${JSON.stringify(e.adapterSession.totalUsage)}`)),!c&&o>0){const g=e.adapterSession.totalUsage.inputTokens;g>0?e.adapterSession.totalUsage.inputTokens=Math.min(o,Math.floor(g*1.5)):e.adapterSession.totalUsage.inputTokens=o,p={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const d={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};p&&(d.usage=p),w(`ai_request handled: estimatedContextTokens=${t.data.estimatedContextTokens??"n/a"} totalUsage=${JSON.stringify(e.adapterSession.totalUsage)} displayUsage=${JSON.stringify(p??null)}`),this.emit("status-change",t.sessionId,e.adapterSession.status,d),this.startDataFlowWatchdog(t.sessionId,e),e.adapterSession.status==="thinking"&&e.watchdogSubmitStartTime&&(e.watchdogSubmitStartTime=Date.now()),this.emitProviderEvent(t,"ai_request",{model:typeof t.data.model=="string"?t.data.model:void 0,endpoint:typeof t.data.endpoint=="string"?t.data.endpoint:void 0,requestMethod:typeof t.data.requestMethod=="string"?t.data.requestMethod:void 0,requestUrl:typeof t.data.requestUrl=="string"?t.data.requestUrl:void 0,requestHeaders:yt(t.data.requestHeaders),stream:typeof t.data.stream=="boolean"?t.data.stream:void 0,messageCount:typeof t.data.messageCount=="number"?t.data.messageCount:void 0,toolCount:typeof t.data.toolCount=="number"?t.data.toolCount:void 0,lastUserMessagePreview:typeof t.data.lastUserMessagePreview=="string"?t.data.lastUserMessagePreview:void 0,requestBody:typeof t.data.requestBody=="string"?t.data.requestBody:void 0});return}if(t.type==="turn_complete"){const o=bt(t.data.usage);if(o){const n=e.adapterSession.totalUsage.inputTokens,i=n>0&&o.inputTokens<Math.floor(n*.2)&&!o.hasCache;w(`turn_complete usage: raw=${JSON.stringify(t.data.usage)} parsed=${JSON.stringify(o)} currentInput=${n} threshold20pct=${Math.floor(n*.2)} isFallbackUsage=${i}`),i?o.outputTokens>0&&(e.adapterSession.totalUsage.outputTokens=o.outputTokens):(e.adapterSession.totalUsage.inputTokens=o.inputTokens,e.adapterSession.totalUsage.outputTokens=o.outputTokens),(o.cacheHitTokens||o.cacheMissTokens)&&(e.adapterSession.totalUsage.cacheHitTokens=o.cacheHitTokens,e.adapterSession.totalUsage.cacheMissTokens=o.cacheMissTokens,l(`[ACode] \u{1F4B0} Cache usage (overwrite from runtime cumulative): hit=${e.adapterSession.totalUsage.cacheHitTokens}, miss=${e.adapterSession.totalUsage.cacheMissTokens} (turn delta: hit=${o.cacheHitTokens||0}, miss=${o.cacheMissTokens||0})`)),w(`totalUsage after turn_complete: ${JSON.stringify(e.adapterSession.totalUsage)}`)}else w(`turn_complete has NO parseable usage: raw=${JSON.stringify(t.data.usage)} failed=${t.data.failed===!0} aborted=${t.data.aborted===!0}`);const s=e.adapterSession.status;if(l(`[ACode] turn_complete event received (session: ${t.sessionId}), previous status: ${s}, failed: ${t.data.failed===!0}, aborted: ${t.data.aborted===!0}`),wt(t.data)){l(`[ACode] Recovering from failed turn_complete (session: ${t.sessionId})`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(t.data.aborted===!0&&e.autoPollActive){l(`[ACode] Recovering from aborted turn_complete (session: ${t.sessionId}), using R2 2s backoff instead of immediate rearm`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(this.cancelDataFlowWatchdog(e),this.emitProviderEvent(t,"turn_complete",{usage:e.adapterSession.totalUsage,responseBody:typeof t.data.responseBody=="string"?t.data.responseBody:void 0,finishReason:typeof t.data.finishReason=="string"?t.data.finishReason:void 0}),e.adapterSession.status="waiting_input",this.emit("status-change",t.sessionId,"waiting_input",{usage:e.adapterSession.totalUsage}),w(`status-change emitted (waiting_input after turn_complete): usage=${JSON.stringify(e.adapterSession.totalUsage)}`),l(`[ACode] Status changed to waiting_input after turn_complete (session: ${t.sessionId})`),e.autoPollActive&&e.autoPollObservedAssistantText&&!e.autoPollObservedPollingTool&&!e.autoPollObservedAnyTool){e.stopAutoPollAfterCurrentTurn=!0,console.warn(`[${this.displayName}] Auto-poll turn produced assistant text without calling any tool; stopping auto-poll rearm for session ${t.sessionId}`);return}this.armIdleLoopOrAutoPoll(t.sessionId);return}if(t.type==="session_complete"){this.cancelDataFlowWatchdog(e),this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.adapterSession.status="completed",this.emitProviderEvent(t,"session_complete",{exitCode:Number(t.data.exitCode)||0}),this.emit("status-change",t.sessionId,"completed");return}if(t.type==="question_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const o=typeof t.data.toolCallId=="string"?t.data.toolCallId:"",s=Array.isArray(t.data.questions)?t.data.questions:[];o&&(e.pendingQuestionToolCallId=o,e.pendingQuestions=s),this.emit("ask-user-question",{sessionId:t.sessionId,toolCallId:o||void 0,questions:s});return}if(t.type==="error"){if(t.data.nonFatal){this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")});return}this.cancelDataFlowWatchdog(e),e.adapterSession.status="error",this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")}),this.emit("status-change",t.sessionId,"error"),e.autoPollActive||this.recoverTurnFailure(t.sessionId,e);return}if(t.type==="mcp_status"){if(!t.data.action&&Array.isArray(t.data.tools)){const f=t.data.tools;f.some(T=>rt(T))||console.warn(`[${this.displayName}] ACode runtime is not exposing a poll_message tool. The LLM cannot call poll_message. Please configure an MCP server that provides poll_message (e.g. aws-mcp) in the dashboard panel for this runtime.`);const _=Array.isArray(t.data.servers)?t.data.servers:[],k=f.map(T=>({name:String(T.name??""),source:String(T.source??""),description:String(T.description??"")})).filter(T=>T.name),b={kind:"mcp",mcpServers:_,mcpTools:k};e.cachedMcpCapabilities=b,e.lastMcpCapabilities=b,e.lastCombinedCapabilities={kind:"combined",mcpServers:_,mcpTools:k,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},l(`[cap-diag] MCP capabilities cached: ${_.length} servers, ${k.length} tools`,{sessionId:t.sessionId,servers:_,toolNames:k.map(T=>T.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const T=e.cachedMcpCapabilities;if(!T)return;const C={...T,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:C,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(C)}),l(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${K}ms)`,{sessionId:t.sessionId,mcpServers:T.mcpServers,mcpToolsCount:T.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},K);return}const o=String(t.data.action??"");l(`[ACode] \u{1F4E1} mcp_status event: action=${o}, server=${typeof t.data.server=="string"?t.data.server:"?"}, tool=${typeof t.data.tool=="string"?t.data.tool:"?"}, toolUseId=${typeof t.data.toolUseId=="string"?t.data.toolUseId.slice(0,16)+"\u2026":"none"}, failed=${t.data.failed===!0}, session=${t.sessionId}, status=${e.adapterSession.status}`);const s=typeof t.data.server=="string"?t.data.server:"mcp",n=typeof t.data.tool=="string"?t.data.tool:"",i=s&&n?`${s}__${n}`:n||s,a=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,r=lt(i,a);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,r.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const c=Pt(r.actionType)?r.actionDetail||J(void 0,s,n):J(r.actionDetail,s,n),p=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,m=a?JSON.stringify(a,null,2):void 0,d={toolName:c,rawToolName:i,actionType:r.actionType,actionLabel:r.actionLabel,actionDetail:c,...m?{actionInput:m}:{},...a?{toolInput:a}:{},...p?{toolUseId:p,actionId:p}:{},metadata:{mcpServer:s}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...d,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const f=r.actionType==="idle"&&!Lt(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=f,r.actionType==="idle"&&(e.idleToolActiveAt=void 0),this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const A=r.actionType==="idle";this.emit("status-change",t.sessionId,f,A||f==="thinking"?void 0:d);return}const g=r.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=g,r.actionType==="idle"&&(e.idleToolActiveAt=Date.now()),g==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...d}),this.emitProviderEvent(t,"tool_use_start",d),this.emit("status-change",t.sessionId,g,d);return}if(t.type==="skill_status"){const s=(Array.isArray(t.data.skills)?t.data.skills:[]).map(m=>({name:String(m.name??""),description:typeof m.description=="string"?m.description:void 0,directory:typeof m.directory=="string"?m.directory:void 0})).filter(m=>m.name),n=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,a=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(m=>{const d=Array.isArray(m.skills)?m.skills:[];return{dir:typeof m.dir=="string"?m.dir:"",exists:m.exists===!0,skills:d.map(g=>({name:String(g.name??""),description:typeof g.description=="string"?g.description:void 0,directory:typeof g.directory=="string"?g.directory:void 0})).filter(g=>g.name)}}).filter(m=>m.dir),r=e.cachedMcpCapabilities??e.lastMcpCapabilities,c=e.cachedMcpCapabilities!==void 0,p={kind:"combined",mcpServers:r?.mcpServers??[],mcpTools:r?.mcpTools??[],skills:s,skillsDir:n,skillGroups:a};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:p,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(p)}),e.lastCombinedCapabilities=p,l(`[cap-diag] Combined capabilities emitted ${c?"(startup merge)":"(runtime refresh)"}: ${(r?.mcpTools??[]).length} MCP tools, ${s.length} skills`,{sessionId:t.sessionId,mcpServers:r?.mcpServers??[],skillsDir:n}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="startup_phase"){l(`[ACode] \u{1F680} startup_phase swallowed: ${String(t.data.phase??"unknown")}`,{sessionId:t.sessionId});return}if(t.type==="command_status"){if(t.data.action==="commands_loaded"){l(`[ACode] \u{1F4CB} command_status commands_loaded swallowed: ${typeof t.data.installedCommandCount=="number"?t.data.installedCommandCount:"?"} commands`,{sessionId:t.sessionId});return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)});return}if(t.type==="session_started"){const o=G(t.data),s=h(t.data.contextLimit)||void 0,n=h(t.data.maxOutput)||void 0,i=h(t.data.inputLimit)||void 0,a=h(t.data.compactionThreshold)||void 0;let r=!1;o>0&&(e.adapterSession.totalUsage.inputTokens=o,e.adapterSession.totalUsage.outputTokens=0,r=!0),s!==void 0&&(e.adapterSession.totalUsage.contextLimit=s,r=!0),n!==void 0&&(e.adapterSession.totalUsage.maxOutput=n,r=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,r=!0),a!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=a,r=!0),r&&this.emit("status-change",t.sessionId,e.adapterSession.status,{usage:e.adapterSession.totalUsage});return}if(t.type==="exit_plan_mode"){e.adapterSession.status="waiting_input";const o=typeof t.data.plan=="string"?t.data.plan:void 0;this.emitProviderEvent(t,"exit_plan_mode",{toolInput:t.data.toolInput&&typeof t.data.toolInput=="object"?t.data.toolInput:void 0,text:o||"\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"}),this.emit("status-change",t.sessionId,"waiting_input",{actionLabel:"\u5BA1\u6279\u8BA1\u5212",actionDetail:o||"\u7B49\u5F85\u7528\u6237\u5BA1\u6279\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"});return}if(t.type==="context_compaction"){const o=t.data,s=o.action,n=s==="start",i=s==="end",a=s==="phase",r=o.parentId,c=o.compactionId;let p,m;if(n){const g=String(o.sizeKB??o.sizeBeforeKB??"?"),f=String(o.messageCount??o.messageCountBefore??"?"),A=o.estimatedTokens,_=o.actualInputTokens?`input=${o.actualInputTokens}`:"",k=o.actualOutputTokens?`output=${o.actualOutputTokens}`:"",b=o.trigger?`, \u89E6\u53D1: ${o.trigger}`:"";p="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",A!==void 0?m=`\u538B\u7F29\u524D: ~${A} tokens, \u6D88\u606F: ${f}\u6761`+(_?`, \u5B9E\u9645 tokens: ${_} ${k}`:"")+b:m=`\u538B\u7F29\u524D: ${g}KB, \u6D88\u606F: ${f}\u6761`+(_?`, \u5B9E\u9645 tokens: ${_} ${k}`:"")+b}else if(a)p=String(o.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),m=String(o.phaseDetail??"");else{const g=o.tokensBefore,f=o.tokensAfter,A=o.freedTokens,_=String(o.sizeBeforeKB??"?"),k=String(o.sizeAfterKB??"?"),b=String(o.freedKB??"?"),T=String(o.strategy??"?"),C=Number(o.prunedToolMessages??0),S=Number(o.summarizedMessages??0);p="\u538B\u7F29\u5B8C\u6210",g!==void 0&&f!==void 0?m=`\u91CA\u653E: ${A??g-f} tokens, ${g} tokens \u2192 ${f} tokens, \u7B56\u7565: ${T}`+(C?`, \u88C1\u526A\u5DE5\u5177: ${C}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:""):m=`\u91CA\u653E: ${b}KB, ${_}KB \u2192 ${k}KB, \u7B56\u7565: ${T}`+(C?`, \u88C1\u526A\u5DE5\u5177: ${C}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:"")}n&&(e.adapterSession.status="compacting");const d={actionType:"context_compaction",actionLabel:p,actionDetail:m};if(n&&c)d.actionId=c;else if((a||i)&&c)if(d.parentId=c,a){const g=String(o.phase??"unknown");d.actionId=`${c}-phase-${g}`}else d.actionId=`${c}-end`;a&&r&&!d.parentId&&(d.parentId=r),i&&(e.adapterSession.totalUsage.inputTokens=h(o.tokensAfter),e.adapterSession.totalUsage.outputTokens=0,d.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",d),this.emit("status-change",t.sessionId,"compacting",d);return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)})}}emitProviderEvent(t,e,o){this.emit("event",{type:e,sessionId:t.sessionId,timestamp:t.timestamp,data:o})}armIdleLoopOrAutoPoll(t){const e=this.sessions.get(t);if(!(!e||this.isTerminalStatus(e.adapterSession.status))){if(e.idleCommands?.idleInputCommand){this.getIdlePollLoop(e).start();return}this.scheduleAutoPoll(t)}}getIdlePollLoop(t){if(t.idlePollLoop)return t.idlePollLoop;const e=t.adapterSession.sessionId;return t.idlePollLoop=new ut({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:o=>L(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,s)=>this.submitAutoPollPrompt(e,s?o:Tt,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.submitAutoPollPrompt(e,o)}),t.idlePollLoop}submitAutoPollPrompt(t,e,o){const s=this.sessions.get(t);if(!s||this.isTerminalStatus(s.adapterSession.status))return;const n=(s.autoPollToken??0)+1;s.autoPollToken=n,s.autoPollActive=!0,s.autoPollObservedPollingTool=!1,s.autoPollObservedAssistantText=!1,s.autoPollObservedAnyTool=!1,s.stopAutoPollAfterCurrentTurn=!1,s.autoPollQueuedAt=Date.now(),s.autoPollLastActivityAt=Date.now(),s.idleToolActiveAt=void 0,o?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking")),this.startSubmitTimeoutDetection(t,s,"submitAutoPollPrompt"),s.runtime.submit(e).catch(i=>{this.emitRuntimeError(t,i)}).finally(()=>{const i=this.sessions.get(t);if(i){if(i.autoPollToken!==n){l(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${n}, current=${i.autoPollToken}), skipping cleanup \u2014 newer turn has taken over`);return}if(this.cancelSubmitTimeoutDetection(i),i.autoPollActive=!1,i.failedTurnRecoveryScheduled||i.autoPollTimer){i.failedTurnRecoveryScheduled=!1;return}if(i.stopAutoPollAfterCurrentTurn){i.stopAutoPollAfterCurrentTurn=!1,i.autoPollObservedPollingTool=!1,i.autoPollObservedAssistantText=!1,i.autoPollObservedAnyTool=!1;return}if(i.adapterSession.status==="error"){this.recoverTurnFailure(t,i);return}if(i.adapterSession.status==="thinking"||i.adapterSession.status==="tool_using"){this.recoverResolvedTurnWithoutTerminalEvent(t);return}i.adapterSession.status==="waiting_input"&&this.armIdleLoopOrAutoPoll(t)}})}scheduleAutoPoll(t,e=ft){const o=this.sessions.get(t);!o||o.autoPollActive||o.autoPollTimer||this.isTerminalStatus(o.adapterSession.status)||(o.autoPollTimer=setTimeout(()=>{const s=this.sessions.get(t);!s||s.autoPollActive||this.isTerminalStatus(s.adapterSession.status)||(s.autoPollTimer=void 0,this.submitAutoPollPrompt(t,q,{keepWaitingStatus:!0}))},e))}cancelScheduledAutoPoll(t){t.autoPollTimer&&(clearTimeout(t.autoPollTimer),t.autoPollTimer=void 0)}isTerminalStatus(t){return t==="completed"||t==="terminated"}emitRuntimeError(t,e,o){const s=this.sessions.get(t);s&&(s.adapterSession.status="error",this.emitRuntimeErrorEvent(t,e),this.emit("status-change",t,"error"),o?.recover&&this.recoverTurnFailure(t,s))}emitRuntimeErrorEvent(t,e){const o=new Date().toISOString();this.emit("event",{type:"error",sessionId:t,timestamp:o,data:{text:e instanceof Error?e.message:String(e)}})}estimateOutputTokensFromMessages(t){const e=t.filter(o=>o.role==="assistant").map(o=>o.content).join("");return Math.max(0,Math.round(e.length/4))}recoverTurnFailure(t,e){if(this.isTerminalStatus(e.adapterSession.status))return;if(e.idleToolActiveAt=void 0,e.adapterSession.status==="tool_using"&&e.pendingToolEventData){const a=e.pendingToolEventData;l(`[ACode] recoverTurnFailure: \u8865\u53D1 tool_use_end (tool: ${a.toolName??"unknown"}) \u5173\u95ED\u65F6\u95F4\u7EBF\u6761\u76EE\uFF0C\u907F\u514D\u6C38\u4E45\u5361\u5728\u5DE5\u5177\u6267\u884C\u72B6\u6001`),this.emit("event",{type:"tool_use_end",sessionId:t,timestamp:new Date().toISOString(),data:{...a,toolResult:"[aborted] \u5DE5\u5177\u6267\u884C\u88AB\u6570\u636E\u6D41\u770B\u95E8\u72D7\u4E2D\u65AD"}}),e.pendingToolEventData=void 0}const o=this.estimateOutputTokensFromMessages(e.adapterSession.messages);if(o>0){const a=e.adapterSession.totalUsage.outputTokens;e.adapterSession.totalUsage.outputTokens=o,l(`[ACode] recoverTurnFailure: \u4F30\u7B97\u8986\u76D6 output tokens ${a} -> ${o} (totalUsage now: input=${e.adapterSession.totalUsage.inputTokens}, output=${e.adapterSession.totalUsage.outputTokens})`)}const s=e.idleCommands?.idleInputCommand,i=!!(s&&L(s))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;if(e.autoPollTimer||e.failedTurnRecoveryScheduled){e.adapterSession.status!=="waiting_input"&&(e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage,...i}));return}this.cancelScheduledAutoPoll(e),e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage,...i}),e.failedTurnRecoveryScheduled=!0,e.autoPollTimer=setTimeout(()=>{const a=this.sessions.get(t);if(!a||a.autoPollActive||this.isTerminalStatus(a.adapterSession.status)){a&&(a.failedTurnRecoveryScheduled=!1);return}a.autoPollTimer=void 0,a.failedTurnRecoveryScheduled=!1,a.idleCommands?.idleInputCommand?this.getIdlePollLoop(a).start():this.submitAutoPollPrompt(t,q,{keepWaitingStatus:!0})},ht)}recoverResolvedTurnWithoutTerminalEvent(t){l(`[ACode] \u25B6\uFE0F recoverResolvedTurnWithoutTerminalEvent called for session ${t}`);const e=this.sessions.get(t);if(!e||this.isTerminalStatus(e.adapterSession.status)){l(`[ACode] Skipping recovery: entry=${!!e}, isTerminal=${e?this.isTerminalStatus(e.adapterSession.status):"N/A"}`);return}if(l(`[ACode] Current status: ${e.adapterSession.status}`),e.adapterSession.status!=="thinking"&&e.adapterSession.status!=="tool_using"){l(`[ACode] Skipping recovery: status is ${e.adapterSession.status} (not thinking/tool_using)`);return}console.warn(`[ACode] \u26A0\uFE0F Detected stuck state: ${e.adapterSession.status} after submit resolved! Recovering to waiting_input. If runtime.submit() is still pending (e.g., built-in tool execution not interruptible by abort()), the submitQueue is deadlocked and subsequent auto-poll/user submits will never execute.`),l("[ACode] Recovering to waiting_input..."),e.adapterSession.status="waiting_input";const o=e.idleCommands?.idleInputCommand,n=!!(o&&L(o))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",n),l(`[ACode] \u2705 Recovery complete, status now: ${e.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Arming idle loop or auto-poll..."),this.armIdleLoopOrAutoPoll(t),l("[ACode] \u2705 Idle loop armed, recovery process complete")}startSubmitTimeoutDetection(t,e,o){this.cancelSubmitTimeoutDetection(e),e.watchdogSubmitStartTime=Date.now(),e.watchdogLastDataFlowTime=Date.now(),e.watchdogTimer=setInterval(()=>{const s=this.sessions.get(t);if(!s){this.cancelSubmitTimeoutDetection(e);return}const n=s.adapterSession.status,i=Date.now();if(n==="waiting_input"){if(s.autoPollActive&&s.autoPollLastActivityAt&&s.idleToolActiveAt===void 0&&i-s.autoPollLastActivityAt>=gt){console.warn(`[ACode] CRITICAL: stuck auto-poll detected after ${Math.round((i-s.autoPollLastActivityAt)/1e3)}s (source: ${o}, session: ${t}): submit queued but no runtime events and no active poll_message tool. Forcing recovery (runtime force-settle will unblock submitQueue).`),this.executeWatchdogRecovery(t,s,o,"stuck_autopoll",i-s.autoPollLastActivityAt);return}s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(n==="tool_using"){const c=i-(s.watchdogLastDataFlowTime||i);if(c>=pt){const p=String(s.pendingToolEventData?.rawToolName??"");if(p.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(c/1e3)}s but await_complete is running (session: ${t}, tool: ${p}), skipping recovery (sub-agents have their own watchdogs, bg commands have timeout limits)`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(console.warn(`[ACode] CRITICAL: tool_using slow timeout triggered after ${Math.round(c/1e3)}s (source: ${o}, session: ${t}). Tool execution likely hung. Forcing recovery via recoverTurnFailure.`),s.runtime.detachCurrentToolExecution?.()){console.warn(`[ACode] tool_using slow (${Math.round(c/1e3)}s): detached tool ${p} to background (session: ${t}); waiting for the real tool_result to continue the turn`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}this.executeWatchdogRecovery(t,s,o,"tool_using_slow",c);return}s.watchdogSubmitStartTime=i;return}if(n!=="thinking")return;const a=i-(s.watchdogSubmitStartTime||i),r=i-(s.watchdogLastDataFlowTime||i);if(N>0&&r>=N){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(r/1e3)}s (source: ${o}, session: ${t}, status: ${n}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"data_flow",r);return}if(H>0&&a>=H){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(a/1e3)}s (source: ${o}, session: ${t}, status: ${n}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,s,o,"submit_timeout",a);return}},mt)}executeWatchdogRecovery(t,e,o,s,n){l(`[ACode] Watchdog (${s}): calling runtime.abort() after ${Math.round(n/1e3)}s...`);try{e.runtime.abort(),l(`[ACode] Watchdog (${s}): runtime.abort() called`)}catch(i){console.warn(`[ACode] \u26A0\uFE0F Watchdog (${s}): runtime.abort() threw: ${i instanceof Error?i.message:String(i)}`)}this.cancelSubmitTimeoutDetection(e),this.recoverTurnFailure(t,e),console.warn(`[ACode] \u26A0\uFE0F Watchdog (${s}) recovery complete. If abort() could not cancel the underlying operation, submitQueue may still be deadlocked.`)}cancelSubmitTimeoutDetection(t){t.watchdogTimer&&(clearInterval(t.watchdogTimer),t.watchdogTimer=void 0),t.watchdogSubmitStartTime=void 0,t.watchdogLastDataFlowTime=void 0}resetDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now(),e.watchdogSubmitStartTime=Date.now()}startDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now()}cancelDataFlowWatchdog(t){t.watchdogLastDataFlowTime=Date.now()}formatAiRequestActionDetail(t){const e=`
1
+ import{EventEmitter as z}from"node:events";import I from"node:path";import Y from"node:fs/promises";import{pathToFileURL as X}from"node:url";import{v4 as U}from"uuid";import{getAcodeConfigFile as $,getAcodeSkillsDir as V}from"../config.js";import{getReleasedAcodeEntryPath as Z}from"../services/acode-package.js";import{getInstanceAiConfigDebugLogger as x}from"../utils/instance-ai-config-debug-logger.js";import{redactForLog as R}from"../services/instance-ai-config-service.js";import{subAgentManager as tt}from"../services/sub-agent-manager-instance.js";import{agentPtyManager as et}from"../services/agent-pty-manager.js";import{resolveAcodeProviderConfig as ot}from"./instance-ai-config-resolver.js";import{recordAgentFileChange as st}from"../services/workspaceTaskChangeWatcher.js";import{getBrowserTools as F,closeBrowserSession as it,registerListenerWakeHook as at,unregisterListenerWakeHook as v}from"../services/browser-session-manager.js";import{getDesktopTools as D,getDesktopToolsIfReady as nt}from"../services/desktop-mcp-manager.js";import{BROWSER_FEATURE_KEY as q,DESKTOP_FEATURE_KEY as O,getAgentToolPermissions as rt,isFeatureEnabled as P,resolveAgentToolPermissions as ut}from"../services/instance-features.js";import{isMessagePollingIdleCommand as L,isPollMessageToolDescriptor as lt}from"./acode-tool-names.js";import{IdlePollLoop as dt}from"./idle-poll-loop.js";import{getCanonicalMcpDetail as B,getToolActionInfo as ct}from"./types.js";const mt=process.env.ACODE_COMPACTION_DEBUG==="1";function l(...u){mt&&console.log(...u)}const pt=process.env.ACODE_TOKEN_DEBUG==="1";function w(...u){pt&&console.log("[TokenDebug][Adapter]",...u)}const W=["Continue the AgentsWork message loop now.","You MUST call the exact MCP tool named aws-mcp__poll_message as your next action and wait for the next assigned message or task.","Do not answer in plain text before calling aws-mcp__poll_message.","After handling any received work, reply through the appropriate aws-mcp messaging tool, then continue listening again."].join(" "),gt=5e3;function E(u,t){const e=process.env[u];if(e===void 0||e.trim()==="")return t;const o=Number(e.trim());return Number.isFinite(o)&&o>=0?Math.floor(o):t}const N=E("ACODE_DATA_FLOW_WATCHDOG_MS",12e4),ft=5*6e4,ht=E("ACODE_STUCK_AUTOPOLL_TIMEOUT_MS",5*6e4),Tt=250,At=2e3,H=E("ACODE_SUBMIT_TIMEOUT_MS",12e4),K=3e3,_t="\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u6CA1\u6709\u5176\u5B83\u8981\u505A\u7684\uFF0C\u5148\u8C03\u7528 poll_message \u5DE5\u5177\u963B\u585E\u7B49\u5F85\u65B0\u6D88\u606F\u548C\u6D41\u7A0B\u7EBF\u4EFB\u52A1\u63D0\u9192\uFF1B\u6536\u5230\u6D41\u7A0B\u4EFB\u52A1\u63D0\u9192\u540E\u8C03\u7528 my_task \u67E5\u770B\u5DF2\u7531\u540E\u53F0\u9759\u9ED8\u62A2\u5360\u7684\u4EFB\u52A1\u8BE6\u60C5\u5E76\u76F4\u63A5\u5904\u7406\uFF1B\u5B8C\u6210\u4EFB\u52A1\u540E\u8C03\u7528 submit_task_result \u63D0\u4EA4\u7ED3\u679C\uFF0C\u7136\u540E\u7EE7\u7EED poll_message\u3002 \u8C03\u7528 submit_task_result \u65F6\u8BF7\u4E00\u5E76\u4F20\u5165 changeLog\uFF08\u672C\u6B21\u5904\u7406\u7684\u6587\u4EF6/\u5185\u5BB9\u53D8\u66F4\u65E5\u5FD7\uFF0C\u5305\u542B operation \u4E0E path\uFF09\uFF0C\u7528\u4E8E AI \u56DE\u9000\u3002";function St(){return I.resolve(Z())}function bt(u){return X(I.resolve(u)).href}const j=128e3,C={"claude-4":{contextLimit:2e5,maxOutput:8192},"claude-sonnet-4":{contextLimit:2e5,maxOutput:8192},"claude-3-5-sonnet":{contextLimit:2e5,maxOutput:8192},"claude-3-opus":{contextLimit:2e5,maxOutput:8192},"claude-3-haiku":{contextLimit:2e5,maxOutput:8192},"claude-2":{contextLimit:1e5,maxOutput:4096},"gpt-4o":{contextLimit:128e3,maxOutput:16384},"gpt-4-turbo":{contextLimit:128e3,maxOutput:4096},"gpt-4":{contextLimit:8192,maxOutput:4096},"gpt-3.5-turbo":{contextLimit:16384,maxOutput:4096},o1:{contextLimit:2e5,maxOutput:1e5},"o3-mini":{contextLimit:2e5,maxOutput:1e5},"gemini-2.0-flash":{contextLimit:1048576,maxOutput:8192},"gemini-2.5-pro":{contextLimit:1048576,maxOutput:8192},"gemini-1.5-pro":{contextLimit:2097152,maxOutput:8192},"gemini-1.5-flash":{contextLimit:1048576,maxOutput:8192},deepseek:{contextLimit:64e3,maxOutput:8192},"deepseek-chat":{contextLimit:64e3,maxOutput:8192},"deepseek-reasoner":{contextLimit:64e3,maxOutput:8192},"qwen-max":{contextLimit:32e3,maxOutput:8192},"qwen-plus":{contextLimit:128e3,maxOutput:8192},"qwen-turbo":{contextLimit:1e6,maxOutput:8192},"glm-4":{contextLimit:128e3,maxOutput:4096},"yi-":{contextLimit:2e5,maxOutput:4096},"llama-3":{contextLimit:8192,maxOutput:4096},"llama-2":{contextLimit:4096,maxOutput:4096},mistral:{contextLimit:32e3,maxOutput:4096},mixtral:{contextLimit:32e3,maxOutput:4096},codestral:{contextLimit:256e3,maxOutput:8192},grok:{contextLimit:131072,maxOutput:4096},"nova-":{contextLimit:2e5,maxOutput:8192}};function yt(u){if(!u)return j;const t=u.toLowerCase().trim();if(C[t])return C[t].contextLimit;const e=Object.keys(C).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?C[e[0]].contextLimit:j}const Q=4096;function kt(u){if(!u)return Q;const t=u.toLowerCase().trim();if(C[t])return C[t].maxOutput;const e=Object.keys(C).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?C[e[0]].maxOutput:Q}function Ct(u){if(!u||typeof u!="object")return;const t=u,e=h(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),o=h(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(e===0&&o===0)return;let s=h(t.cacheHitTokens,t.promptCacheHitTokens,t.prompt_cache_hit_tokens),a=h(t.cacheMissTokens,t.promptCacheMissTokens,t.prompt_cache_miss_tokens),i=t.cacheHitTokens!==void 0||t.cacheMissTokens!==void 0||t.promptCacheHitTokens!==void 0||t.promptCacheMissTokens!==void 0||t.prompt_cache_hit_tokens!==void 0||t.prompt_cache_miss_tokens!==void 0;if(s===0&&a===0){const n=h(t.cache_read_input_tokens),r=h(t.cache_creation_input_tokens);n>0||r>0?(s=n,a=r+h(t.input_tokens),i=!0):(s=h(t.cache_hit_tokens),a=h(t.cache_miss_tokens),i=i||t.cache_hit_tokens!==void 0||t.cache_miss_tokens!==void 0)}if(s===0&&a===0){const n=h(t.prompt_tokens_details?.cached_tokens);n>0&&(s=n,a=e>n?e-n:0,i=!0)}return{inputTokens:e,outputTokens:o,...s>0||a>0?{cacheHitTokens:s,cacheMissTokens:a}:{},...i?{hasCache:!0}:{}}}function h(...u){for(const t of u){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function G(u){return h(u.estimatedContextTokens,u.contextTokens,u.context_tokens,u.contextUsedTokens,u.context_used_tokens)}function wt(u){return u==="stderr"||u==="mixed"?u:"stdout"}function Pt(u){if(!u||typeof u!="object"||Array.isArray(u))return;const t={};for(const[e,o]of Object.entries(u))typeof o=="string"&&(t[e]=o);return Object.keys(t).length>0?t:void 0}function Lt(u){return u.failed===!0}function J(u,t,e){if(!u)return e?`${t}/${e}`:t;const o=`${t}__`;return u.startsWith(o)?B(`${t}__${u.slice(o.length)}`):B(u.replace("/","__"))}function $t(u){return u==="read_file"||u==="edit_file"||u==="write_file"||u==="bash"}function xt(u){const t=Dt(u);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof u=="string"&&u.trim().length>0}function Dt(u){if(u&&typeof u=="object"&&!Array.isArray(u))return u;if(!(typeof u!="string"||!u.trim()))try{const t=JSON.parse(u);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class Yt extends z{constructor(){super(...arguments),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const o=e.mcpConfigPath||$(),{resolved:s,configContextLimit:a,supportsImage:i}=await this.resolveAcodeProvider(e,o),n=s.model,r=a??yt(n),d=kt(n),p={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:r,maxOutput:d,cacheHitTokens:0,cacheMissTokens:0}};this.sessions.set(t,{adapterSession:p,config:e,runtime:await this.createRuntime(t,n,e,s,i),autoPollActive:!1}),this.emit("status-change",t,"starting");const m=this.sessions.get(t);if(!m)throw new Error("ACode session was not initialized");const c=()=>{const g=this.sessions.get(t);g&&this.getIdlePollLoop(g).start()};this.listenerWakeHooks.set(t,c),at(e.agentId,c);try{await m.runtime.start(),p.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:m.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(g){p.status="error",this.emitRuntimeErrorEvent(t,g),this.emit("status-change",t,"error");const f=this.sessions.get(t);throw f?.capabilitiesFallbackTimer&&clearTimeout(f.capabilitiesFallbackTimer),this.sessions.delete(t),v(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),g}}async sendMessage(t,e){const o=Date.now();l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l("[ACode] \u25B6\uFE0F sendMessage STARTED"),l(`[ACode] Session: ${t}`),l(`[ACode] Message: ${e.slice(0,100)}${e.length>100?"...":""}`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");const s=this.requireSession(t),a=s.adapterSession.status;l(`[ACode] Previous status: ${a}`),this.cancelScheduledAutoPoll(s),s.failedTurnRecoveryScheduled=!1,s.idlePollLoop?.stop();const i={id:U(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};s.adapterSession.messages.push(i),this.emit("conversation-message",t,i),l(`[ACode] Changing status: ${a} \u2192 thinking`),s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,s,"sendMessage");try{l("[ACode] \u25B6\uFE0F Calling runtime.submit()...");const n=Date.now();await s.runtime.submit(e);const r=Date.now()-n;this.cancelSubmitTimeoutDetection(s),l(`[ACode] \u2705 runtime.submit() completed in ${r}ms`),l(`[ACode] Current status after submit: ${s.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Calling recoverResolvedTurnWithoutTerminalEvent()..."),this.recoverResolvedTurnWithoutTerminalEvent(t),l(`[ACode] Status after recovery: ${s.adapterSession.status}`);const d=Date.now()-o;l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l(`[ACode] \u2705 sendMessage COMPLETED in ${d}ms`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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(n){const r=Date.now()-o;console.error(`[ACode] \u274C sendMessage FAILED after ${r}ms:`,n instanceof Error?n.message:String(n)),this.cancelSubmitTimeoutDetection(s),l("[ACode] \u25B6\uFE0F Calling emitRuntimeError with recover=true..."),this.emitRuntimeError(t,n,{recover:!0}),l(`[ACode] Status after error recovery: ${s.adapterSession.status}`)}}async sendConfirmation(t,e){}submitToolPermissionDecision(t,e,o){const s=this.sessions.get(t);if(!s)return!1;s.pendingToolAuthRequests?.delete(e);const a=s.runtime.submitToolPermissionDecision?.(e,o)??!1;return a&&this.startSubmitTimeoutDetection(t,s,"submitToolPermissionDecision"),a}getPendingToolAuthRequests(t){const e=this.sessions.get(t);return e?.pendingToolAuthRequests?Array.from(e.pendingToolAuthRequests.entries()).map(([o,s])=>({requestId:o,capability:s.capability,detail:s.detail,requestedAt:s.requestedAt})):[]}async sendQuestionAnswer(t,e){const o=this.sessions.get(t);if(!o)return;const s=o.pendingQuestionToolCallId;if(!s){l(`[AcodeSdkAdapter] sendQuestionAnswer: no pending question for session ${t}`);return}o.pendingQuestionToolCallId=void 0,o.pendingQuestions=void 0,o.runtime.submitQuestionAnswer&&o.runtime.submitQuestionAnswer(s,e),this.startSubmitTimeoutDetection(t,o,"sendQuestionAnswer")}async abortCurrentTurn(t){await this.requireSession(t).runtime.abort()}async resetContext(t){const e=this.requireSession(t);if(this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.autoPollActive=!1,e.autoPollObservedPollingTool=!1,e.autoPollObservedAssistantText=!1,e.autoPollObservedAnyTool=!1,e.stopAutoPollAfterCurrentTurn=!1,e.idlePollLoop?.stop(),!e.runtime.resetContext)throw new Error("ACode runtime does not support context reset");await e.runtime.resetContext(),e.adapterSession.messages=[];const o=e.adapterSession.totalUsage;if(e.adapterSession.totalUsage={inputTokens:0,outputTokens:0,contextLimit:o.contextLimit,maxOutput:o.maxOutput,inputLimit:o.inputLimit,compactionThreshold:o.compactionThreshold,cacheHitTokens:o.cacheHitTokens,cacheMissTokens:o.cacheMissTokens},e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),e.config.initialPrompt?.trim()){this.startInitialPromptTurn(t,e.config.initialPrompt);return}this.armIdleLoopOrAutoPoll(t)}async terminateSession(t){const e=this.sessions.get(t);if(!e)return;this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),await e.runtime.stop();const o=e.config.agentId;o&&(v(o,this.listenerWakeHooks.get(t)),it(o)),this.listenerWakeHooks.delete(t),e.adapterSession.status="terminated",this.sessions.delete(t),this.emit("status-change",t,"terminated")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.has(t)?t:void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}notifyForceMessage(t){const e=this.sessions.get(t);return e?.runtime?.notifyForceMessage?(e.runtime.notifyForceMessage(),!0):!1}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}async resolveAgentAiInfo(t){try{const e=[...this.sessions.values()].find(i=>i.config.agentId===t);if(!e)return;const o=e.config.mcpConfigPath||$(),{resolved:s,supportsImage:a}=await this.resolveAcodeProvider(e.config,o);return s?.model?{model:s.model,supportsImage:a===!0,...s.baseURL?{baseURL:s.baseURL}:{},...s.apiKey?{apiKey:s.apiKey}:{}}:void 0}catch{return}}async applyAgentFeatures(t){if(!t)return;const e=P(t,O),o=P(t,q);for(const[a,i]of this.sessions){if(i.config.agentId!==t)continue;const n=i.runtime;try{if(e){const r=await D(t,await this.resolveAgentAiInfo(t)),d=n.addBuiltInTools?.(r)??0;d>0&&l(`[acode-adapter] session ${a}: ${d} desktop tools hot-added for agent ${t}`)}else{const r=n.removeBuiltInToolsByPrefix?.("desktop_")??0;r>0&&l(`[acode-adapter] session ${a}: ${r} desktop tools hot-removed for agent ${t}`)}}catch(r){l(`[acode-adapter] session ${a}: desktop feature hot-sync failed for agent ${t}:`,r.message)}if(o)try{const r=await F(t,i.config.scopeKey,typeof i.config.browserAllowPrivate=="boolean"?{allowPrivate:i.config.browserAllowPrivate}:void 0),d=n.addBuiltInTools?.(r)??0;d>0&&l(`[acode-adapter] session ${a}: ${d} browser tools hot-added for agent ${t}`)}catch(r){l(`[acode-adapter] session ${a}: browser feature hot-sync failed for agent ${t}:`,r.message)}}this.syncMcpToolsForAgent(t);const s=ut(t);for(const[a,i]of this.sessions)if(i.config.agentId===t)try{i.runtime.setToolPermissionPolicy?.(s)}catch(n){l(`[acode-adapter] session ${a}: tool permission policy hot-sync failed for agent ${t}:`,n.message)}}syncMcpToolsForAgent(t){if(t){for(const[e,o]of this.sessions)if(o.config.agentId===t)try{o.runtime.requestMcpToolsRefresh?.()}catch(s){l(`[acode-adapter] session ${e}: mcp tools refresh failed for agent ${t}:`,s.message)}}}getPendingQuestion(t){const e=this.sessions.get(t);if(e?.pendingQuestionToolCallId)return{toolCallId:e.pendingQuestionToolCallId,questions:e.pendingQuestions??[]}}cleanup(){for(const t of this.sessions.keys())this.terminateSession(t)}setIdleCommands(t,e){const o=this.sessions.get(t);if(o){if(o.idleCommands=e,this.cancelScheduledAutoPoll(o),e.idleInputCommand&&L(e.idleInputCommand)){this.getIdlePollLoop(o).start();return}o.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.getIdlePollLoop(o).start()}}setRuntimeConstructorForTest(t){this.runtimeConstructor=t}async loadAcodeProviderSection(t){try{const e=await Y.readFile(t,"utf-8"),o=JSON.parse(e),a=o.provider?.default,i=a?.options,n=h(o.contextLimit),r={},d={},p=a?.models;if(p&&typeof p=="object"){for(const[m,c]of Object.entries(p))if(c&&typeof c=="object"){const g=h(c.contextLimit);g>0&&(r[m.trim()]=g);const f=c.modalities?.input,_=Array.isArray(f)&&f.includes("image")||c.supportsImageInput===!0;d[m.trim()]=_===!0}}return{...a?.model?{model:a.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...n>0?{contextLimit:n}:{},...Object.keys(r).length>0?{modelContextLimits:r}:{},...Object.keys(d).length>0?{modelImageSupport:d}:{}}}catch(e){const o=e instanceof Error?e.message:String(e);return x().log({level:"warn",category:"load",message:`loadAcodeProviderSection failed: ${t}: ${o}`,source:"bridge"}),{}}}async resolveAcodeProvider(t,e){const o=typeof t.model=="string"&&t.model.trim()?t.model.trim():void 0,s=x();s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?R(t.instanceAiConfig):null,configPath:e}});const a={...t.instanceAiConfig?.model?{model:t.instanceAiConfig.model}:{},...t.instanceAiConfig?.baseURL?{baseURL:t.instanceAiConfig.baseURL}:{},...t.instanceAiConfig?.apiKey?{apiKey:t.instanceAiConfig.apiKey}:{},...t.instanceAiConfig?.effort?{effort:t.instanceAiConfig.effort}:{},...o?{model:o}:{}},i=await this.loadAcodeProviderSection(e);let n=i.contextLimit;if(!n&&i.modelContextLimits){const d=o||t.instanceAiConfig?.model||i.model;d&&i.modelContextLimits[d]&&(n=i.modelContextLimits[d])}const r=ot(a,i,"acode-default");return s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:R(a),globalConfigModel:i?.model??null,resolvedModel:r.model,resolvedBaseURL:r.baseURL??null,resolvedApiKey:r.apiKey?"[set]":null,configContextLimit:n,resolvedSource:r.source}}),{resolved:r,configPath:e,perSessionModel:o,configContextLimit:n,supportsImage:i.modelImageSupport?.[r.model]===!0}}async createRuntime(t,e,o,s,a){const i=await this.loadRuntimeConstructor(),n=o.mcpConfigPath||$();let r=[];try{r=await F(o.agentId,o.scopeKey,typeof o.browserAllowPrivate=="boolean"?{allowPrivate:o.browserAllowPrivate}:void 0)}catch(c){l(`[acode-adapter] browser tools injection skipped for agent ${o.agentId}:`,c.message)}let d=[];if(P(o.agentId??"",q)&&(d=r),o.agentId&&P(o.agentId,O))try{const c=s?.model?{model:s.model,supportsImage:a===!0,...s.baseURL?{baseURL:s.baseURL}:{},...s.apiKey?{apiKey:s.apiKey}:{}}:void 0,g=await D(o.agentId,c);g.length>0&&(d=[...d,...g])}catch(c){l(`[acode-adapter] desktop tools injection skipped for agent ${o.agentId}:`,c.message)}const p=new i({sessionId:t,agentId:o.agentId,workingDirectory:o.workingDirectory,configPath:n,skillsDir:V(),model:e,systemPrompt:typeof o.systemPrompt=="string"?o.systemPrompt:void 0,globalPrompt:typeof o.globalPrompt=="string"?o.globalPrompt:void 0,rolePrompt:typeof o.rolePrompt=="string"?o.rolePrompt:void 0,memory:typeof o.memory=="string"?o.memory:void 0,env:o.envOverrides,subAgentManager:tt,terminalManager:et,...o.subAgentModel?{subAgentModel:o.subAgentModel}:{},...o.subAgentEffort?{subAgentEffort:o.subAgentEffort}:{},...o.instanceAiConfig?.effort?{effort:o.instanceAiConfig.effort}:{},onFileChange:c=>st({...c,agentId:o.agentId,workspacePath:o.workingDirectory}),extraBuiltInTools:d,...o.agentId?{toolPermissionPolicy:rt(o.agentId)??void 0}:{},subAgentSuiteTools:r,subAgentSuiteToolProvider:this.buildSubAgentSuiteToolProvider(o.agentId)});return x().log({level:"info",category:"resolve",message:"ACode provider resolved",source:"bridge",sessionId:t,details:{resolvedModel:e,perInstanceModel:o.instanceAiConfig?.model||null,perInstanceBaseURL:o.instanceAiConfig?.baseURL?"[set]":null,perInstanceApiKey:o.instanceAiConfig?.apiKey?"[set]":null,configPath:n}}),p.on("event",c=>this.forwardAcodeEvent(c)),p}buildSubAgentSuiteToolProvider(t){return async e=>{if(!t)return[];if(!P(t,O))return[];if(e.length===0)return nt();if(!e.some(a=>{const i=a.trim().replace(/[.*]+$/,"");return i==="desktop"||i.startsWith("desktop.")}))return[];const s=await this.resolveAgentAiInfo(t);return D(t,s)}}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=St(),e=await import(bt(t));if(!e.ACodeRuntime)throw new Error(`ACode runtime export not found: ${t}`);return this.runtimeConstructor=e.ACodeRuntime,this.runtimeConstructor}requireSession(t){const e=this.sessions.get(t);if(!e)throw new Error("ACode session not found");return e}startInitialPromptTurn(t,e){const o=this.sessions.get(t);o&&(o.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,o,"startInitialPromptTurn"),o.runtime.submit(e).then(()=>{this.cancelSubmitTimeoutDetection(o),this.recoverResolvedTurnWithoutTerminalEvent(t)}).catch(s=>{const a=this.sessions.get(t);a&&(this.cancelSubmitTimeoutDetection(a),this.emitRuntimeError(t,s,{recover:!0}))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(e.autoPollActive&&(e.autoPollLastActivityAt=Date.now()),t.type==="assistant_delta"){const o=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:U(),sessionId:t.sessionId,role:"assistant",content:o,timestamp:t.timestamp}),this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"text_delta",{text:o});return}if(t.type==="thinking_delta"){const o=typeof t.data.text=="string"?t.data.text:"";this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"thinking",{text:o});return}if(t.type==="command_output"){this.emitProviderEvent(t,"command_output",{text:typeof t.data.text=="string"?t.data.text:"",stream:wt(t.data.stream),sequence:typeof t.data.sequence=="number"?t.data.sequence:void 0,cwd:typeof t.data.cwd=="string"?t.data.cwd:void 0,commandLineCount:typeof t.data.commandLineCount=="number"?t.data.commandLineCount:void 0,commandFilePath:typeof t.data.commandFilePath=="string"?t.data.commandFilePath:void 0});return}if(t.type==="background_command_completed"){this.emitProviderEvent(t,"background_command_completed",t.data);return}if(t.type==="ai_request"){const o=G(t.data),s=t.data.lastUsage,a=h(s?.inputTokens),i=h(s?.outputTokens),n=h(s?.cacheHitTokens),r=h(s?.cacheMissTokens),d=!!(s&&(a>0||i>0));let p;if(d&&(a>0&&(e.adapterSession.totalUsage.inputTokens=a),i>0&&(e.adapterSession.totalUsage.outputTokens=i),(s?.cacheHitTokens!==void 0||s?.cacheMissTokens!==void 0)&&(e.adapterSession.totalUsage.cacheHitTokens=n,e.adapterSession.totalUsage.cacheMissTokens=r),p={...e.adapterSession.totalUsage},w(`ai_request lastUsage applied: ${JSON.stringify(s)} -> totalUsage=${JSON.stringify(e.adapterSession.totalUsage)}`)),!d&&o>0){const g=e.adapterSession.totalUsage.inputTokens;g>0?e.adapterSession.totalUsage.inputTokens=Math.min(o,Math.floor(g*1.5)):e.adapterSession.totalUsage.inputTokens=o,p={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const c={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};p&&(c.usage=p),w(`ai_request handled: estimatedContextTokens=${t.data.estimatedContextTokens??"n/a"} totalUsage=${JSON.stringify(e.adapterSession.totalUsage)} displayUsage=${JSON.stringify(p??null)}`),this.emit("status-change",t.sessionId,e.adapterSession.status,c),this.startDataFlowWatchdog(t.sessionId,e),e.adapterSession.status==="thinking"&&e.watchdogSubmitStartTime&&(e.watchdogSubmitStartTime=Date.now()),this.emitProviderEvent(t,"ai_request",{model:typeof t.data.model=="string"?t.data.model:void 0,endpoint:typeof t.data.endpoint=="string"?t.data.endpoint:void 0,requestMethod:typeof t.data.requestMethod=="string"?t.data.requestMethod:void 0,requestUrl:typeof t.data.requestUrl=="string"?t.data.requestUrl:void 0,requestHeaders:Pt(t.data.requestHeaders),stream:typeof t.data.stream=="boolean"?t.data.stream:void 0,messageCount:typeof t.data.messageCount=="number"?t.data.messageCount:void 0,toolCount:typeof t.data.toolCount=="number"?t.data.toolCount:void 0,lastUserMessagePreview:typeof t.data.lastUserMessagePreview=="string"?t.data.lastUserMessagePreview:void 0,requestBody:typeof t.data.requestBody=="string"?t.data.requestBody:void 0});return}if(t.type==="turn_complete"){const o=Ct(t.data.usage);if(o){const a=e.adapterSession.totalUsage.inputTokens,i=a>0&&o.inputTokens<Math.floor(a*.2)&&!o.hasCache;w(`turn_complete usage: raw=${JSON.stringify(t.data.usage)} parsed=${JSON.stringify(o)} currentInput=${a} threshold20pct=${Math.floor(a*.2)} isFallbackUsage=${i}`),i?o.outputTokens>0&&(e.adapterSession.totalUsage.outputTokens=o.outputTokens):(e.adapterSession.totalUsage.inputTokens=o.inputTokens,e.adapterSession.totalUsage.outputTokens=o.outputTokens),(o.cacheHitTokens||o.cacheMissTokens)&&(e.adapterSession.totalUsage.cacheHitTokens=o.cacheHitTokens,e.adapterSession.totalUsage.cacheMissTokens=o.cacheMissTokens,l(`[ACode] \u{1F4B0} Cache usage (overwrite from runtime cumulative): hit=${e.adapterSession.totalUsage.cacheHitTokens}, miss=${e.adapterSession.totalUsage.cacheMissTokens} (turn delta: hit=${o.cacheHitTokens||0}, miss=${o.cacheMissTokens||0})`)),w(`totalUsage after turn_complete: ${JSON.stringify(e.adapterSession.totalUsage)}`)}else w(`turn_complete has NO parseable usage: raw=${JSON.stringify(t.data.usage)} failed=${t.data.failed===!0} aborted=${t.data.aborted===!0}`);const s=e.adapterSession.status;if(l(`[ACode] turn_complete event received (session: ${t.sessionId}), previous status: ${s}, failed: ${t.data.failed===!0}, aborted: ${t.data.aborted===!0}`),Lt(t.data)){l(`[ACode] Recovering from failed turn_complete (session: ${t.sessionId})`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(t.data.aborted===!0&&e.autoPollActive){l(`[ACode] Recovering from aborted turn_complete (session: ${t.sessionId}), using R2 2s backoff instead of immediate rearm`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(this.cancelDataFlowWatchdog(e),this.emitProviderEvent(t,"turn_complete",{usage:e.adapterSession.totalUsage,responseBody:typeof t.data.responseBody=="string"?t.data.responseBody:void 0,finishReason:typeof t.data.finishReason=="string"?t.data.finishReason:void 0}),e.adapterSession.status="waiting_input",this.emit("status-change",t.sessionId,"waiting_input",{usage:e.adapterSession.totalUsage}),w(`status-change emitted (waiting_input after turn_complete): usage=${JSON.stringify(e.adapterSession.totalUsage)}`),l(`[ACode] Status changed to waiting_input after turn_complete (session: ${t.sessionId})`),e.autoPollActive&&e.autoPollObservedAssistantText&&!e.autoPollObservedPollingTool&&!e.autoPollObservedAnyTool){e.stopAutoPollAfterCurrentTurn=!0,console.warn(`[${this.displayName}] Auto-poll turn produced assistant text without calling any tool; stopping auto-poll rearm for session ${t.sessionId}`);return}this.armIdleLoopOrAutoPoll(t.sessionId);return}if(t.type==="session_complete"){this.cancelDataFlowWatchdog(e),this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.adapterSession.status="completed",this.emitProviderEvent(t,"session_complete",{exitCode:Number(t.data.exitCode)||0}),this.emit("status-change",t.sessionId,"completed");return}if(t.type==="question_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const o=typeof t.data.toolCallId=="string"?t.data.toolCallId:"",s=Array.isArray(t.data.questions)?t.data.questions:[];o&&(e.pendingQuestionToolCallId=o,e.pendingQuestions=s),this.emit("ask-user-question",{sessionId:t.sessionId,toolCallId:o||void 0,questions:s});return}if(t.type==="tool_permission_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const o=typeof t.data.requestId=="string"?t.data.requestId:"";o&&(e.pendingToolAuthRequests||(e.pendingToolAuthRequests=new Map),e.pendingToolAuthRequests.set(o,{capability:String(t.data.capability||""),detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation},requestedAt:Date.now()})),this.emit("tool-permission-request",{sessionId:t.sessionId,requestId:o,capability:String(t.data.capability||""),agentId:e.config.agentId,detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation}});return}if(t.type==="error"){if(t.data.nonFatal){this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")});return}this.cancelDataFlowWatchdog(e),e.adapterSession.status="error",this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")}),this.emit("status-change",t.sessionId,"error"),e.autoPollActive||this.recoverTurnFailure(t.sessionId,e);return}if(t.type==="mcp_status"){if(!t.data.action&&Array.isArray(t.data.tools)){const f=t.data.tools;f.some(T=>lt(T))||console.warn(`[${this.displayName}] ACode runtime is not exposing a poll_message tool. The LLM cannot call poll_message. Please configure an MCP server that provides poll_message (e.g. aws-mcp) in the dashboard panel for this runtime.`);const A=Array.isArray(t.data.servers)?t.data.servers:[],b=f.map(T=>({name:String(T.name??""),source:String(T.source??""),description:String(T.description??"")})).filter(T=>T.name),y={kind:"mcp",mcpServers:A,mcpTools:b};e.cachedMcpCapabilities=y,e.lastMcpCapabilities=y,e.lastCombinedCapabilities={kind:"combined",mcpServers:A,mcpTools:b,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},l(`[cap-diag] MCP capabilities cached: ${A.length} servers, ${b.length} tools`,{sessionId:t.sessionId,servers:A,toolNames:b.map(T=>T.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const T=e.cachedMcpCapabilities;if(!T)return;const k={...T,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:k,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(k)}),l(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${K}ms)`,{sessionId:t.sessionId,mcpServers:T.mcpServers,mcpToolsCount:T.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},K);return}const o=String(t.data.action??"");l(`[ACode] \u{1F4E1} mcp_status event: action=${o}, server=${typeof t.data.server=="string"?t.data.server:"?"}, tool=${typeof t.data.tool=="string"?t.data.tool:"?"}, toolUseId=${typeof t.data.toolUseId=="string"?t.data.toolUseId.slice(0,16)+"\u2026":"none"}, failed=${t.data.failed===!0}, session=${t.sessionId}, status=${e.adapterSession.status}`);const s=typeof t.data.server=="string"?t.data.server:"mcp",a=typeof t.data.tool=="string"?t.data.tool:"",i=s&&a?`${s}__${a}`:a||s,n=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,r=ct(i,n);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,r.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const d=$t(r.actionType)?r.actionDetail||J(void 0,s,a):J(r.actionDetail,s,a),p=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,m=n?JSON.stringify(n,null,2):void 0,c={toolName:d,rawToolName:i,actionType:r.actionType,actionLabel:r.actionLabel,actionDetail:d,...m?{actionInput:m}:{},...n?{toolInput:n}:{},...p?{toolUseId:p,actionId:p}:{},metadata:{mcpServer:s}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...c,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const f=r.actionType==="idle"&&!xt(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=f,r.actionType==="idle"&&(e.idleToolActiveAt=void 0),this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const _=r.actionType==="idle";this.emit("status-change",t.sessionId,f,_||f==="thinking"?void 0:c);return}const g=r.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=g,r.actionType==="idle"&&(e.idleToolActiveAt=Date.now()),g==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...c}),this.emitProviderEvent(t,"tool_use_start",c),this.emit("status-change",t.sessionId,g,c);return}if(t.type==="skill_status"){const s=(Array.isArray(t.data.skills)?t.data.skills:[]).map(m=>({name:String(m.name??""),description:typeof m.description=="string"?m.description:void 0,directory:typeof m.directory=="string"?m.directory:void 0})).filter(m=>m.name),a=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,n=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(m=>{const c=Array.isArray(m.skills)?m.skills:[];return{dir:typeof m.dir=="string"?m.dir:"",exists:m.exists===!0,skills:c.map(g=>({name:String(g.name??""),description:typeof g.description=="string"?g.description:void 0,directory:typeof g.directory=="string"?g.directory:void 0})).filter(g=>g.name)}}).filter(m=>m.dir),r=e.cachedMcpCapabilities??e.lastMcpCapabilities,d=e.cachedMcpCapabilities!==void 0,p={kind:"combined",mcpServers:r?.mcpServers??[],mcpTools:r?.mcpTools??[],skills:s,skillsDir:a,skillGroups:n};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:p,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(p)}),e.lastCombinedCapabilities=p,l(`[cap-diag] Combined capabilities emitted ${d?"(startup merge)":"(runtime refresh)"}: ${(r?.mcpTools??[]).length} MCP tools, ${s.length} skills`,{sessionId:t.sessionId,mcpServers:r?.mcpServers??[],skillsDir:a}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="startup_phase"){l(`[ACode] \u{1F680} startup_phase swallowed: ${String(t.data.phase??"unknown")}`,{sessionId:t.sessionId});return}if(t.type==="command_status"){if(t.data.action==="commands_loaded"){l(`[ACode] \u{1F4CB} command_status commands_loaded swallowed: ${typeof t.data.installedCommandCount=="number"?t.data.installedCommandCount:"?"} commands`,{sessionId:t.sessionId});return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)});return}if(t.type==="session_started"){const o=G(t.data),s=h(t.data.contextLimit)||void 0,a=h(t.data.maxOutput)||void 0,i=h(t.data.inputLimit)||void 0,n=h(t.data.compactionThreshold)||void 0;let r=!1;o>0&&(e.adapterSession.totalUsage.inputTokens=o,e.adapterSession.totalUsage.outputTokens=0,r=!0),s!==void 0&&(e.adapterSession.totalUsage.contextLimit=s,r=!0),a!==void 0&&(e.adapterSession.totalUsage.maxOutput=a,r=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,r=!0),n!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=n,r=!0),r&&this.emit("status-change",t.sessionId,e.adapterSession.status,{usage:e.adapterSession.totalUsage});return}if(t.type==="exit_plan_mode"){e.adapterSession.status="waiting_input";const o=typeof t.data.plan=="string"?t.data.plan:void 0;this.emitProviderEvent(t,"exit_plan_mode",{toolInput:t.data.toolInput&&typeof t.data.toolInput=="object"?t.data.toolInput:void 0,text:o||"\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"}),this.emit("status-change",t.sessionId,"waiting_input",{actionLabel:"\u5BA1\u6279\u8BA1\u5212",actionDetail:o||"\u7B49\u5F85\u7528\u6237\u5BA1\u6279\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"});return}if(t.type==="context_compaction"){const o=t.data,s=o.action,a=s==="start",i=s==="end",n=s==="phase",r=o.parentId,d=o.compactionId;let p,m;if(a){const g=String(o.sizeKB??o.sizeBeforeKB??"?"),f=String(o.messageCount??o.messageCountBefore??"?"),_=o.estimatedTokens,A=o.actualInputTokens?`input=${o.actualInputTokens}`:"",b=o.actualOutputTokens?`output=${o.actualOutputTokens}`:"",y=o.trigger?`, \u89E6\u53D1: ${o.trigger}`:"";p="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",_!==void 0?m=`\u538B\u7F29\u524D: ~${_} tokens, \u6D88\u606F: ${f}\u6761`+(A?`, \u5B9E\u9645 tokens: ${A} ${b}`:"")+y:m=`\u538B\u7F29\u524D: ${g}KB, \u6D88\u606F: ${f}\u6761`+(A?`, \u5B9E\u9645 tokens: ${A} ${b}`:"")+y}else if(n)p=String(o.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),m=String(o.phaseDetail??"");else{const g=o.tokensBefore,f=o.tokensAfter,_=o.freedTokens,A=String(o.sizeBeforeKB??"?"),b=String(o.sizeAfterKB??"?"),y=String(o.freedKB??"?"),T=String(o.strategy??"?"),k=Number(o.prunedToolMessages??0),S=Number(o.summarizedMessages??0);p="\u538B\u7F29\u5B8C\u6210",g!==void 0&&f!==void 0?m=`\u91CA\u653E: ${_??g-f} tokens, ${g} tokens \u2192 ${f} tokens, \u7B56\u7565: ${T}`+(k?`, \u88C1\u526A\u5DE5\u5177: ${k}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:""):m=`\u91CA\u653E: ${y}KB, ${A}KB \u2192 ${b}KB, \u7B56\u7565: ${T}`+(k?`, \u88C1\u526A\u5DE5\u5177: ${k}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:"")}a&&(e.adapterSession.status="compacting");const c={actionType:"context_compaction",actionLabel:p,actionDetail:m};if(a&&d)c.actionId=d;else if((n||i)&&d)if(c.parentId=d,n){const g=String(o.phase??"unknown");c.actionId=`${d}-phase-${g}`}else c.actionId=`${d}-end`;n&&r&&!c.parentId&&(c.parentId=r),i&&(e.adapterSession.totalUsage.inputTokens=h(o.tokensAfter),e.adapterSession.totalUsage.outputTokens=0,c.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",c),this.emit("status-change",t.sessionId,"compacting",c);return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)})}}emitProviderEvent(t,e,o){this.emit("event",{type:e,sessionId:t.sessionId,timestamp:t.timestamp,data:o})}armIdleLoopOrAutoPoll(t){const e=this.sessions.get(t);if(!(!e||this.isTerminalStatus(e.adapterSession.status))){if(e.idleCommands?.idleInputCommand){this.getIdlePollLoop(e).start();return}this.scheduleAutoPoll(t)}}getIdlePollLoop(t){if(t.idlePollLoop)return t.idlePollLoop;const e=t.adapterSession.sessionId;return t.idlePollLoop=new dt({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:o=>L(o),preDispatchHook:()=>null,dispatchPollingPrompt:(o,s)=>this.submitAutoPollPrompt(e,s?o:_t,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:o=>this.submitAutoPollPrompt(e,o)}),t.idlePollLoop}submitAutoPollPrompt(t,e,o){const s=this.sessions.get(t);if(!s||this.isTerminalStatus(s.adapterSession.status))return;const a=(s.autoPollToken??0)+1;s.autoPollToken=a,s.autoPollActive=!0,s.autoPollObservedPollingTool=!1,s.autoPollObservedAssistantText=!1,s.autoPollObservedAnyTool=!1,s.stopAutoPollAfterCurrentTurn=!1,s.autoPollQueuedAt=Date.now(),s.autoPollLastActivityAt=Date.now(),s.idleToolActiveAt=void 0,o?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking")),this.startSubmitTimeoutDetection(t,s,"submitAutoPollPrompt"),s.runtime.submit(e).catch(i=>{this.emitRuntimeError(t,i)}).finally(()=>{const i=this.sessions.get(t);if(i){if(i.autoPollToken!==a){l(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${a}, current=${i.autoPollToken}), skipping cleanup \u2014 newer turn has taken over`);return}if(this.cancelSubmitTimeoutDetection(i),i.autoPollActive=!1,i.failedTurnRecoveryScheduled||i.autoPollTimer){i.failedTurnRecoveryScheduled=!1;return}if(i.stopAutoPollAfterCurrentTurn){i.stopAutoPollAfterCurrentTurn=!1,i.autoPollObservedPollingTool=!1,i.autoPollObservedAssistantText=!1,i.autoPollObservedAnyTool=!1;return}if(i.adapterSession.status==="error"){this.recoverTurnFailure(t,i);return}if(i.adapterSession.status==="thinking"||i.adapterSession.status==="tool_using"){this.recoverResolvedTurnWithoutTerminalEvent(t);return}i.adapterSession.status==="waiting_input"&&this.armIdleLoopOrAutoPoll(t)}})}scheduleAutoPoll(t,e=Tt){const o=this.sessions.get(t);!o||o.autoPollActive||o.autoPollTimer||this.isTerminalStatus(o.adapterSession.status)||(o.autoPollTimer=setTimeout(()=>{const s=this.sessions.get(t);!s||s.autoPollActive||this.isTerminalStatus(s.adapterSession.status)||(s.autoPollTimer=void 0,this.submitAutoPollPrompt(t,W,{keepWaitingStatus:!0}))},e))}cancelScheduledAutoPoll(t){t.autoPollTimer&&(clearTimeout(t.autoPollTimer),t.autoPollTimer=void 0)}isTerminalStatus(t){return t==="completed"||t==="terminated"}emitRuntimeError(t,e,o){const s=this.sessions.get(t);s&&(s.adapterSession.status="error",this.emitRuntimeErrorEvent(t,e),this.emit("status-change",t,"error"),o?.recover&&this.recoverTurnFailure(t,s))}emitRuntimeErrorEvent(t,e){const o=new Date().toISOString();this.emit("event",{type:"error",sessionId:t,timestamp:o,data:{text:e instanceof Error?e.message:String(e)}})}estimateOutputTokensFromMessages(t){const e=t.filter(o=>o.role==="assistant").map(o=>o.content).join("");return Math.max(0,Math.round(e.length/4))}recoverTurnFailure(t,e){if(this.isTerminalStatus(e.adapterSession.status))return;if(e.idleToolActiveAt=void 0,e.pendingToolAuthRequests?.size&&e.pendingToolAuthRequests.clear(),e.adapterSession.status==="tool_using"&&e.pendingToolEventData){const n=e.pendingToolEventData;l(`[ACode] recoverTurnFailure: \u8865\u53D1 tool_use_end (tool: ${n.toolName??"unknown"}) \u5173\u95ED\u65F6\u95F4\u7EBF\u6761\u76EE\uFF0C\u907F\u514D\u6C38\u4E45\u5361\u5728\u5DE5\u5177\u6267\u884C\u72B6\u6001`),this.emit("event",{type:"tool_use_end",sessionId:t,timestamp:new Date().toISOString(),data:{...n,toolResult:"[aborted] \u5DE5\u5177\u6267\u884C\u88AB\u6570\u636E\u6D41\u770B\u95E8\u72D7\u4E2D\u65AD"}}),e.pendingToolEventData=void 0}const o=this.estimateOutputTokensFromMessages(e.adapterSession.messages);if(o>0){const n=e.adapterSession.totalUsage.outputTokens;e.adapterSession.totalUsage.outputTokens=o,l(`[ACode] recoverTurnFailure: \u4F30\u7B97\u8986\u76D6 output tokens ${n} -> ${o} (totalUsage now: input=${e.adapterSession.totalUsage.inputTokens}, output=${e.adapterSession.totalUsage.outputTokens})`)}const s=e.idleCommands?.idleInputCommand,i=!!(s&&L(s))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;if(e.autoPollTimer||e.failedTurnRecoveryScheduled){e.adapterSession.status!=="waiting_input"&&(e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage,...i}));return}this.cancelScheduledAutoPoll(e),e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage,...i}),e.failedTurnRecoveryScheduled=!0,e.autoPollTimer=setTimeout(()=>{const n=this.sessions.get(t);if(!n||n.autoPollActive||this.isTerminalStatus(n.adapterSession.status)){n&&(n.failedTurnRecoveryScheduled=!1);return}n.autoPollTimer=void 0,n.failedTurnRecoveryScheduled=!1,n.idleCommands?.idleInputCommand?this.getIdlePollLoop(n).start():this.submitAutoPollPrompt(t,W,{keepWaitingStatus:!0})},At)}recoverResolvedTurnWithoutTerminalEvent(t){l(`[ACode] \u25B6\uFE0F recoverResolvedTurnWithoutTerminalEvent called for session ${t}`);const e=this.sessions.get(t);if(!e||this.isTerminalStatus(e.adapterSession.status)){l(`[ACode] Skipping recovery: entry=${!!e}, isTerminal=${e?this.isTerminalStatus(e.adapterSession.status):"N/A"}`);return}if(l(`[ACode] Current status: ${e.adapterSession.status}`),e.adapterSession.status!=="thinking"&&e.adapterSession.status!=="tool_using"){l(`[ACode] Skipping recovery: status is ${e.adapterSession.status} (not thinking/tool_using)`);return}console.warn(`[ACode] \u26A0\uFE0F Detected stuck state: ${e.adapterSession.status} after submit resolved! Recovering to waiting_input. If runtime.submit() is still pending (e.g., built-in tool execution not interruptible by abort()), the submitQueue is deadlocked and subsequent auto-poll/user submits will never execute.`),l("[ACode] Recovering to waiting_input..."),e.adapterSession.status="waiting_input";const o=e.idleCommands?.idleInputCommand,a=!!(o&&L(o))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",a),l(`[ACode] \u2705 Recovery complete, status now: ${e.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Arming idle loop or auto-poll..."),this.armIdleLoopOrAutoPoll(t),l("[ACode] \u2705 Idle loop armed, recovery process complete")}startSubmitTimeoutDetection(t,e,o){this.cancelSubmitTimeoutDetection(e),e.watchdogSubmitStartTime=Date.now(),e.watchdogLastDataFlowTime=Date.now(),e.watchdogTimer=setInterval(()=>{const s=this.sessions.get(t);if(!s){this.cancelSubmitTimeoutDetection(e);return}const a=s.adapterSession.status,i=Date.now();if(a==="waiting_input"){if(s.autoPollActive&&s.autoPollLastActivityAt&&s.idleToolActiveAt===void 0&&i-s.autoPollLastActivityAt>=ht){console.warn(`[ACode] CRITICAL: stuck auto-poll detected after ${Math.round((i-s.autoPollLastActivityAt)/1e3)}s (source: ${o}, session: ${t}): submit queued but no runtime events and no active poll_message tool. Forcing recovery (runtime force-settle will unblock submitQueue).`),this.executeWatchdogRecovery(t,s,o,"stuck_autopoll",i-s.autoPollLastActivityAt);return}s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(a==="tool_using"){const d=i-(s.watchdogLastDataFlowTime||i);if(d>=ft){const p=String(s.pendingToolEventData?.rawToolName??"");if((s.pendingToolAuthRequests?.size??0)>0){console.warn(`[ACode] tool_using elapsed ${Math.round(d/1e3)}s but ${s.pendingToolAuthRequests.size} tool permission request(s) awaiting user decision (session: ${t}), skipping recovery`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(p.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(d/1e3)}s but await_complete is running (session: ${t}, tool: ${p}), skipping recovery (sub-agents have their own watchdogs, bg commands have timeout limits)`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(console.warn(`[ACode] CRITICAL: tool_using slow timeout triggered after ${Math.round(d/1e3)}s (source: ${o}, session: ${t}). Tool execution likely hung. Forcing recovery via recoverTurnFailure.`),s.runtime.detachCurrentToolExecution?.()){console.warn(`[ACode] tool_using slow (${Math.round(d/1e3)}s): detached tool ${p} to background (session: ${t}); waiting for the real tool_result to continue the turn`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}this.executeWatchdogRecovery(t,s,o,"tool_using_slow",d);return}s.watchdogSubmitStartTime=i;return}if(a!=="thinking")return;const n=i-(s.watchdogSubmitStartTime||i),r=i-(s.watchdogLastDataFlowTime||i);if(N>0&&r>=N){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(r/1e3)}s (source: ${o}, session: ${t}, status: ${a}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"data_flow",r);return}if(H>0&&n>=H){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(n/1e3)}s (source: ${o}, session: ${t}, status: ${a}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,s,o,"submit_timeout",n);return}},gt)}executeWatchdogRecovery(t,e,o,s,a){l(`[ACode] Watchdog (${s}): calling runtime.abort() after ${Math.round(a/1e3)}s...`);try{e.runtime.abort(),l(`[ACode] Watchdog (${s}): runtime.abort() called`)}catch(i){console.warn(`[ACode] \u26A0\uFE0F Watchdog (${s}): runtime.abort() threw: ${i instanceof Error?i.message:String(i)}`)}this.cancelSubmitTimeoutDetection(e),this.recoverTurnFailure(t,e),console.warn(`[ACode] \u26A0\uFE0F Watchdog (${s}) recovery complete. If abort() could not cancel the underlying operation, submitQueue may still be deadlocked.`)}cancelSubmitTimeoutDetection(t){t.watchdogTimer&&(clearInterval(t.watchdogTimer),t.watchdogTimer=void 0),t.watchdogSubmitStartTime=void 0,t.watchdogLastDataFlowTime=void 0}resetDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now(),e.watchdogSubmitStartTime=Date.now()}startDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now()}cancelDataFlowWatchdog(t){t.watchdogLastDataFlowTime=Date.now()}formatAiRequestActionDetail(t){const e=`
2
2
 
3
3
  \u8BF7\u6C42\u5934:
4
4
  `,o=`
5
5
 
6
6
  \u8BF7\u6C42\u4F53:
7
- `,n=typeof t.model=="string"?t.model:"",i=typeof t.endpoint=="string"?t.endpoint:typeof t.requestUrl=="string"?t.requestUrl:"",a=typeof t.requestMethod=="string"?t.requestMethod:"",r=typeof t.stream=="boolean"?t.stream:void 0,c=typeof t.messageCount=="number"?t.messageCount:void 0,p=typeof t.toolCount=="number"?t.toolCount:void 0,m=typeof t.lastUserMessagePreview=="string"?t.lastUserMessagePreview:"",d=[n?`\u6A21\u578B: ${n}`:void 0,i?`\u63A5\u53E3: ${i}`:void 0,a?`\u65B9\u6CD5: ${a}`:void 0,r!==void 0?`\u6D41\u5F0F: ${r?"\u662F":"\u5426"}`:void 0,c!==void 0?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${c}`:void 0,p!==void 0?`\u53EF\u7528\u5DE5\u5177: ${p}`:void 0,m?`\u6700\u540E\u8BF7\u6C42: ${m}`:void 0].filter(S=>!!S),g=/^(authorization|x-api-key|api-key|cookie|set-cookie|x-auth-token|token)$/i,f=t.requestHeaders,A=f?Object.entries(f).filter(([S])=>!g.test(S)).map(([S,M])=>`${S}: ${M}`).filter(S=>S.trim().length>0):[],_=d.join(`
8
- `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",k=A.length>0?`${e}${A.join(`
9
- `)}`:"",b=typeof t.requestBody=="string"?t.requestBody:"",T=b.length>6e4?`${b.slice(0,6e4)}
10
- ...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:b,C=T?`${o}${T}`:"";return`${_}${k}${C}`}}export{Jt as AcodeSdkAdapter,wt as isFailedAcodeTurnComplete,At as toAcodeEsmImportSpecifier};
7
+ `,a=typeof t.model=="string"?t.model:"",i=typeof t.endpoint=="string"?t.endpoint:typeof t.requestUrl=="string"?t.requestUrl:"",n=typeof t.requestMethod=="string"?t.requestMethod:"",r=typeof t.stream=="boolean"?t.stream:void 0,d=typeof t.messageCount=="number"?t.messageCount:void 0,p=typeof t.toolCount=="number"?t.toolCount:void 0,m=typeof t.lastUserMessagePreview=="string"?t.lastUserMessagePreview:"",c=[a?`\u6A21\u578B: ${a}`:void 0,i?`\u63A5\u53E3: ${i}`:void 0,n?`\u65B9\u6CD5: ${n}`:void 0,r!==void 0?`\u6D41\u5F0F: ${r?"\u662F":"\u5426"}`:void 0,d!==void 0?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${d}`:void 0,p!==void 0?`\u53EF\u7528\u5DE5\u5177: ${p}`:void 0,m?`\u6700\u540E\u8BF7\u6C42: ${m}`:void 0].filter(S=>!!S),g=/^(authorization|x-api-key|api-key|cookie|set-cookie|x-auth-token|token)$/i,f=t.requestHeaders,_=f?Object.entries(f).filter(([S])=>!g.test(S)).map(([S,M])=>`${S}: ${M}`).filter(S=>S.trim().length>0):[],A=c.join(`
8
+ `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",b=_.length>0?`${e}${_.join(`
9
+ `)}`:"",y=typeof t.requestBody=="string"?t.requestBody:"",T=y.length>6e4?`${y.slice(0,6e4)}
10
+ ...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:y,k=T?`${o}${T}`:"";return`${A}${b}${k}`}}export{Yt as AcodeSdkAdapter,Lt as isFailedAcodeTurnComplete,bt as toAcodeEsmImportSpecifier};
11
11
 
@@ -314,6 +314,15 @@ export declare abstract class BaseProviderAdapter extends EventEmitter {
314
314
 
315
315
  abstract sendQuestionAnswer?(sessionId: string, answers: Record<string, string>): Promise<void>;
316
316
 
317
+ abstract submitToolPermissionDecision?(sessionId: string, requestId: string, allowed: boolean): boolean;
318
+
319
+ abstract getPendingToolAuthRequests?(sessionId: string): Array<{
320
+ requestId: string;
321
+ capability: string;
322
+ detail: Record<string, unknown>;
323
+ requestedAt: number;
324
+ }>;
325
+
317
326
  abstract setIdleCommands?(sessionId: string, commands: {
318
327
  idleInputCommand: string;
319
328
  nonInputCommand: string;
@@ -1,2 +1,2 @@
1
- import{resolveSsrfConfig as E,validateUrlWithDns as M}from"./ssrf-guard.js";import{locateElement as U}from"./element-locator.js";import{serializeSnapshot as P,buildRefMap as j}from"./snapshot-serializer.js";import{DEFAULT_BROWSER_ID as k}from"./types.js";const X=3e4,$=1e4;function oe(v){const{pool:b,wsServer:_}=v,q=v.agentId,N=v.scopeKey,D=E({perAgent:v.ssrfConfig,pool:b.getSsrfConfig()});function u(e){const r=(typeof e.agentId=="string"&&e.agentId.trim()?e.agentId.trim():void 0)??q;if(!r)throw new Error("agentId is required: pass via createBuiltInBrowserTools({agentId}) or tool args.agentId");const n=typeof e.browserId=="string"&&e.browserId.trim()?e.browserId.trim():k,s=typeof e.title=="string"&&e.title.trim()?e.title.trim():void 0,o=N??`agent:${r}`;return{agentId:r,browserId:n,title:s,scopeKey:o}}function B(e,t){const r=b.get(e,t);if(!r)throw new Error(`Browser session not launched for ${e}/${t}. Call browser_launch first.`);if(r.humanTakeover)throw new Error(`Human takeover active for ${e}/${t}. Release takeover before calling browser tools.`);return b.touchActivity(e,t),r}function m(e,t){return{session:B(e,t),page:b.getActivePage(e,t)}}function p(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}function I(e,t){if(e)try{e.archive.record(t)}catch{}}function x(e){const t={};for(const[r,n]of Object.entries(e))n!==void 0&&(t[r]=n);return t}const T=new Map;function A(e,t){return`${e}:${t}`}function C(e,t,r){return T.get(A(e,t))?.get(r)}function R(e,t,r){T.set(A(e,t),j(r))}return v.pool.onSessionClose((e,t)=>{T.delete(A(e,t))}),[{kind:"builtin",toolName:"browser_launch",exposedName:"browser_launch",description:"Launch a headless browser session for the current agent. Returns wsUrl for live JPEG frame streaming (open in browser to watch the agent operate). Pass browserId to start a separate browser instance (independent cookies/cache/storage). Default browserId is 'default'. Must be called before any other browser_* tool. The session is automatically reclaimed after 10 minutes of inactivity. title is required and should briefly describe the intent of this browser session (e.g. '\u641C\u7D22\u7ADE\u54C1\u4EF7\u683C', '\u767B\u5F55\u7BA1\u7406\u540E\u53F0').",inputSchema:{type:"object",properties:{agentId:{type:"string",description:"Agent identifier (optional if configured at factory time). Used to isolate browser sessions across agents."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default'). Same agent can have multiple browserIds (each = independent chromium process)."},title:{type:"string",description:"Brief human-readable title describing the intent of this browser session (e.g. '\u641C\u7D22\u7ADE\u54C1\u4EF7\u683C', '\u767B\u5F55\u7BA1\u7406\u540E\u53F0'). Required \u2014 used as tab label in dashboard."}},required:["title"]},async execute(e){try{const{agentId:t,browserId:r,title:n,scopeKey:s}=u(e),o=await b.getOrLaunch(t,r,n,s),a=o.pages[o.activePageIndex].viewportSize(),c={ok:!0,agentId:t,browserId:o.browserId,title:o.title,viewport:{width:a?.width??0,height:a?.height??0}};return _&&(c.wsUrl=_.getUrl(t,o.browserId)),c}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_navigate",exposedName:"browser_navigate",description:"Navigate the active page to a URL. Waits for DOMContentLoaded (30s timeout). Access to private/loopback addresses is allowed by default (configurable).",inputSchema:{type:"object",properties:{url:{type:"string",description:"Target URL (http/https only). Private IP ranges are allowed by default, can be disabled via ssrfConfig."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:["url"]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.url=="string"?e.url:"";if(!o)return{ok:!1,error:"url is required"};const i=await M(o,D),a=s.url(),c=Date.now();await s.goto(i,{waitUntil:"domcontentloaded",timeout:X});const l=s.url();try{await n.listenerManager.reattach(s)}catch{}let d="";try{d=await s.title()}catch{}return I(n,{tool:"browser_navigate",args:x({url:i,browserId:r}),beforeUrl:a,afterUrl:l,durationMs:Date.now()-c}),{ok:!0,url:i,finalUrl:l,title:d,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_snapshot",exposedName:"browser_snapshot",description:"Capture the active page's accessibility tree as YAML (Playwright ariaSnapshot mode=ai). Interactive elements get [ref=eXX] markers \u2014 pass the eXX string to browser_click / browser_type / browser_select. Re-snapshot after navigation (refs are invalidated on page change). Output truncated to maxChars (default 16000).",inputSchema:{type:"object",properties:{maxChars:{type:"number",description:"Max chars to return (default 16000)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{page:n}=m(t,r),s=typeof e.maxChars=="number"&&e.maxChars>0?Math.floor(e.maxChars):void 0,o=await P(n,{maxChars:s});R(t,r,o);let i="";try{i=await n.title()}catch{}return{ok:!0,snapshot:o,url:n.url(),title:i,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_click",exposedName:"browser_click",description:"Click an element identified by ref (from browser_snapshot), text (getByText), role+name (getByRole), or CSS selector. ref is preferred, but text/role are more stable on SPA pages where refs invalidate frequently. If ref fails, the system auto-falls back to the cached role+name from the last snapshot and retries the snapshot once. 10s timeout.",inputSchema:{type:"object",properties:{ref:{type:"string",description:"Element ref from browser_snapshot, e.g. 'e5' (preferred)."},text:{type:"string",description:"Locate element by visible text (getByText). More stable than ref on SPA pages, e.g. 'javaok'."},role:{type:"string",description:"Locate element by ARIA role (e.g. button, link, textbox, listitem). Use with 'name'."},name:{type:"string",description:"Accessible name to combine with 'role' (e.g. role=button + name='Submit')."},selector:{type:"string",description:"CSS selector (subset: tag/.class/#id/[attr]/descendant/>)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.ref=="string"&&e.ref.trim()?e.ref.trim():void 0,i=typeof e.text=="string"&&e.text.trim()?e.text.trim():void 0,a=typeof e.role=="string"&&e.role.trim()?e.role.trim():void 0,c=typeof e.name=="string"&&e.name?e.name:void 0,l=typeof e.selector=="string"?e.selector:void 0;if(o===void 0&&i===void 0&&a===void 0&&!l)return{ok:!1,error:"Either 'ref', 'text', 'role', or 'selector' is required for browser_click"};const d=o!==void 0?C(t,r,o):void 0,h=await U(s,{ref:o,text:i,role:a,name:c,selector:l,refFallback:d}),w=s.url(),y=Date.now();await h.click({timeout:$});const f=s.url(),g=o!==void 0?`ref=${o}`:i!==void 0?`text=${i}`:a!==void 0?`role=${a}`:`selector=${l}`;return I(n,{tool:"browser_click",args:x({ref:o,text:i,role:a,name:c,selector:l,browserId:r}),beforeUrl:w,afterUrl:f,durationMs:Date.now()-y}),{ok:!0,clicked:g,url:f,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_type",exposedName:"browser_type",description:"Type text into an input identified by ref, role+name (getByRole), or CSS selector. Note: 'text' param is the text to type (not for locating); use 'role'+'name' to locate the input. clear=true (default) clears the field first. delay adds per-keystroke delay (ms).",inputSchema:{type:"object",properties:{ref:{type:"string",description:"Element ref from browser_snapshot, e.g. 'e5'."},role:{type:"string",description:"Locate input by ARIA role (e.g. textbox, searchbox). Use with 'name'."},name:{type:"string",description:"Accessible name to combine with 'role'."},selector:{type:"string",description:"CSS selector subset."},text:{type:"string",description:"Text to type (required)."},clear:{type:"boolean",description:"Clear field before typing (default true)."},delay:{type:"number",description:"Per-keystroke delay in ms (default 0)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:["text"]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.ref=="string"&&e.ref.trim()?e.ref.trim():void 0,i=typeof e.role=="string"&&e.role.trim()?e.role.trim():void 0,a=typeof e.name=="string"&&e.name?e.name:void 0,c=typeof e.selector=="string"?e.selector:void 0,l=typeof e.text=="string"?e.text:"";if(!l)return{ok:!1,error:"text is required for browser_type"};if(o===void 0&&i===void 0&&!c)return{ok:!1,error:"Either 'ref', 'role', or 'selector' is required for browser_type"};const d=e.clear!==!1,h=typeof e.delay=="number"&&e.delay>=0?e.delay:0,w=o!==void 0?C(t,r,o):void 0,y=await U(s,{ref:o,role:i,name:a,selector:c,refFallback:w}),f=s.url(),g=Date.now();d&&await y.fill(""),await y.type(l,{delay:h});const S=s.url();return I(n,{tool:"browser_type",args:x({ref:o,role:i,name:a,selector:c,text:l,clear:d,delay:h,browserId:r}),beforeUrl:f,afterUrl:S,durationMs:Date.now()-g}),{ok:!0,typed:l.length,url:S,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_select",exposedName:"browser_select",description:"Select an option in a <select> element identified by ref, text (getByText), role+name (getByRole), or CSS selector. value is the option value (string).",inputSchema:{type:"object",properties:{ref:{type:"string",description:"Element ref from browser_snapshot, e.g. 'e5'."},text:{type:"string",description:"Locate element by visible text (getByText)."},role:{type:"string",description:"Locate element by ARIA role (e.g. combobox, listbox). Use with 'name'."},name:{type:"string",description:"Accessible name to combine with 'role'."},selector:{type:"string",description:"CSS selector subset."},value:{type:"string",description:"Option value to select (required)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:["value"]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.ref=="string"&&e.ref.trim()?e.ref.trim():void 0,i=typeof e.text=="string"&&e.text.trim()?e.text.trim():void 0,a=typeof e.role=="string"&&e.role.trim()?e.role.trim():void 0,c=typeof e.name=="string"&&e.name?e.name:void 0,l=typeof e.selector=="string"?e.selector:void 0,d=typeof e.value=="string"?e.value:e.value!==void 0&&e.value!==null?String(e.value):"";if(!d)return{ok:!1,error:"value is required for browser_select"};if(o===void 0&&i===void 0&&a===void 0&&!l)return{ok:!1,error:"Either 'ref', 'text', 'role', or 'selector' is required for browser_select"};const h=o!==void 0?C(t,r,o):void 0,w=await U(s,{ref:o,text:i,role:a,name:c,selector:l,refFallback:h}),y=s.url(),f=Date.now();await w.selectOption(d);const g=s.url();return I(n,{tool:"browser_select",args:x({ref:o,text:i,role:a,name:c,selector:l,value:d,browserId:r}),beforeUrl:y,afterUrl:g,durationMs:Date.now()-f}),{ok:!0,selected:d,url:g,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_press_key",exposedName:"browser_press_key",description:"Press a keyboard key on the active page. Examples: 'Enter', 'Escape', 'Tab', 'Control+a', 'ArrowDown'. See Playwright key names for full list.",inputSchema:{type:"object",properties:{key:{type:"string",description:"Key or chord (e.g. 'Enter', 'Control+a')."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:["key"]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.key=="string"?e.key:"";if(!o)return{ok:!1,error:"key is required for browser_press_key"};const i=s.url(),a=Date.now();await s.keyboard.press(o);const c=s.url();return I(n,{tool:"browser_press_key",args:x({key:o,browserId:r}),beforeUrl:i,afterUrl:c,durationMs:Date.now()-a}),{ok:!0,key:o,url:c,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_scroll",exposedName:"browser_scroll",description:"Scroll the active page. Provide x/y for absolute scroll-to, OR deltaX/deltaY for relative wheel scroll. If both provided, x/y wins.",inputSchema:{type:"object",properties:{x:{type:"number",description:"Absolute scrollX (window.scrollTo)."},y:{type:"number",description:"Absolute scrollY (window.scrollTo)."},deltaX:{type:"number",description:"Relative wheel delta X."},deltaY:{type:"number",description:"Relative wheel delta Y."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.x=="number"&&Number.isFinite(e.x)||typeof e.y=="number"&&Number.isFinite(e.y),i=typeof e.deltaX=="number"&&Number.isFinite(e.deltaX)||typeof e.deltaY=="number"&&Number.isFinite(e.deltaY);if(!o&&!i)return{ok:!1,error:"Provide x/y (absolute) or deltaX/deltaY (relative) for browser_scroll"};const a=s.url(),c=Date.now();let l=0,d=0;if(o){const w=typeof e.x=="number"?e.x:0,y=typeof e.y=="number"?e.y:0;await s.evaluate(([g,S])=>globalThis.scrollTo(g,S),[w,y]);const f=await s.evaluate(()=>globalThis);l=f.scrollX,d=f.scrollY}else{const w=typeof e.deltaX=="number"?e.deltaX:0,y=typeof e.deltaY=="number"?e.deltaY:0;await s.mouse.wheel(w,y);const f=await s.evaluate(()=>globalThis);l=f.scrollX,d=f.scrollY}const h=s.url();return I(n,{tool:"browser_scroll",args:x({x:e.x,y:e.y,deltaX:e.deltaX,deltaY:e.deltaY,browserId:r}),beforeUrl:a,afterUrl:h,durationMs:Date.now()-c}),{ok:!0,scrollX:l,scrollY:d,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_screenshot",exposedName:"browser_screenshot",description:"Capture a single screenshot of the active page. Returns dataUrl (base64-encoded). fullPage=true captures the entire scrollable page (may be large).",inputSchema:{type:"object",properties:{fullPage:{type:"boolean",description:"Capture entire scrollable page (default false)."},format:{type:"string",enum:["jpeg","png"],description:"Image format (default 'jpeg')."},quality:{type:"number",description:"JPEG quality 0-100 (default 80, ignored for png)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{page:n}=m(t,r),s=e.fullPage===!0,o=e.format==="png"||e.format==="jpeg"?e.format:"jpeg",i=typeof e.quality=="number"&&e.quality>=0&&e.quality<=100?e.quality:80,c=(await n.screenshot({fullPage:s,type:o,quality:o==="jpeg"?i:void 0})).toString("base64"),l=`data:image/${o};base64,${c}`,d=n.viewportSize();return{ok:!0,dataUrl:l,width:d?.width??0,height:d?.height??0,url:n.url(),browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_close",exposedName:"browser_close",description:"Close the default browser session (browserId='default') for the current agent. Returns the step archive (recent operations). To close a non-default browser session, use browser_session_close({browserId}).",inputSchema:{type:"object",properties:{agentId:{type:"string",description:"Agent identifier (optional)."}},required:[]},async execute(e){try{const{agentId:t}=u(e),r=b.get(t,k);if(!r)return{ok:!1,error:`Browser session not launched for ${t}/${k}. Call browser_launch first.`};const n=r.archive.toJSON();return await b.close(t,k),{ok:!0,browserId:k,archive:n}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_list_sessions",exposedName:"browser_list_sessions",description:"List all browser sessions for the current agent. Returns an array of {browserId, pageCount, currentUrl, currentTitle, launchedAt, lastActivityAt}. Use this to discover which browserIds are currently active before calling browser_session_close.",inputSchema:{type:"object",properties:{agentId:{type:"string",description:"Agent identifier (optional)."}},required:[]},async execute(e){try{const{agentId:t}=u(e),r=b.listSessions(t);return{ok:!0,agentId:t,sessions:r.map(n=>({browserId:n.browserId,pageCount:n.pageCount,activePageIndex:n.activePageIndex,currentUrl:n.currentUrl,currentTitle:n.currentTitle,launchedAt:n.launchedAt,lastActivityAt:n.lastActivityAt,wsUrl:_?_.getUrl(t,n.browserId):void 0}))}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_session_close",exposedName:"browser_session_close",description:"Close a specific browser session by browserId for the current agent. Returns the step archive of that session. Use browser_list_sessions to enumerate active browserIds. For the default session, you can also call browser_close (alias for browser_session_close with browserId='default').",inputSchema:{type:"object",properties:{browserId:{type:"string",description:"Browser instance ID to close (default 'default'). Required for non-default sessions."},agentId:{type:"string",description:"Agent identifier (optional)."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),n=b.get(t,r);if(!n)return{ok:!1,error:`Browser session not launched for ${t}/${r}. Call browser_launch first.`};const s=n.archive.toJSON();return await b.close(t,r),{ok:!0,browserId:r,archive:s}}catch(t){return p(t)}}}].map(e=>({...e,category:"browser"}))}export{oe as createBuiltInBrowserTools};
1
+ import{resolveSsrfConfig as E,validateUrlWithDns as M}from"./ssrf-guard.js";import{locateElement as q}from"./element-locator.js";import{serializeSnapshot as P,buildRefMap as j}from"./snapshot-serializer.js";import{DEFAULT_BROWSER_ID as k}from"./types.js";const X=3e4,$=1e4;function oe(v){const{pool:b,wsServer:_}=v,U=v.agentId,N=v.scopeKey,D=E({perAgent:v.ssrfConfig,pool:b.getSsrfConfig()});function u(e){const r=(typeof e.agentId=="string"&&e.agentId.trim()?e.agentId.trim():void 0)??U;if(!r)throw new Error("agentId is required: pass via createBuiltInBrowserTools({agentId}) or tool args.agentId");const n=typeof e.browserId=="string"&&e.browserId.trim()?e.browserId.trim():k,s=typeof e.title=="string"&&e.title.trim()?e.title.trim():void 0,o=N??`agent:${r}`;return{agentId:r,browserId:n,title:s,scopeKey:o}}function B(e,t){const r=b.get(e,t);if(!r)throw new Error(`Browser session not launched for ${e}/${t}. Call browser_launch first.`);if(r.humanTakeover)throw new Error(`Human takeover active for ${e}/${t}. Release takeover before calling browser tools.`);return b.touchActivity(e,t),r}function m(e,t){return{session:B(e,t),page:b.getActivePage(e,t)}}function p(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}function I(e,t){if(e)try{e.archive.record(t)}catch{}}function x(e){const t={};for(const[r,n]of Object.entries(e))n!==void 0&&(t[r]=n);return t}const S=new Map;function A(e,t){return`${e}:${t}`}function C(e,t,r){return S.get(A(e,t))?.get(r)}function R(e,t,r){S.set(A(e,t),j(r))}return v.pool.onSessionClose((e,t)=>{S.delete(A(e,t))}),[{kind:"builtin",toolName:"browser_launch",exposedName:"browser_launch",description:"Launch a headless browser session for the current agent. Returns wsUrl for live JPEG frame streaming (open in browser to watch the agent operate). Pass browserId to start a separate browser instance (independent cookies/cache/storage). Default browserId is 'default'. Must be called before any other browser_* tool. The session is automatically reclaimed after 10 minutes of inactivity. title is required and should briefly describe the intent of this browser session (e.g. '\u641C\u7D22\u7ADE\u54C1\u4EF7\u683C', '\u767B\u5F55\u7BA1\u7406\u540E\u53F0').",inputSchema:{type:"object",properties:{agentId:{type:"string",description:"Agent identifier (optional if configured at factory time). Used to isolate browser sessions across agents."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default'). Same agent can have multiple browserIds (each = independent chromium process)."},title:{type:"string",description:"Brief human-readable title describing the intent of this browser session (e.g. '\u641C\u7D22\u7ADE\u54C1\u4EF7\u683C', '\u767B\u5F55\u7BA1\u7406\u540E\u53F0'). Required \u2014 used as tab label in dashboard."}},required:["title"]},async execute(e){try{const{agentId:t,browserId:r,title:n,scopeKey:s}=u(e),o=await b.getOrLaunch(t,r,n,s),l=o.pages[o.activePageIndex].viewportSize(),c={ok:!0,agentId:t,browserId:o.browserId,title:o.title,viewport:{width:l?.width??0,height:l?.height??0}};return _&&(c.wsUrl=_.getUrl(t,o.browserId)),c}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_navigate",exposedName:"browser_navigate",description:"Navigate the active page to a URL. Waits for DOMContentLoaded (30s timeout). Access to private/loopback addresses is allowed by default (configurable).",inputSchema:{type:"object",properties:{url:{type:"string",description:"Target URL (http/https only). Private IP ranges are allowed by default, can be disabled via ssrfConfig."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:["url"]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.url=="string"?e.url:"";if(!o)return{ok:!1,error:"url is required"};const i=await M(o,D),l=s.url(),c=Date.now();await s.goto(i,{waitUntil:"domcontentloaded",timeout:X});const a=s.url();try{await n.listenerManager.reattach(s)}catch{}let d="";try{d=await s.title()}catch{}return I(n,{tool:"browser_navigate",args:x({url:i,browserId:r}),beforeUrl:l,afterUrl:a,durationMs:Date.now()-c}),{ok:!0,url:i,finalUrl:a,title:d,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_snapshot",exposedName:"browser_snapshot",description:"Capture the active page's accessibility tree as YAML (Playwright ariaSnapshot mode=ai). Interactive elements get [ref=eXX] markers \u2014 pass the eXX string to browser_click / browser_type / browser_select. Re-snapshot after navigation (refs are invalidated on page change). Output truncated to maxChars (default 16000).",inputSchema:{type:"object",properties:{maxChars:{type:"number",description:"Max chars to return (default 16000)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{page:n}=m(t,r),s=typeof e.maxChars=="number"&&e.maxChars>0?Math.floor(e.maxChars):void 0,o=await P(n,{maxChars:s});R(t,r,o);let i="";try{i=await n.title()}catch{}return{ok:!0,snapshot:o,url:n.url(),title:i,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_click",exposedName:"browser_click",description:"Click an element identified by ref (from browser_snapshot), text (getByText), role+name (getByRole), or CSS selector. ref is preferred, but text/role are more stable on SPA pages where refs invalidate frequently. If ref fails, the system auto-falls back to the cached role+name from the last snapshot and retries the snapshot once. 10s timeout.",inputSchema:{type:"object",properties:{ref:{type:"string",description:"Element ref from browser_snapshot, e.g. 'e5' (preferred)."},text:{type:"string",description:"Locate element by visible text (getByText). More stable than ref on SPA pages, e.g. 'javaok'."},role:{type:"string",description:"Locate element by ARIA role (e.g. button, link, textbox, listitem). Use with 'name'."},name:{type:"string",description:"Accessible name to combine with 'role' (e.g. role=button + name='Submit')."},selector:{type:"string",description:"CSS selector (subset: tag/.class/#id/[attr]/descendant/>)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.ref=="string"&&e.ref.trim()?e.ref.trim():void 0,i=typeof e.text=="string"&&e.text.trim()?e.text.trim():void 0,l=typeof e.role=="string"&&e.role.trim()?e.role.trim():void 0,c=typeof e.name=="string"&&e.name?e.name:void 0,a=typeof e.selector=="string"?e.selector:void 0;if(o===void 0&&i===void 0&&l===void 0&&!a)return{ok:!1,error:"Either 'ref', 'text', 'role', or 'selector' is required for browser_click"};const d=o!==void 0?C(t,r,o):void 0,h=await q(s,{ref:o,text:i,role:l,name:c,selector:a,refFallback:d}),w=s.url(),y=Date.now();await h.click({timeout:$});const f=s.url(),g=o!==void 0?`ref=${o}`:i!==void 0?`text=${i}`:l!==void 0?`role=${l}`:`selector=${a}`;return I(n,{tool:"browser_click",args:x({ref:o,text:i,role:l,name:c,selector:a,browserId:r}),beforeUrl:w,afterUrl:f,durationMs:Date.now()-y}),{ok:!0,clicked:g,url:f,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_type",exposedName:"browser_type",description:"Type text into an input identified by ref, role+name (getByRole), or CSS selector. Note: 'text' param is the text to type (not for locating); use 'role'+'name' to locate the input. clear=true (default) clears the field first. delay adds per-keystroke delay (ms).",inputSchema:{type:"object",properties:{ref:{type:"string",description:"Element ref from browser_snapshot, e.g. 'e5'."},role:{type:"string",description:"Locate input by ARIA role (e.g. textbox, searchbox). Use with 'name'."},name:{type:"string",description:"Accessible name to combine with 'role'."},selector:{type:"string",description:"CSS selector subset."},text:{type:"string",description:"Text to type (required)."},clear:{type:"boolean",description:"Clear field before typing (default true)."},delay:{type:"number",description:"Per-keystroke delay in ms (default 0)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:["text"]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.ref=="string"&&e.ref.trim()?e.ref.trim():void 0,i=typeof e.role=="string"&&e.role.trim()?e.role.trim():void 0,l=typeof e.name=="string"&&e.name?e.name:void 0,c=typeof e.selector=="string"?e.selector:void 0,a=typeof e.text=="string"?e.text:"";if(!a)return{ok:!1,error:"text is required for browser_type"};if(o===void 0&&i===void 0&&!c)return{ok:!1,error:"Either 'ref', 'role', or 'selector' is required for browser_type"};const d=e.clear!==!1,h=typeof e.delay=="number"&&e.delay>=0?e.delay:0,w=o!==void 0?C(t,r,o):void 0,y=await q(s,{ref:o,role:i,name:l,selector:c,refFallback:w}),f=s.url(),g=Date.now();d&&await y.fill(""),await y.type(a,{delay:h});const T=s.url();return I(n,{tool:"browser_type",args:x({ref:o,role:i,name:l,selector:c,text:a,clear:d,delay:h,browserId:r}),beforeUrl:f,afterUrl:T,durationMs:Date.now()-g}),{ok:!0,typed:a.length,url:T,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_select",exposedName:"browser_select",description:"Select an option in a <select> element identified by ref, text (getByText), role+name (getByRole), or CSS selector. value is the option value (string).",inputSchema:{type:"object",properties:{ref:{type:"string",description:"Element ref from browser_snapshot, e.g. 'e5'."},text:{type:"string",description:"Locate element by visible text (getByText)."},role:{type:"string",description:"Locate element by ARIA role (e.g. combobox, listbox). Use with 'name'."},name:{type:"string",description:"Accessible name to combine with 'role'."},selector:{type:"string",description:"CSS selector subset."},value:{type:"string",description:"Option value to select (required)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:["value"]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.ref=="string"&&e.ref.trim()?e.ref.trim():void 0,i=typeof e.text=="string"&&e.text.trim()?e.text.trim():void 0,l=typeof e.role=="string"&&e.role.trim()?e.role.trim():void 0,c=typeof e.name=="string"&&e.name?e.name:void 0,a=typeof e.selector=="string"?e.selector:void 0,d=typeof e.value=="string"?e.value:e.value!==void 0&&e.value!==null?String(e.value):"";if(!d)return{ok:!1,error:"value is required for browser_select"};if(o===void 0&&i===void 0&&l===void 0&&!a)return{ok:!1,error:"Either 'ref', 'text', 'role', or 'selector' is required for browser_select"};const h=o!==void 0?C(t,r,o):void 0,w=await q(s,{ref:o,text:i,role:l,name:c,selector:a,refFallback:h}),y=s.url(),f=Date.now();await w.selectOption(d);const g=s.url();return I(n,{tool:"browser_select",args:x({ref:o,text:i,role:l,name:c,selector:a,value:d,browserId:r}),beforeUrl:y,afterUrl:g,durationMs:Date.now()-f}),{ok:!0,selected:d,url:g,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_press_key",exposedName:"browser_press_key",description:"Press a keyboard key on the active page. Examples: 'Enter', 'Escape', 'Tab', 'Control+a', 'ArrowDown'. See Playwright key names for full list.",inputSchema:{type:"object",properties:{key:{type:"string",description:"Key or chord (e.g. 'Enter', 'Control+a')."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:["key"]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.key=="string"?e.key:"";if(!o)return{ok:!1,error:"key is required for browser_press_key"};const i=s.url(),l=Date.now();await s.keyboard.press(o);const c=s.url();return I(n,{tool:"browser_press_key",args:x({key:o,browserId:r}),beforeUrl:i,afterUrl:c,durationMs:Date.now()-l}),{ok:!0,key:o,url:c,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_scroll",exposedName:"browser_scroll",description:"Scroll the active page. Provide x/y for absolute scroll-to, OR deltaX/deltaY for relative wheel scroll. If both provided, x/y wins.",inputSchema:{type:"object",properties:{x:{type:"number",description:"Absolute scrollX (window.scrollTo)."},y:{type:"number",description:"Absolute scrollY (window.scrollTo)."},deltaX:{type:"number",description:"Relative wheel delta X."},deltaY:{type:"number",description:"Relative wheel delta Y."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{session:n,page:s}=m(t,r),o=typeof e.x=="number"&&Number.isFinite(e.x)||typeof e.y=="number"&&Number.isFinite(e.y),i=typeof e.deltaX=="number"&&Number.isFinite(e.deltaX)||typeof e.deltaY=="number"&&Number.isFinite(e.deltaY);if(!o&&!i)return{ok:!1,error:"Provide x/y (absolute) or deltaX/deltaY (relative) for browser_scroll"};const l=s.url(),c=Date.now();let a=0,d=0;if(o){const w=typeof e.x=="number"?e.x:0,y=typeof e.y=="number"?e.y:0;await s.evaluate(([g,T])=>globalThis.scrollTo(g,T),[w,y]);const f=await s.evaluate(()=>globalThis);a=f.scrollX,d=f.scrollY}else{const w=typeof e.deltaX=="number"?e.deltaX:0,y=typeof e.deltaY=="number"?e.deltaY:0;await s.mouse.wheel(w,y);const f=await s.evaluate(()=>globalThis);a=f.scrollX,d=f.scrollY}const h=s.url();return I(n,{tool:"browser_scroll",args:x({x:e.x,y:e.y,deltaX:e.deltaX,deltaY:e.deltaY,browserId:r}),beforeUrl:l,afterUrl:h,durationMs:Date.now()-c}),{ok:!0,scrollX:a,scrollY:d,browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_screenshot",exposedName:"browser_screenshot",description:"Capture a single screenshot of the active page. The screenshot is returned as an image attachment (inlined into the conversation so you can see it; requires a model with image input). fullPage=true captures the entire scrollable page (may be large).",inputSchema:{type:"object",properties:{fullPage:{type:"boolean",description:"Capture entire scrollable page (default false)."},format:{type:"string",enum:["jpeg","png"],description:"Image format (default 'jpeg')."},quality:{type:"number",description:"JPEG quality 0-100 (default 80, ignored for png)."},agentId:{type:"string",description:"Agent identifier (optional)."},browserId:{type:"string",description:"Browser instance ID (optional, default 'default')."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),{page:n}=m(t,r),s=e.fullPage===!0,o=e.format==="png"||e.format==="jpeg"?e.format:"jpeg",i=typeof e.quality=="number"&&e.quality>=0&&e.quality<=100?e.quality:80,c=(await n.screenshot({fullPage:s,type:o,quality:o==="jpeg"?i:void 0})).toString("base64"),a=n.viewportSize();return{ok:!0,attachments:[{type:"image",name:`screenshot.${o}`,mediaType:`image/${o}`,base64Data:c}],width:a?.width??0,height:a?.height??0,url:n.url(),browserId:r}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_close",exposedName:"browser_close",description:"Close the default browser session (browserId='default') for the current agent. Returns the step archive (recent operations). To close a non-default browser session, use browser_session_close({browserId}).",inputSchema:{type:"object",properties:{agentId:{type:"string",description:"Agent identifier (optional)."}},required:[]},async execute(e){try{const{agentId:t}=u(e),r=b.get(t,k);if(!r)return{ok:!1,error:`Browser session not launched for ${t}/${k}. Call browser_launch first.`};const n=r.archive.toJSON();return await b.close(t,k),{ok:!0,browserId:k,archive:n}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_list_sessions",exposedName:"browser_list_sessions",description:"List all browser sessions for the current agent. Returns an array of {browserId, pageCount, currentUrl, currentTitle, launchedAt, lastActivityAt}. Use this to discover which browserIds are currently active before calling browser_session_close.",inputSchema:{type:"object",properties:{agentId:{type:"string",description:"Agent identifier (optional)."}},required:[]},async execute(e){try{const{agentId:t}=u(e),r=b.listSessions(t);return{ok:!0,agentId:t,sessions:r.map(n=>({browserId:n.browserId,pageCount:n.pageCount,activePageIndex:n.activePageIndex,currentUrl:n.currentUrl,currentTitle:n.currentTitle,launchedAt:n.launchedAt,lastActivityAt:n.lastActivityAt,wsUrl:_?_.getUrl(t,n.browserId):void 0}))}}catch(t){return p(t)}}},{kind:"builtin",toolName:"browser_session_close",exposedName:"browser_session_close",description:"Close a specific browser session by browserId for the current agent. Returns the step archive of that session. Use browser_list_sessions to enumerate active browserIds. For the default session, you can also call browser_close (alias for browser_session_close with browserId='default').",inputSchema:{type:"object",properties:{browserId:{type:"string",description:"Browser instance ID to close (default 'default'). Required for non-default sessions."},agentId:{type:"string",description:"Agent identifier (optional)."}},required:[]},async execute(e){try{const{agentId:t,browserId:r}=u(e),n=b.get(t,r);if(!n)return{ok:!1,error:`Browser session not launched for ${t}/${r}. Call browser_launch first.`};const s=n.archive.toJSON();return await b.close(t,r),{ok:!0,browserId:r,archive:s}}catch(t){return p(t)}}}].map(e=>({...e,category:"browser"}))}export{oe as createBuiltInBrowserTools};
2
2
 
@@ -1,2 +1,2 @@
1
- import{Router as o}from"express";import{validateToken as s}from"../middleware/auth.js";import{collectSystemMetrics as m}from"../services/system-metrics.js";import{createLogger as c}from"../utils/logger.js";const i=c("system-metrics-route"),a=o();a.get("/system-metrics",s,async(n,t)=>{try{t.json(await m())}catch(r){const e=r instanceof Error?r:new Error(String(r));i.error("Failed to collect system metrics:",e.message),t.status(500).json({error:e.message})}});export{a as systemMetricsRouter};
1
+ import{Router as a}from"express";import{validateToken as c}from"../middleware/auth.js";import{collectProcessDetail as m}from"../services/process-detail.js";import{clampProcessTopLimit as l,collectProcessTop as u,normalizeProcessTopResource as p}from"../services/process-top.js";import{collectSystemMetrics as g}from"../services/system-metrics.js";import{createLogger as y}from"../utils/logger.js";const i=y("system-metrics-route"),n=a();function f(t){const r=Number(t);return!Number.isInteger(r)||r<1||r>4194304?null:r}n.get("/system-metrics",c,async(t,r)=>{try{r.json(await g())}catch(o){const e=o instanceof Error?o:new Error(String(o));i.error("Failed to collect system metrics:",e.message),r.status(500).json({error:e.message})}}),n.get("/process-top",c,async(t,r)=>{const o=p(t.query.resource);if(!o){r.status(400).json({error:"resource must be one of cpu|memory|storage|network"});return}try{r.json(await u(o,l(t.query.limit)))}catch(e){const s=e instanceof Error?e:new Error(String(e));i.error("Failed to collect process top:",s.message),r.status(500).json({error:s.message})}}),n.get("/process-detail",c,async(t,r)=>{const o=f(t.query.pid);if(o===null){r.status(400).json({error:"pid must be a positive integer"});return}try{r.json(await m(o))}catch(e){const s=e instanceof Error?e:new Error(String(e));i.error("Failed to collect process detail:",s.message),r.status(500).json({error:s.message})}});export{n as systemMetricsRouter};
2
2