aws-runtime-bridge 1.9.98 → 1.9.100

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 (120) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +7 -1
  2. package/dist/adapter/AcodeSdkAdapter.js +5 -5
  3. package/dist/adapter/ClaudeSdkAdapter.d.ts +4 -0
  4. package/dist/adapter/ClaudeSdkAdapter.js +2 -2
  5. package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
  6. package/dist/adapter/CodexSdkAdapter.js +3 -3
  7. package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
  8. package/dist/adapter/OpencodeSdkAdapter.js +2 -2
  9. package/dist/adapter/idle-poll-loop.d.ts +4 -1
  10. package/dist/adapter/idle-poll-loop.js +1 -1
  11. package/dist/adapter/types.d.ts +4 -2
  12. package/dist/browser/browser-pool.d.ts +73 -0
  13. package/dist/browser/browser-pool.js +2 -0
  14. package/dist/browser/browser-profile-store.d.ts +28 -0
  15. package/dist/browser/browser-profile-store.js +2 -0
  16. package/dist/browser/built-in-browser-tools.d.ts +27 -0
  17. package/dist/browser/built-in-browser-tools.js +2 -0
  18. package/dist/browser/element-locator.d.ts +24 -0
  19. package/dist/browser/element-locator.js +2 -0
  20. package/dist/browser/element-picker.d.ts +17 -0
  21. package/dist/browser/element-picker.js +2 -0
  22. package/dist/browser/input-dispatcher.d.ts +34 -0
  23. package/dist/browser/input-dispatcher.js +2 -0
  24. package/dist/browser/listener-store.d.ts +32 -0
  25. package/dist/browser/listener-store.js +2 -0
  26. package/dist/browser/page-listener-manager.d.ts +106 -0
  27. package/dist/browser/page-listener-manager.js +307 -0
  28. package/dist/browser/page-listener-types.d.ts +90 -0
  29. package/dist/browser/page-listener-types.js +1 -0
  30. package/dist/browser/screencast-manager.d.ts +42 -0
  31. package/dist/browser/screencast-manager.js +2 -0
  32. package/dist/browser/snapshot-serializer.d.ts +15 -0
  33. package/dist/browser/snapshot-serializer.js +5 -0
  34. package/dist/browser/ssrf-guard.d.ts +15 -0
  35. package/dist/browser/ssrf-guard.js +2 -0
  36. package/dist/browser/stealth.d.ts +7 -0
  37. package/dist/browser/stealth.js +173 -0
  38. package/dist/browser/step-archive.d.ts +52 -0
  39. package/dist/browser/step-archive.js +2 -0
  40. package/dist/browser/types.d.ts +192 -0
  41. package/dist/browser/types.js +2 -0
  42. package/dist/browser/ws-server.d.ts +67 -0
  43. package/dist/browser/ws-server.js +2 -0
  44. package/dist/index.js +1 -1
  45. package/dist/middleware/auth.d.ts +2 -0
  46. package/dist/middleware/auth.js +1 -1
  47. package/dist/remote-desktop/computer-control.d.ts +30 -0
  48. package/dist/remote-desktop/computer-control.js +2 -0
  49. package/dist/remote-desktop/coords.d.ts +13 -0
  50. package/dist/remote-desktop/coords.js +2 -0
  51. package/dist/remote-desktop/frame-backpressure.d.ts +7 -0
  52. package/dist/remote-desktop/frame-backpressure.js +2 -0
  53. package/dist/remote-desktop/index.d.ts +7 -0
  54. package/dist/remote-desktop/index.js +4 -0
  55. package/dist/remote-desktop/input-backends/interface.d.ts +17 -0
  56. package/dist/remote-desktop/input-backends/interface.js +1 -0
  57. package/dist/remote-desktop/input-backends/key-map.d.ts +2 -0
  58. package/dist/remote-desktop/input-backends/key-map.js +2 -0
  59. package/dist/remote-desktop/input-dispatcher.d.ts +11 -0
  60. package/dist/remote-desktop/input-dispatcher.js +2 -0
  61. package/dist/remote-desktop/permission-manager.d.ts +7 -0
  62. package/dist/remote-desktop/permission-manager.js +2 -0
  63. package/dist/remote-desktop/screen-capture.d.ts +27 -0
  64. package/dist/remote-desktop/screen-capture.js +2 -0
  65. package/dist/remote-desktop/session-manager.d.ts +59 -0
  66. package/dist/remote-desktop/session-manager.js +2 -0
  67. package/dist/remote-desktop/system-backend.d.ts +65 -0
  68. package/dist/remote-desktop/system-backend.js +5 -0
  69. package/dist/remote-desktop/types.d.ts +68 -0
  70. package/dist/remote-desktop/types.js +1 -0
  71. package/dist/remote-desktop/ui-automation.d.ts +48 -0
  72. package/dist/remote-desktop/ui-automation.js +31 -0
  73. package/dist/remote-desktop/win32-api.d.ts +29 -0
  74. package/dist/remote-desktop/win32-api.js +2 -0
  75. package/dist/routes/background-tasks.d.ts +2 -0
  76. package/dist/routes/background-tasks.js +2 -0
  77. package/dist/routes/browser-listeners.d.ts +2 -0
  78. package/dist/routes/browser-listeners.js +2 -0
  79. package/dist/routes/browser-sessions.d.ts +2 -0
  80. package/dist/routes/browser-sessions.js +2 -0
  81. package/dist/routes/pty.js +3 -3
  82. package/dist/routes/terminal.js +30 -30
  83. package/dist/services/agent-pty-manager.d.ts +22 -0
  84. package/dist/services/agent-pty-manager.js +5 -0
  85. package/dist/services/browser-session-manager.d.ts +55 -0
  86. package/dist/services/browser-session-manager.js +12 -0
  87. package/dist/services/cli-commands.d.ts +4 -0
  88. package/dist/services/cli-commands.js +5 -5
  89. package/package/acode/dist/await-complete-tool.d.ts +17 -0
  90. package/package/acode/dist/await-complete-tool.js +21 -0
  91. package/package/acode/dist/background-command-manager.d.ts +148 -0
  92. package/package/acode/dist/background-command-manager.js +8 -0
  93. package/package/acode/dist/background-command-store.d.ts +46 -0
  94. package/package/acode/dist/background-command-store.js +2 -0
  95. package/package/acode/dist/background-command-tools.d.ts +5 -0
  96. package/package/acode/dist/background-command-tools.js +18 -0
  97. package/package/acode/dist/background-output-ringbuffer.d.ts +23 -0
  98. package/package/acode/dist/background-output-ringbuffer.js +3 -0
  99. package/package/acode/dist/built-in-file-tools.d.ts +8 -1
  100. package/package/acode/dist/built-in-file-tools.js +2 -2
  101. package/package/acode/dist/compaction.js +6 -6
  102. package/package/acode/dist/index.d.ts +1 -0
  103. package/package/acode/dist/index.js +1 -1
  104. package/package/acode/dist/runtime.d.ts +6 -0
  105. package/package/acode/dist/runtime.js +27 -27
  106. package/package/acode/dist/sub-agent-tools.d.ts +0 -1
  107. package/package/acode/dist/sub-agent-tools.js +11 -28
  108. package/package/acode/dist/terminal-tool.d.ts +7 -0
  109. package/package/acode/dist/terminal-tool.js +2 -0
  110. package/package/acode/dist/terminal-types.d.ts +38 -0
  111. package/package/acode/dist/terminal-types.js +1 -0
  112. package/package/acode/dist/types.d.ts +10 -1
  113. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +3 -1
  114. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  115. package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -0
  116. package/package/aws-client-agent-mcp/dist/logger.js +1 -1
  117. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +8 -0
  118. package/package/aws-client-agent-mcp/dist/mcp-server.js +30 -19
  119. package/package/aws-client-agent-mcp/dist/types.d.ts +25 -0
  120. package/package.json +6 -2
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { EventEmitter } from "node:events";
3
- import type { SubAgentManager } from "@agentswork/acode";
3
+ import type { SubAgentManager, TerminalManager } from "@agentswork/acode";
4
4
  import type { AdapterSessionConfig, BaseProviderAdapter, ConversationMessage, RuntimeCapabilities, SessionStatus } from "./types.js";
5
5
  type ACodeEvent = {
6
6
  type: string;
@@ -32,12 +32,16 @@ type ACodeRuntimeConstructor = new (config: {
32
32
  memory?: string;
33
33
  env?: Record<string, string>;
34
34
  subAgentManager?: SubAgentManager;
35
+
36
+ terminalManager?: TerminalManager;
35
37
  onFileChange?: (record: {
36
38
  filePath: string;
37
39
  operation: 'CREATE' | 'UPDATE' | 'DELETE';
38
40
  beforeContent: string | null;
39
41
  afterContent: string | null;
40
42
  }) => void | Promise<void>;
43
+
44
+ extraBuiltInTools?: unknown[];
41
45
  }) => ACodeRuntimeInstance;
42
46
  export declare function toAcodeEsmImportSpecifier(modulePath: string): string;
43
47
 
@@ -46,6 +50,8 @@ export declare class AcodeSdkAdapter extends EventEmitter implements BaseProvide
46
50
  readonly providerId = "acode";
47
51
  readonly displayName = "ACode";
48
52
  private sessions;
53
+
54
+ private listenerWakeHooks;
49
55
  private runtimeConstructor?;
50
56
  startSession(sessionId: string, config: AdapterSessionConfig): Promise<void>;
51
57
  sendMessage(sessionId: string, message: string): Promise<void>;
@@ -1,11 +1,11 @@
1
- import{EventEmitter as q}from"node:events";import L from"node:path";import B from"node:fs/promises";import{pathToFileURL as W}from"node:url";import{v4 as O}from"uuid";import{getAcodeConfigFile as D,getAcodeSkillsDir as N,getRuntimeHomeDir as K}from"../config.js";import{getReleasedAcodeEntryPath as Q}from"../services/acode-package.js";import{getInstanceAiConfigDebugLogger as k}from"../utils/instance-ai-config-debug-logger.js";import{redactForLog as $}from"../services/instance-ai-config-service.js";import{subAgentManager as j}from"../services/sub-agent-manager-instance.js";import{resolveAcodeProviderConfig as G}from"./instance-ai-config-resolver.js";import{recordAgentFileChange as H}from"../services/workspaceTaskChangeWatcher.js";import{isMessagePollingIdleCommand as w,isPollMessageToolDescriptor as z}from"./acode-tool-names.js";import{IdlePollLoop as J}from"./idle-poll-loop.js";import{getCanonicalMcpDetail as E,getToolActionInfo as Y}from"./types.js";const X=process.env.ACODE_COMPACTION_DEBUG==="1";function l(...n){X&&console.log(...n)}const I=["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(" "),V=5e3,Z=4e4,tt=5*6e4,et=250,ot=2e3,st=12e4,M=3e3,it="\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5F53\u524D\u5DE5\u4F5C\u5DF2\u5B8C\u6210\u6216\u8FD0\u884C\u65F6\u5DF2\u8FDB\u5165\u7A7A\u95F2\u72B6\u6001\u3002\u8BF7\u7ACB\u5373\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 at(){return L.resolve(Q())}function nt(n){return W(L.resolve(n)).href}const R=128e3,P={"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 rt(n){if(!n)return R;const t=n.toLowerCase().trim();if(P[t])return P[t].contextLimit;const e=Object.keys(P).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?P[e[0]].contextLimit:R}const U=4096;function ut(n){if(!n)return U;const t=n.toLowerCase().trim();if(P[t])return P[t].maxOutput;const e=Object.keys(P).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?P[e[0]].maxOutput:U}function lt(n){if(!n||typeof n!="object")return;const t=n,e=y(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),o=y(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(!(e===0&&o===0))return{inputTokens:e,outputTokens:o}}function y(...n){for(const t of n){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function F(n){return y(n.estimatedContextTokens,n.contextTokens,n.context_tokens,n.contextUsedTokens,n.context_used_tokens)}function dt(n){return n==="stderr"||n==="mixed"?n:"stdout"}function ct(n){if(!n||typeof n!="object"||Array.isArray(n))return;const t={};for(const[e,o]of Object.entries(n))typeof o=="string"&&(t[e]=o);return Object.keys(t).length>0?t:void 0}function mt(n){return n.failed===!0}function v(n,t,e){if(!n)return e?`${t}/${e}`:t;const o=`${t}__`;return n.startsWith(o)?E(`${t}__${n.slice(o.length)}`):E(n.replace("/","__"))}function pt(n){return n==="read_file"||n==="edit_file"||n==="write_file"||n==="bash"}function gt(n){const t=ft(n);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof n=="string"&&n.trim().length>0}function ft(n){if(n&&typeof n=="object"&&!Array.isArray(n))return n;if(!(typeof n!="string"||!n.trim()))try{const t=JSON.parse(n);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class $t extends q{constructor(){super(...arguments),this.providerId="acode",this.displayName="ACode",this.sessions=new Map}async startSession(t,e){const o=K(),s=e.mcpConfigPath||D(o),{resolved:r,configContextLimit:i}=await this.resolveAcodeProvider(e,s),a=r.model,u=i??rt(a),c=ut(a),p={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:u,maxOutput:c}};this.sessions.set(t,{adapterSession:p,config:e,runtime:await this.createRuntime(t,a,e,o),autoPollActive:!1}),this.emit("status-change",t,"starting");const d=this.sessions.get(t);if(!d)throw new Error("ACode session was not initialized");try{await d.runtime.start(),p.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:d.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(m){p.status="error",this.emitRuntimeErrorEvent(t,m),this.emit("status-change",t,"error");const g=this.sessions.get(t);throw g?.capabilitiesFallbackTimer&&clearTimeout(g.capabilitiesFallbackTimer),this.sessions.delete(t),m}}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),r=s.adapterSession.status;l(`[ACode] Previous status: ${r}`),this.cancelScheduledAutoPoll(s),s.failedTurnRecoveryScheduled=!1,s.idlePollLoop?.stop();const i={id:O(),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: ${r} \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 u=Date.now()-a;this.cancelSubmitTimeoutDetection(s),l(`[ACode] \u2705 runtime.submit() completed in ${u}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 u=Date.now()-o;console.error(`[ACode] \u274C sendMessage FAILED after ${u}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},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);e&&(this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),await e.runtime.stop(),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}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}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&&w(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 B.readFile(t,"utf-8"),o=JSON.parse(e),r=o.provider?.default,i=r?.options,a=y(o.contextLimit),u={},c=r?.models;if(c&&typeof c=="object"){for(const[p,d]of Object.entries(c))if(d&&typeof d=="object"){const m=y(d.contextLimit);m>0&&(u[p.trim()]=m)}}return{...r?.model?{model:r.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...a>0?{contextLimit:a}:{},...Object.keys(u).length>0?{modelContextLimits:u}:{}}}catch(e){const o=e instanceof Error?e.message:String(e);return k().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=k();s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?$(t.instanceAiConfig):null,configPath:e}});const r={...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 u=G(r,i,"acode-default");return s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:$(r),globalConfigModel:i?.model??null,resolvedModel:u.model,resolvedBaseURL:u.baseURL??null,resolvedApiKey:u.apiKey?"[set]":null,configContextLimit:a,resolvedSource:u.source}}),{resolved:u,configPath:e,perSessionModel:o,configContextLimit:a}}async createRuntime(t,e,o,s){const r=await this.loadRuntimeConstructor(),i=o.mcpConfigPath||D(s),a=new r({sessionId:t,agentId:o.agentId,workingDirectory:o.workingDirectory,configPath:i,skillsDir:N(s),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:j,...o.subAgentModel?{subAgentModel:o.subAgentModel}:{},...o.subAgentEffort?{subAgentEffort:o.subAgentEffort}:{},...o.instanceAiConfig?.effort?{effort:o.instanceAiConfig.effort}:{},onFileChange:c=>H(c)});return k().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:i}}),a.on("event",c=>this.forwardAcodeEvent(c)),a}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=at(),e=await import(nt(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 r=this.sessions.get(t);r&&(this.cancelSubmitTimeoutDetection(r),this.emitRuntimeError(t,s,{recover:!0}))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(t.type==="assistant_delta"){const o=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:O(),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:dt(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==="ai_request"){const o=F(t.data);let s;if(o>0){const a=e.adapterSession.totalUsage.inputTokens;a>0?e.adapterSession.totalUsage.inputTokens=Math.min(o,Math.floor(a*1.5)):e.adapterSession.totalUsage.inputTokens=o,s={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const i={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};s&&(i.usage=s),this.emit("status-change",t.sessionId,e.adapterSession.status,i),this.startDataFlowWatchdog(t.sessionId,e),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:ct(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=lt(t.data.usage);if(o){const r=e.adapterSession.totalUsage.inputTokens;r>0&&o.inputTokens<Math.floor(r*.2)||(e.adapterSession.totalUsage.inputTokens=o.inputTokens,e.adapterSession.totalUsage.outputTokens=o.outputTokens)}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}`),mt(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}),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 h=t.data.tools;h.some(f=>z(f))||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 T=Array.isArray(t.data.servers)?t.data.servers:[],_=h.map(f=>({name:String(f.name??""),source:String(f.source??""),description:String(f.description??"")})).filter(f=>f.name),S={kind:"mcp",mcpServers:T,mcpTools:_};e.cachedMcpCapabilities=S,e.lastMcpCapabilities=S,e.lastCombinedCapabilities={kind:"combined",mcpServers:T,mcpTools:_,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},l(`[cap-diag] MCP capabilities cached: ${T.length} servers, ${_.length} tools`,{sessionId:t.sessionId,servers:T,toolNames:_.map(f=>f.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const f=e.cachedMcpCapabilities;if(!f)return;const b={...f,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:b,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(b)}),l(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${M}ms)`,{sessionId:t.sessionId,mcpServers:f.mcpServers,mcpToolsCount:f.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},M);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",r=typeof t.data.tool=="string"?t.data.tool:"",i=s&&r?`${s}__${r}`:r||s,a=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,u=Y(i,a);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,u.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const c=pt(u.actionType)?u.actionDetail||v(void 0,s,r):v(u.actionDetail,s,r),p=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,d=a?JSON.stringify(a,null,2):void 0,m={toolName:c,rawToolName:i,actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:c,...d?{actionInput:d}:{},...a?{toolInput:a}:{},...p?{toolUseId:p,actionId:p}:{},metadata:{mcpServer:s}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...m,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const h=u.actionType==="idle"&&!gt(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=h,this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const C=u.actionType==="idle";this.emit("status-change",t.sessionId,h,C||h==="thinking"?void 0:m);return}const g=u.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=g,g==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...m}),this.emitProviderEvent(t,"tool_use_start",m),this.emit("status-change",t.sessionId,g,m);return}if(t.type==="skill_status"){const s=(Array.isArray(t.data.skills)?t.data.skills:[]).map(d=>({name:String(d.name??""),description:typeof d.description=="string"?d.description:void 0,directory:typeof d.directory=="string"?d.directory:void 0})).filter(d=>d.name),r=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,a=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(d=>{const m=Array.isArray(d.skills)?d.skills:[];return{dir:typeof d.dir=="string"?d.dir:"",exists:d.exists===!0,skills:m.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(d=>d.dir),u=e.cachedMcpCapabilities??e.lastMcpCapabilities,c=e.cachedMcpCapabilities!==void 0,p={kind:"combined",mcpServers:u?.mcpServers??[],mcpTools:u?.mcpTools??[],skills:s,skillsDir:r,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)"}: ${(u?.mcpTools??[]).length} MCP tools, ${s.length} skills`,{sessionId:t.sessionId,mcpServers:u?.mcpServers??[],skillsDir:r}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="session_started"){const o=F(t.data),s=y(t.data.contextLimit)||void 0,r=y(t.data.maxOutput)||void 0,i=y(t.data.inputLimit)||void 0,a=y(t.data.compactionThreshold)||void 0;let u=!1;o>0&&(e.adapterSession.totalUsage.inputTokens=o,e.adapterSession.totalUsage.outputTokens=0,u=!0),s!==void 0&&(e.adapterSession.totalUsage.contextLimit=s,u=!0),r!==void 0&&(e.adapterSession.totalUsage.maxOutput=r,u=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,u=!0),a!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=a,u=!0),u&&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,r=s==="start",i=s==="end",a=s==="phase",u=o.parentId,c=o.compactionId;let p,d;if(r){const g=String(o.sizeKB??o.sizeBeforeKB??"?"),h=String(o.messageCount??o.messageCountBefore??"?"),C=o.estimatedTokens,T=o.actualInputTokens?`input=${o.actualInputTokens}`:"",_=o.actualOutputTokens?`output=${o.actualOutputTokens}`:"",S=o.trigger?`, \u89E6\u53D1: ${o.trigger}`:"";p="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",C!==void 0?d=`\u538B\u7F29\u524D: ~${C} tokens, \u6D88\u606F: ${h}\u6761`+(T?`, \u5B9E\u9645 tokens: ${T} ${_}`:"")+S:d=`\u538B\u7F29\u524D: ${g}KB, \u6D88\u606F: ${h}\u6761`+(T?`, \u5B9E\u9645 tokens: ${T} ${_}`:"")+S}else if(a)p=String(o.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),d=String(o.phaseDetail??"");else{const g=o.tokensBefore,h=o.tokensAfter,C=o.freedTokens,T=String(o.sizeBeforeKB??"?"),_=String(o.sizeAfterKB??"?"),S=String(o.freedKB??"?"),f=String(o.strategy??"?"),b=Number(o.prunedToolMessages??0),A=Number(o.summarizedMessages??0);p="\u538B\u7F29\u5B8C\u6210",g!==void 0&&h!==void 0?d=`\u91CA\u653E: ${C??g-h} tokens, ${g} tokens \u2192 ${h} tokens, \u7B56\u7565: ${f}`+(b?`, \u88C1\u526A\u5DE5\u5177: ${b}\u6761`:"")+(A?`, \u6458\u8981\u5316: ${A}\u6761`:""):d=`\u91CA\u653E: ${S}KB, ${T}KB \u2192 ${_}KB, \u7B56\u7565: ${f}`+(b?`, \u88C1\u526A\u5DE5\u5177: ${b}\u6761`:"")+(A?`, \u6458\u8981\u5316: ${A}\u6761`:"")}r&&(e.adapterSession.status="compacting");const m={actionType:"context_compaction",actionLabel:p,actionDetail:d};if(r&&c)m.actionId=c;else if((a||i)&&c)if(m.parentId=c,a){const g=String(o.phase??"unknown");m.actionId=`${c}-phase-${g}`}else m.actionId=`${c}-end`;a&&u&&!m.parentId&&(m.parentId=u),i&&(e.adapterSession.totalUsage.inputTokens=0,e.adapterSession.totalUsage.outputTokens=0,m.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",m),this.emit("status-change",t.sessionId,"compacting",m);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 J({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:o=>w(o),dispatchPollingPrompt:()=>this.submitAutoPollPrompt(e,it,{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 r=(s.autoPollToken??0)+1;s.autoPollToken=r,s.autoPollActive=!0,s.autoPollObservedPollingTool=!1,s.autoPollObservedAssistantText=!1,s.autoPollObservedAnyTool=!1,s.stopAutoPollAfterCurrentTurn=!1,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!==r){l(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${r}, 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=et){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,I,{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.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&&w(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,I,{keepWaitingStatus:!0})},ot)}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,r=!!(o&&w(o))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",r),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 r=s.adapterSession.status,i=Date.now();if(r==="waiting_input"){s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(r==="tool_using"){const c=i-(s.watchdogLastDataFlowTime||i);if(c>=tt){const p=String(s.pendingToolEventData?.rawToolName??"");if(p.endsWith("await_sub_agents")){console.warn(`[ACode] tool_using elapsed ${Math.round(c/1e3)}s but await_sub_agents is running (session: ${t}, tool: ${p}), skipping recovery (sub-agents have their own watchdogs)`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}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.`),this.executeWatchdogRecovery(t,s,o,"tool_using_slow",c);return}s.watchdogSubmitStartTime=i;return}if(r!=="thinking")return;const a=i-(s.watchdogSubmitStartTime||i),u=i-(s.watchdogLastDataFlowTime||i);if(u>=Z){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(u/1e3)}s (source: ${o}, session: ${t}, status: ${r}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"data_flow",u);return}if(a>=st){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(a/1e3)}s (source: ${o}, session: ${t}, status: ${r}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,s,o,"submit_timeout",a);return}},V)}executeWatchdogRecovery(t,e,o,s,r){l(`[ACode] Watchdog (${s}): calling runtime.abort() after ${Math.round(r/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()}startDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now()}cancelDataFlowWatchdog(t){t.watchdogLastDataFlowTime=Date.now()}formatAiRequestActionDetail(t){const e=`
1
+ import{EventEmitter as B}from"node:events";import L from"node:path";import q from"node:fs/promises";import{pathToFileURL as N}from"node:url";import{v4 as D}from"uuid";import{getAcodeConfigFile as O,getAcodeSkillsDir as K,getRuntimeHomeDir as H}from"../config.js";import{getReleasedAcodeEntryPath as j}from"../services/acode-package.js";import{getInstanceAiConfigDebugLogger as P}from"../utils/instance-ai-config-debug-logger.js";import{redactForLog as $}from"../services/instance-ai-config-service.js";import{subAgentManager as Q}from"../services/sub-agent-manager-instance.js";import{agentPtyManager as G}from"../services/agent-pty-manager.js";import{resolveAcodeProviderConfig as z}from"./instance-ai-config-resolver.js";import{recordAgentFileChange as J}from"../services/workspaceTaskChangeWatcher.js";import{getBrowserTools as Y,closeBrowserSession as X,registerListenerWakeHook as V,unregisterListenerWakeHook as E}from"../services/browser-session-manager.js";import{isMessagePollingIdleCommand as w,isPollMessageToolDescriptor as Z}from"./acode-tool-names.js";import{IdlePollLoop as tt}from"./idle-poll-loop.js";import{getCanonicalMcpDetail as I,getToolActionInfo as et}from"./types.js";const ot=process.env.ACODE_COMPACTION_DEBUG==="1";function u(...r){ot&&console.log(...r)}const M=["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(" "),st=5e3,it=4e4,at=5*6e4,nt=250,rt=2e3,lt=12e4,R=3e3,ut="\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 dt(){return L.resolve(j())}function ct(r){return N(L.resolve(r)).href}const U=128e3,k={"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 mt(r){if(!r)return U;const t=r.toLowerCase().trim();if(k[t])return k[t].contextLimit;const e=Object.keys(k).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?k[e[0]].contextLimit:U}const v=4096;function pt(r){if(!r)return v;const t=r.toLowerCase().trim();if(k[t])return k[t].maxOutput;const e=Object.keys(k).filter(o=>t.startsWith(o)).sort((o,s)=>s.length-o.length);return e.length>0?k[e[0]].maxOutput:v}function gt(r){if(!r||typeof r!="object")return;const t=r,e=y(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),o=y(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(!(e===0&&o===0))return{inputTokens:e,outputTokens:o}}function y(...r){for(const t of r){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function F(r){return y(r.estimatedContextTokens,r.contextTokens,r.context_tokens,r.contextUsedTokens,r.context_used_tokens)}function ft(r){return r==="stderr"||r==="mixed"?r:"stdout"}function ht(r){if(!r||typeof r!="object"||Array.isArray(r))return;const t={};for(const[e,o]of Object.entries(r))typeof o=="string"&&(t[e]=o);return Object.keys(t).length>0?t:void 0}function Tt(r){return r.failed===!0}function W(r,t,e){if(!r)return e?`${t}/${e}`:t;const o=`${t}__`;return r.startsWith(o)?I(`${t}__${r.slice(o.length)}`):I(r.replace("/","__"))}function St(r){return r==="read_file"||r==="edit_file"||r==="write_file"||r==="bash"}function At(r){const t=_t(r);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof r=="string"&&r.trim().length>0}function _t(r){if(r&&typeof r=="object"&&!Array.isArray(r))return r;if(!(typeof r!="string"||!r.trim()))try{const t=JSON.parse(r);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class Ft extends B{constructor(){super(...arguments),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){const o=H(),s=e.mcpConfigPath||O(o),{resolved:n,configContextLimit:i}=await this.resolveAcodeProvider(e,s),a=n.model,l=i??mt(a),c=pt(a),m={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:l,maxOutput:c}};this.sessions.set(t,{adapterSession:m,config:e,runtime:await this.createRuntime(t,a,e,o),autoPollActive:!1}),this.emit("status-change",t,"starting");const d=this.sessions.get(t);if(!d)throw new Error("ACode session was not initialized");const g=()=>{const p=this.sessions.get(t);p&&this.getIdlePollLoop(p).start()};this.listenerWakeHooks.set(t,g),V(e.agentId,g);try{await d.runtime.start(),m.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:d.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(p){m.status="error",this.emitRuntimeErrorEvent(t,p),this.emit("status-change",t,"error");const h=this.sessions.get(t);throw h?.capabilitiesFallbackTimer&&clearTimeout(h.capabilitiesFallbackTimer),this.sessions.delete(t),E(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),p}}async sendMessage(t,e){const o=Date.now();u("[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"),u("[ACode] \u25B6\uFE0F sendMessage STARTED"),u(`[ACode] Session: ${t}`),u(`[ACode] Message: ${e.slice(0,100)}${e.length>100?"...":""}`),u("[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;u(`[ACode] Previous status: ${n}`),this.cancelScheduledAutoPoll(s),s.failedTurnRecoveryScheduled=!1,s.idlePollLoop?.stop();const i={id:D(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};s.adapterSession.messages.push(i),this.emit("conversation-message",t,i),u(`[ACode] Changing status: ${n} \u2192 thinking`),s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.startSubmitTimeoutDetection(t,s,"sendMessage");try{u("[ACode] \u25B6\uFE0F Calling runtime.submit()...");const a=Date.now();await s.runtime.submit(e);const l=Date.now()-a;this.cancelSubmitTimeoutDetection(s),u(`[ACode] \u2705 runtime.submit() completed in ${l}ms`),u(`[ACode] Current status after submit: ${s.adapterSession.status}`),u("[ACode] \u25B6\uFE0F Calling recoverResolvedTurnWithoutTerminalEvent()..."),this.recoverResolvedTurnWithoutTerminalEvent(t),u(`[ACode] Status after recovery: ${s.adapterSession.status}`);const c=Date.now()-o;u("[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"),u(`[ACode] \u2705 sendMessage COMPLETED in ${c}ms`),u("[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 l=Date.now()-o;console.error(`[ACode] \u274C sendMessage FAILED after ${l}ms:`,a instanceof Error?a.message:String(a)),this.cancelSubmitTimeoutDetection(s),u("[ACode] \u25B6\uFE0F Calling emitRuntimeError with recover=true..."),this.emitRuntimeError(t,a,{recover:!0}),u(`[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){u(`[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},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&&(E(o,this.listenerWakeHooks.get(t)),X(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}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}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&&w(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 q.readFile(t,"utf-8"),o=JSON.parse(e),n=o.provider?.default,i=n?.options,a=y(o.contextLimit),l={},c=n?.models;if(c&&typeof c=="object"){for(const[m,d]of Object.entries(c))if(d&&typeof d=="object"){const g=y(d.contextLimit);g>0&&(l[m.trim()]=g)}}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(l).length>0?{modelContextLimits:l}:{}}}catch(e){const o=e instanceof Error?e.message:String(e);return P().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=P();s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?$(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 l=z(n,i,"acode-default");return s.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:$(n),globalConfigModel:i?.model??null,resolvedModel:l.model,resolvedBaseURL:l.baseURL??null,resolvedApiKey:l.apiKey?"[set]":null,configContextLimit:a,resolvedSource:l.source}}),{resolved:l,configPath:e,perSessionModel:o,configContextLimit:a}}async createRuntime(t,e,o,s){const n=await this.loadRuntimeConstructor(),i=o.mcpConfigPath||O(s);let a=[];try{a=await Y(o.agentId,o.scopeKey)}catch(m){u(`[acode-adapter] browser tools injection skipped for agent ${o.agentId}:`,m.message)}const l=new n({sessionId:t,agentId:o.agentId,workingDirectory:o.workingDirectory,configPath:i,skillsDir:K(s),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:Q,terminalManager:G,...o.subAgentModel?{subAgentModel:o.subAgentModel}:{},...o.subAgentEffort?{subAgentEffort:o.subAgentEffort}:{},...o.instanceAiConfig?.effort?{effort:o.instanceAiConfig.effort}:{},onFileChange:m=>J(m),extraBuiltInTools:a});return P().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:i}}),l.on("event",m=>this.forwardAcodeEvent(m)),l}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=dt(),e=await import(ct(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(t.type==="assistant_delta"){const o=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:D(),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:ft(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==="ai_request"){const o=F(t.data);let s;if(o>0){const a=e.adapterSession.totalUsage.inputTokens;a>0?e.adapterSession.totalUsage.inputTokens=Math.min(o,Math.floor(a*1.5)):e.adapterSession.totalUsage.inputTokens=o,s={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const i={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};s&&(i.usage=s),this.emit("status-change",t.sessionId,e.adapterSession.status,i),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:ht(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=gt(t.data.usage);if(o){const n=e.adapterSession.totalUsage.inputTokens;n>0&&o.inputTokens<Math.floor(n*.2)||(e.adapterSession.totalUsage.inputTokens=o.inputTokens,e.adapterSession.totalUsage.outputTokens=o.outputTokens)}const s=e.adapterSession.status;if(u(`[ACode] turn_complete event received (session: ${t.sessionId}), previous status: ${s}, failed: ${t.data.failed===!0}, aborted: ${t.data.aborted===!0}`),Tt(t.data)){u(`[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){u(`[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}),u(`[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 h=t.data.tools;h.some(f=>Z(f))||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 T=Array.isArray(t.data.servers)?t.data.servers:[],A=h.map(f=>({name:String(f.name??""),source:String(f.source??""),description:String(f.description??"")})).filter(f=>f.name),_={kind:"mcp",mcpServers:T,mcpTools:A};e.cachedMcpCapabilities=_,e.lastMcpCapabilities=_,e.lastCombinedCapabilities={kind:"combined",mcpServers:T,mcpTools:A,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},u(`[cap-diag] MCP capabilities cached: ${T.length} servers, ${A.length} tools`,{sessionId:t.sessionId,servers:T,toolNames:A.map(f=>f.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const f=e.cachedMcpCapabilities;if(!f)return;const b={...f,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:b,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(b)}),u(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${R}ms)`,{sessionId:t.sessionId,mcpServers:f.mcpServers,mcpToolsCount:f.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},R);return}const o=String(t.data.action??"");u(`[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,l=et(i,a);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,l.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const c=St(l.actionType)?l.actionDetail||W(void 0,s,n):W(l.actionDetail,s,n),m=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,d=a?JSON.stringify(a,null,2):void 0,g={toolName:c,rawToolName:i,actionType:l.actionType,actionLabel:l.actionLabel,actionDetail:c,...d?{actionInput:d}:{},...a?{toolInput:a}:{},...m?{toolUseId:m,actionId:m}:{},metadata:{mcpServer:s}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...g,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const h=l.actionType==="idle"&&!At(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=h,this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const C=l.actionType==="idle";this.emit("status-change",t.sessionId,h,C||h==="thinking"?void 0:g);return}const p=l.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=p,p==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...g}),this.emitProviderEvent(t,"tool_use_start",g),this.emit("status-change",t.sessionId,p,g);return}if(t.type==="skill_status"){const s=(Array.isArray(t.data.skills)?t.data.skills:[]).map(d=>({name:String(d.name??""),description:typeof d.description=="string"?d.description:void 0,directory:typeof d.directory=="string"?d.directory:void 0})).filter(d=>d.name),n=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,a=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(d=>{const g=Array.isArray(d.skills)?d.skills:[];return{dir:typeof d.dir=="string"?d.dir:"",exists:d.exists===!0,skills:g.map(p=>({name:String(p.name??""),description:typeof p.description=="string"?p.description:void 0,directory:typeof p.directory=="string"?p.directory:void 0})).filter(p=>p.name)}}).filter(d=>d.dir),l=e.cachedMcpCapabilities??e.lastMcpCapabilities,c=e.cachedMcpCapabilities!==void 0,m={kind:"combined",mcpServers:l?.mcpServers??[],mcpTools:l?.mcpTools??[],skills:s,skillsDir:n,skillGroups:a};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:m,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(m)}),e.lastCombinedCapabilities=m,u(`[cap-diag] Combined capabilities emitted ${c?"(startup merge)":"(runtime refresh)"}: ${(l?.mcpTools??[]).length} MCP tools, ${s.length} skills`,{sessionId:t.sessionId,mcpServers:l?.mcpServers??[],skillsDir:n}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="session_started"){const o=F(t.data),s=y(t.data.contextLimit)||void 0,n=y(t.data.maxOutput)||void 0,i=y(t.data.inputLimit)||void 0,a=y(t.data.compactionThreshold)||void 0;let l=!1;o>0&&(e.adapterSession.totalUsage.inputTokens=o,e.adapterSession.totalUsage.outputTokens=0,l=!0),s!==void 0&&(e.adapterSession.totalUsage.contextLimit=s,l=!0),n!==void 0&&(e.adapterSession.totalUsage.maxOutput=n,l=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,l=!0),a!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=a,l=!0),l&&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",l=o.parentId,c=o.compactionId;let m,d;if(n){const p=String(o.sizeKB??o.sizeBeforeKB??"?"),h=String(o.messageCount??o.messageCountBefore??"?"),C=o.estimatedTokens,T=o.actualInputTokens?`input=${o.actualInputTokens}`:"",A=o.actualOutputTokens?`output=${o.actualOutputTokens}`:"",_=o.trigger?`, \u89E6\u53D1: ${o.trigger}`:"";m="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",C!==void 0?d=`\u538B\u7F29\u524D: ~${C} tokens, \u6D88\u606F: ${h}\u6761`+(T?`, \u5B9E\u9645 tokens: ${T} ${A}`:"")+_:d=`\u538B\u7F29\u524D: ${p}KB, \u6D88\u606F: ${h}\u6761`+(T?`, \u5B9E\u9645 tokens: ${T} ${A}`:"")+_}else if(a)m=String(o.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),d=String(o.phaseDetail??"");else{const p=o.tokensBefore,h=o.tokensAfter,C=o.freedTokens,T=String(o.sizeBeforeKB??"?"),A=String(o.sizeAfterKB??"?"),_=String(o.freedKB??"?"),f=String(o.strategy??"?"),b=Number(o.prunedToolMessages??0),S=Number(o.summarizedMessages??0);m="\u538B\u7F29\u5B8C\u6210",p!==void 0&&h!==void 0?d=`\u91CA\u653E: ${C??p-h} tokens, ${p} tokens \u2192 ${h} tokens, \u7B56\u7565: ${f}`+(b?`, \u88C1\u526A\u5DE5\u5177: ${b}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:""):d=`\u91CA\u653E: ${_}KB, ${T}KB \u2192 ${A}KB, \u7B56\u7565: ${f}`+(b?`, \u88C1\u526A\u5DE5\u5177: ${b}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:"")}n&&(e.adapterSession.status="compacting");const g={actionType:"context_compaction",actionLabel:m,actionDetail:d};if(n&&c)g.actionId=c;else if((a||i)&&c)if(g.parentId=c,a){const p=String(o.phase??"unknown");g.actionId=`${c}-phase-${p}`}else g.actionId=`${c}-end`;a&&l&&!g.parentId&&(g.parentId=l),i&&(e.adapterSession.totalUsage.inputTokens=0,e.adapterSession.totalUsage.outputTokens=0,g.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",g),this.emit("status-change",t.sessionId,"compacting",g);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,o=t.config.agentId;return t.idlePollLoop=new tt({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:s=>w(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,n)=>this.submitAutoPollPrompt(e,n?s:ut,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:s=>this.submitAutoPollPrompt(e,s)}),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,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){u(`[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=nt){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,M,{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.adapterSession.status==="tool_using"&&e.pendingToolEventData){const a=e.pendingToolEventData;u(`[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,u(`[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&&w(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,M,{keepWaitingStatus:!0})},rt)}recoverResolvedTurnWithoutTerminalEvent(t){u(`[ACode] \u25B6\uFE0F recoverResolvedTurnWithoutTerminalEvent called for session ${t}`);const e=this.sessions.get(t);if(!e||this.isTerminalStatus(e.adapterSession.status)){u(`[ACode] Skipping recovery: entry=${!!e}, isTerminal=${e?this.isTerminalStatus(e.adapterSession.status):"N/A"}`);return}if(u(`[ACode] Current status: ${e.adapterSession.status}`),e.adapterSession.status!=="thinking"&&e.adapterSession.status!=="tool_using"){u(`[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.`),u("[ACode] Recovering to waiting_input..."),e.adapterSession.status="waiting_input";const o=e.idleCommands?.idleInputCommand,n=!!(o&&w(o))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",n),u(`[ACode] \u2705 Recovery complete, status now: ${e.adapterSession.status}`),u("[ACode] \u25B6\uFE0F Arming idle loop or auto-poll..."),this.armIdleLoopOrAutoPoll(t),u("[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"){s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}if(n==="tool_using"){const c=i-(s.watchdogLastDataFlowTime||i);if(c>=at){const m=String(s.pendingToolEventData?.rawToolName??"");if(m.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(c/1e3)}s but await_complete is running (session: ${t}, tool: ${m}), skipping recovery (sub-agents have their own watchdogs, bg commands have timeout limits)`),s.watchdogSubmitStartTime=i,s.watchdogLastDataFlowTime=i;return}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.`),this.executeWatchdogRecovery(t,s,o,"tool_using_slow",c);return}s.watchdogSubmitStartTime=i;return}if(n!=="thinking")return;const a=i-(s.watchdogSubmitStartTime||i),l=i-(s.watchdogLastDataFlowTime||i);if(l>=it){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(l/1e3)}s (source: ${o}, session: ${t}, status: ${n}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,s,o,"data_flow",l);return}if(a>=lt){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}},st)}executeWatchdogRecovery(t,e,o,s,n){u(`[ACode] Watchdog (${s}): calling runtime.abort() after ${Math.round(n/1e3)}s...`);try{e.runtime.abort(),u(`[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()}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
- `,r=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:"",u=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,d=typeof t.lastUserMessagePreview=="string"?t.lastUserMessagePreview:"",m=[r?`\u6A21\u578B: ${r}`:void 0,i?`\u63A5\u53E3: ${i}`:void 0,a?`\u65B9\u6CD5: ${a}`:void 0,u!==void 0?`\u6D41\u5F0F: ${u?"\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,d?`\u6700\u540E\u8BF7\u6C42: ${d}`:void 0].filter(A=>!!A),g=/^(authorization|x-api-key|api-key|cookie|set-cookie|x-auth-token|token)$/i,h=t.requestHeaders,C=h?Object.entries(h).filter(([A])=>!g.test(A)).map(([A,x])=>`${A}: ${x}`).filter(A=>A.trim().length>0):[],T=m.join(`
8
- `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",_=C.length>0?`${e}${C.join(`
9
- `)}`:"",S=typeof t.requestBody=="string"?t.requestBody:"",f=S.length>6e4?`${S.slice(0,6e4)}
10
- ...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:S,b=f?`${o}${f}`:"";return`${T}${_}${b}`}}export{$t as AcodeSdkAdapter,mt as isFailedAcodeTurnComplete,nt as toAcodeEsmImportSpecifier};
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:"",l=typeof t.stream=="boolean"?t.stream:void 0,c=typeof t.messageCount=="number"?t.messageCount:void 0,m=typeof t.toolCount=="number"?t.toolCount:void 0,d=typeof t.lastUserMessagePreview=="string"?t.lastUserMessagePreview:"",g=[n?`\u6A21\u578B: ${n}`:void 0,i?`\u63A5\u53E3: ${i}`:void 0,a?`\u65B9\u6CD5: ${a}`:void 0,l!==void 0?`\u6D41\u5F0F: ${l?"\u662F":"\u5426"}`:void 0,c!==void 0?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${c}`:void 0,m!==void 0?`\u53EF\u7528\u5DE5\u5177: ${m}`:void 0,d?`\u6700\u540E\u8BF7\u6C42: ${d}`:void 0].filter(S=>!!S),p=/^(authorization|x-api-key|api-key|cookie|set-cookie|x-auth-token|token)$/i,h=t.requestHeaders,C=h?Object.entries(h).filter(([S])=>!p.test(S)).map(([S,x])=>`${S}: ${x}`).filter(S=>S.trim().length>0):[],T=g.join(`
8
+ `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",A=C.length>0?`${e}${C.join(`
9
+ `)}`:"",_=typeof t.requestBody=="string"?t.requestBody:"",f=_.length>6e4?`${_.slice(0,6e4)}
10
+ ...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:_,b=f?`${o}${f}`:"";return`${T}${A}${b}`}}export{Ft as AcodeSdkAdapter,Tt as isFailedAcodeTurnComplete,ct as toAcodeEsmImportSpecifier};
11
11
 
@@ -34,6 +34,10 @@ export declare class ClaudeSdkAdapter extends EventEmitter implements BaseProvid
34
34
  private idlePollLoops;
35
35
  private lastActivityAt;
36
36
 
37
+ private sessionAgentIds;
38
+
39
+ private listenerWakeHooks;
40
+
37
41
  setIdleCommands(sessionId: string, commands: {
38
42
  idleInputCommand: string;
39
43
  nonInputCommand: string;
@@ -1,4 +1,4 @@
1
- import{execSync as S}from"child_process";import{EventEmitter as C}from"events";import*as p from"fs";import*as c from"path";import{v4 as h}from"uuid";import{importBridgeSdkPackage as y}from"../utils/sdk-package-loader.js";import{IdlePollLoop as k}from"./idle-poll-loop.js";import{getToolActionInfo as f}from"./types.js";class v{constructor(){this.queue=[],this.resolve=null,this.done=!1}enqueue(t){if(!this.done)if(this.resolve){const e=this.resolve;this.resolve=null,e({value:t,done:!1})}else this.queue.push(t)}close(){if(this.done=!0,this.resolve){const t=this.resolve;this.resolve=null,t({value:void 0,done:!0})}}[Symbol.asyncIterator](){return{next:()=>this.queue.length>0?Promise.resolve({value:this.queue.shift(),done:!1}):this.done?Promise.resolve({value:void 0,done:!0}):new Promise(t=>{this.resolve=t})}}}class A extends C{constructor(){super(...arguments),this.providerId="claude-code",this.displayName="Claude Code",this.sessions=new Map,this.sdkQueries=new Map,this.inputStreams=new Map,this.abortControllers=new Map,this.sdkModule=null,this.pendingPermissions=new Map,this.pendingQuestions=new Map,this.activeToolUseIds=new Map,this.recentToolNames=new Map,this.toolInputBuffers=new Map,this.idleCommands=new Map,this.idleTimers=new Map,this.idlePollLoops=new Map,this.lastActivityAt=new Map}async startSession(t,e){console.log(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u542F\u52A8 Claude Code SDK \u4F1A\u8BDD \u2605\u2605\u2605 sessionId="${t}", command="${e.command}", workingDirectory="${e.workingDirectory}"`);const o={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,o);try{const a=await this.loadSdk(),n=new AbortController;this.abortControllers.set(t,n);const i=new v;this.inputStreams.set(t,i);const s=this.buildQueryOptions(t,e,n),r=a.query({prompt:i,options:s});if(this.sdkQueries.set(t,r),this.consumeStream(t,r).catch(l=>{console.error(`[ClaudeSdkAdapter] Stream error for ${t}:`,l)}),await new Promise(l=>setTimeout(l,100)),e.initialPrompt){o.status="starting",this.emit("status-change",t,"starting");const l={id:h(),sessionId:t,role:"user",content:e.initialPrompt,timestamp:new Date().toISOString()};o.messages.push(l),this.emit("conversation-message",t,l);const d=this.parseMessageContent(e.initialPrompt);i.enqueue({type:"user",message:{role:"user",content:d}})}else o.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:o.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}catch(a){const n=a instanceof Error?a.message:String(a);throw o.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Failed to start session: ${n}`}}),a}}async sendMessage(t,e){const o=this.sessions.get(t),a=this.inputStreams.get(t);if(!o||!a)throw new Error(`Session ${t} not found`);if(o.status==="error")throw new Error(`Session ${t} is in error state`);const n={id:h(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};o.messages.push(n),this.emit("conversation-message",t,n),o.status="thinking",this.emit("status-change",t,"thinking");const i=this.parseMessageContent(e);a.enqueue({type:"user",message:{role:"user",content:i}})}parseMessageContent(t){const e=[],o=/\[图片\s*:\s*([^\]\n]+?)\s*\]/gi;let a=0,n=o.exec(t);for(;n!==null;){if(n.index>a){const s=t.slice(a,n.index).trim();s&&e.push({type:"text",text:s})}const i=n[1].trim();i&&(console.log(`[ClaudeSdkAdapter] \u6DFB\u52A0\u56FE\u7247 URL: ${i}`),e.push({type:"image",source:{type:"url",url:i}})),a=n.index+n[0].length,n=o.exec(t)}if(a<t.length){const i=t.slice(a).trim();i&&e.push({type:"text",text:i})}return e.length===0&&e.push({type:"text",text:t}),e}async sendConfirmation(t,e){const o=this.pendingPermissions.get(t);o&&(e?o.resolve({behavior:"allow",updatedInput:o.toolInput}):o.resolve({behavior:"deny",message:"User denied"}),this.pendingPermissions.delete(t))}async sendQuestionAnswer(t,e){const o=this.pendingQuestions.get(t);if(!o)return;const a=o.toolInput.questions;let n=`\u7528\u6237\u5DF2\u56DE\u7B54\u4E86\u60A8\u7684\u95EE\u9898\uFF1A
1
+ import{execSync as k}from"child_process";import{EventEmitter as C}from"events";import*as p from"fs";import*as c from"path";import{v4 as h}from"uuid";import{registerListenerWakeHook as y,unregisterListenerWakeHook as f}from"../services/browser-session-manager.js";import{importBridgeSdkPackage as v}from"../utils/sdk-package-loader.js";import{IdlePollLoop as _}from"./idle-poll-loop.js";import{getToolActionInfo as g}from"./types.js";class x{constructor(){this.queue=[],this.resolve=null,this.done=!1}enqueue(t){if(!this.done)if(this.resolve){const e=this.resolve;this.resolve=null,e({value:t,done:!1})}else this.queue.push(t)}close(){if(this.done=!0,this.resolve){const t=this.resolve;this.resolve=null,t({value:void 0,done:!0})}}[Symbol.asyncIterator](){return{next:()=>this.queue.length>0?Promise.resolve({value:this.queue.shift(),done:!1}):this.done?Promise.resolve({value:void 0,done:!0}):new Promise(t=>{this.resolve=t})}}}class M extends C{constructor(){super(...arguments),this.providerId="claude-code",this.displayName="Claude Code",this.sessions=new Map,this.sdkQueries=new Map,this.inputStreams=new Map,this.abortControllers=new Map,this.sdkModule=null,this.pendingPermissions=new Map,this.pendingQuestions=new Map,this.activeToolUseIds=new Map,this.recentToolNames=new Map,this.toolInputBuffers=new Map,this.idleCommands=new Map,this.idleTimers=new Map,this.idlePollLoops=new Map,this.lastActivityAt=new Map,this.sessionAgentIds=new Map,this.listenerWakeHooks=new Map}async startSession(t,e){console.log(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u542F\u52A8 Claude Code SDK \u4F1A\u8BDD \u2605\u2605\u2605 sessionId="${t}", command="${e.command}", workingDirectory="${e.workingDirectory}"`);const o={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};if(this.sessions.set(t,o),e.agentId&&this.sessionAgentIds.set(t,e.agentId),e.agentId){const a=()=>{this.getIdlePollLoop(t).start()};this.listenerWakeHooks.set(t,a),y(e.agentId,a)}try{const a=await this.loadSdk(),n=new AbortController;this.abortControllers.set(t,n);const i=new x;this.inputStreams.set(t,i);const s=this.buildQueryOptions(t,e,n),r=a.query({prompt:i,options:s});if(this.sdkQueries.set(t,r),this.consumeStream(t,r).catch(l=>{console.error(`[ClaudeSdkAdapter] Stream error for ${t}:`,l)}),await new Promise(l=>setTimeout(l,100)),e.initialPrompt){o.status="starting",this.emit("status-change",t,"starting");const l={id:h(),sessionId:t,role:"user",content:e.initialPrompt,timestamp:new Date().toISOString()};o.messages.push(l),this.emit("conversation-message",t,l);const d=this.parseMessageContent(e.initialPrompt);i.enqueue({type:"user",message:{role:"user",content:d}})}else o.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:o.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}catch(a){e.agentId&&f(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const n=a instanceof Error?a.message:String(a);throw o.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Failed to start session: ${n}`}}),a}}async sendMessage(t,e){const o=this.sessions.get(t),a=this.inputStreams.get(t);if(!o||!a)throw new Error(`Session ${t} not found`);if(o.status==="error")throw new Error(`Session ${t} is in error state`);const n={id:h(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};o.messages.push(n),this.emit("conversation-message",t,n),o.status="thinking",this.emit("status-change",t,"thinking");const i=this.parseMessageContent(e);a.enqueue({type:"user",message:{role:"user",content:i}})}parseMessageContent(t){const e=[],o=/\[图片\s*:\s*([^\]\n]+?)\s*\]/gi;let a=0,n=o.exec(t);for(;n!==null;){if(n.index>a){const s=t.slice(a,n.index).trim();s&&e.push({type:"text",text:s})}const i=n[1].trim();i&&(console.log(`[ClaudeSdkAdapter] \u6DFB\u52A0\u56FE\u7247 URL: ${i}`),e.push({type:"image",source:{type:"url",url:i}})),a=n.index+n[0].length,n=o.exec(t)}if(a<t.length){const i=t.slice(a).trim();i&&e.push({type:"text",text:i})}return e.length===0&&e.push({type:"text",text:t}),e}async sendConfirmation(t,e){const o=this.pendingPermissions.get(t);o&&(e?o.resolve({behavior:"allow",updatedInput:o.toolInput}):o.resolve({behavior:"deny",message:"User denied"}),this.pendingPermissions.delete(t))}async sendQuestionAnswer(t,e){const o=this.pendingQuestions.get(t);if(!o)return;const a=o.toolInput.questions;let n=`\u7528\u6237\u5DF2\u56DE\u7B54\u4E86\u60A8\u7684\u95EE\u9898\uFF1A
2
2
  `;Array.isArray(a)?a.forEach((i,s)=>{const r=String(s),l=e[r]||e[i.header||""]||e[i.question]||"\uFF08\u672A\u586B\u5199\uFF09";n+=`\u2022 ${i.header||i.question}\uFF1A${l}
3
- `}):n+=JSON.stringify(e),o.resolve({behavior:"deny",message:n}),this.pendingQuestions.delete(t)}async abortCurrentTurn(t){const e=this.abortControllers.get(t);e&&e.abort()}async terminateSession(t){const e=this.sessions.get(t),o=this.sdkQueries.get(t),a=this.inputStreams.get(t);if(a&&a.close(),o)try{o.close()}catch{}e&&(e.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent(t,{type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}})),this.cleanupSession(t)}getConversation(t){return this.sessions.get(t)?.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.providerSessionId}getSessionStatus(t){return this.sessions.get(t)?.status}getSessionPid(t){return this.sessions.get(t)?.pid}cleanup(){for(const t of this.sessions.keys())try{this.terminateSession(t)}catch{}this.sessions.clear(),this.sdkQueries.clear(),this.inputStreams.clear(),this.abortControllers.clear(),this.pendingPermissions.clear(),this.pendingQuestions.clear(),this.idleCommands.clear(),this.idleTimers.clear()}setIdleCommands(t,e){this.idleCommands.set(t,e);const o=this.sessions.get(t);o&&o.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.idleCommands.get(t);if(!e?.idleInputCommand)return;if(this.isMessagePollingIdleCommand(e.idleInputCommand)){this.getIdlePollLoop(t).start();return}this.lastActivityAt.set(t,Date.now());const o=setInterval(()=>{this.checkIdleState(t)},500);this.idleTimers.set(t,o)}stopIdleDetection(t){this.idlePollLoops.get(t)?.stop();const e=this.idleTimers.get(t);e&&(clearInterval(e),this.idleTimers.delete(t))}checkIdleState(t){const e=this.sessions.get(t);if(!e||e.status!=="waiting_input")return;const o=this.idleCommands.get(t);if(!o||!o.idleInputCommand&&!o.nonInputCommand)return;const a=this.lastActivityAt.get(t)||0;if(!(Date.now()-a<1500)&&(this.lastActivityAt.set(t,Date.now()),o.idleInputCommand)){const s=o.idleInputCommand;this.isMessagePollingIdleCommand(s)?this.sendIdlePrompt(t,this.buildMessagePollingIdlePrompt()):this.sendIdlePrompt(t,s)}}sendIdlePrompt(t,e,o){const a=this.inputStreams.get(t);if(!a)return;const n=this.sessions.get(t);n&&!o?.keepWaitingStatus&&(n.status="thinking",this.emit("status-change",t,"thinking")),a.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:e}]}})}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const o=e.toLowerCase();return o.includes("poll_message")||o.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}buildMessagePollingIdlePrompt(){return"\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5F53\u524D\u5DE5\u4F5C\u5DF2\u5B8C\u6210\u6216\u8FD0\u884C\u65F6\u5DF2\u8FDB\u5165\u7A7A\u95F2\u72B6\u6001\u3002\u8BF7\u7ACB\u5373\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"}getIdlePollLoop(t){const e=this.idlePollLoops.get(t);if(e)return e;const o=new k({getStatus:()=>this.sessions.get(t)?.status,getCommand:()=>this.idleCommands.get(t)?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),dispatchPollingPrompt:()=>this.sendIdlePrompt(t,this.buildMessagePollingIdlePrompt(),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a)});return this.idlePollLoops.set(t,o),o}async sendShortcutInput(t,e){await this.executeIdleCommand(t,e)}async executeIdleCommand(t,e){const o=this.inputStreams.get(t);if(!o)return;const a=/\[(.+?)\]/g;let n=0;const i=[];let s=a.exec(e);for(;s!==null;){s.index>n&&i.push({type:"text",value:e.slice(n,s.index)});const r=s[1];if(r.startsWith("wait:")){const l=parseFloat(r.slice(5));isNaN(l)||i.push({type:"wait",value:l*1e3})}else{const l={enter:"\r",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",tab:" ",esc:"\x1B",escape:"\x1B",space:" ","ctrl+c":""};i.push({type:"key",value:l[r.toLowerCase()]||r})}n=s.index+s[0].length,s=a.exec(e)}n<e.length&&i.push({type:"text",value:e.slice(n)});for(const r of i)if(r.type==="wait")await new Promise(l=>setTimeout(l,r.value));else{const l=String(r.value);o.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:l}]}})}}updateActivity(t){this.lastActivityAt.set(t,Date.now())}async resumeSession(t,e,o){const a={sessionId:t,providerSessionId:e,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,a);try{await this.startSession(t,o),a.providerSessionId=e}catch(n){throw a.status="error",this.emit("status-change",t,"error"),n}}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await y("@anthropic-ai/claude-agent-sdk")}catch(t){throw new Error(`Failed to load @anthropic-ai/claude-agent-sdk. Please install: npm install @anthropic-ai/claude-agent-sdk. Original error: ${t}`)}return this.sdkModule}findClaudeExecutable(t){const e=this.extractExecutableCommand(t);if(c.isAbsolute(e)&&p.existsSync(e)){const i=this.resolveWindowsWrapper(e);if(i)return i;if(this.isWindowsWrapperPath(e)){console.warn(`[ClaudeSdkAdapter] Skipping wrapper script for Claude Code executable: ${e}`);return}return e}const o=this.resolveExecutableFromPath(e);if(o)return o;if(process.platform==="win32"&&this.shouldUseDefaultClaudeFallbacks(e)){const i=process.env.USERPROFILE||"",s=process.env.LOCALAPPDATA||"",r=process.env.APPDATA||"",l=[c.join(s,"Volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(s,"Volta","tools","image","packages","@anthropic-ai","claude-code","cli.js")];for(const u of l)if(p.existsSync(u))return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI via Volta: ${u}`),u;const d=[c.join(r,"npm","node_modules","@anthropic-ai","claude-code","cli.js"),c.join(s,"Programs","claude-code","claude.exe"),c.join(i,".local","bin","claude.exe")];for(const u of d)if(u&&p.existsSync(u))return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI: ${u}`),u}const a=process.env.HOME||"",n=[c.join(a,".local","bin","claude"),c.join(a,".npm-global","bin","claude"),c.join(a,".local","share","mise","shims","claude"),c.join(a,".asdf","shims","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude","/usr/bin/claude","/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js","/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js",c.join(a,".local","share","volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(a,".volta","tools","shared","@anthropic-ai","claude-code","cli.js")];if(this.shouldUseDefaultClaudeFallbacks(e)){for(const i of n)if(i&&p.existsSync(i))return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI: ${i}`),i}if(this.shouldUseDefaultClaudeFallbacks(e))try{const i=S("npm root -g",{encoding:"utf8",timeout:5e3}).trim(),s=c.join(i,"@anthropic-ai","claude-code","cli.js");if(p.existsSync(s))return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI via npm root: ${s}`),s}catch{}console.warn(`[ClaudeSdkAdapter] Claude Code executable not found for command: ${e}`)}extractExecutableCommand(t){const o=((t||"claude").trim()||"claude").match(/^\s*(?:"([^"]+)"|'([^']+)'|(\S+))/);return o?.[1]||o?.[2]||o?.[3]||"claude"}resolveExecutableFromPath(t){const e=process.env.PATH||"";if(!e)return;const o=c.extname(t).length>0,a=process.platform==="win32"?this.getWindowsPathExtensions(o):[""];for(const n of e.split(c.delimiter))if(n)for(const i of a){const s=c.join(n,`${t}${i}`);if(p.existsSync(s)){if(this.isWindowsWrapperPath(s)){const r=this.resolveWindowsWrapper(s);if(r)return r;continue}return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI via PATH: ${s}`),s}}}getWindowsPathExtensions(t){return t?[""]:(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM;.PS1").split(";").map(o=>o.trim()).filter(o=>o.length>0)}shouldUseDefaultClaudeFallbacks(t){return["claude","claude-code","claudecode"].includes(t.toLowerCase())}isWindowsWrapperPath(t){const e=c.extname(t).toLowerCase();return[".cmd",".bat",".ps1"].includes(e)}resolveWindowsWrapper(t){if(this.isWindowsWrapperPath(t))return this.resolveCliJsFromWrapper(t)}resolveCliJsFromWrapper(t){try{if(p.readFileSync(t,"utf8").includes("volta run")){const n=c.join(process.env.LOCALAPPDATA||"","Volta","tools","shared","@anthropic-ai","claude-code","cli.js");if(p.existsSync(n))return n}const o=c.dirname(t),a=c.join(o,"node_modules","@anthropic-ai","claude-code","cli.js");if(p.existsSync(a))return a}catch{}}buildQueryOptions(t,e,o){const a={cwd:e.workingDirectory,abortController:o,settingSources:["user","project","local"],includePartialMessages:!0},n=this.findClaudeExecutable(e.command);if(n?(a.pathToClaudeCodeExecutable=n,console.log(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u4F7F\u7528 Claude Code \u53EF\u6267\u884C\u6587\u4EF6 \u2605\u2605\u2605 path="${n}"`)):console.warn(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u8B66\u544A\uFF1A\u672A\u627E\u5230 Claude Code \u53EF\u6267\u884C\u6587\u4EF6 \u2605\u2605\u2605 command="${e.command}"`),e.model&&(a.model=e.model),e.maxTurns&&e.maxTurns>0&&(a.maxTurns=e.maxTurns),e.mcpConfigPath)try{const i=p.readFileSync(e.mcpConfigPath,"utf-8"),s=JSON.parse(i);a.mcpServers={...e.extraMcpServers,...s.mcpServers}}catch{a.mcpServers=e.extraMcpServers||{}}else a.mcpServers=e.extraMcpServers||{};return e.allowedTools&&e.allowedTools.length>0?a.allowedTools=e.allowedTools:a.allowedTools=["Read","Write","Edit","Bash","Glob","Grep","WebSearch","WebFetch","Task","NotebookEdit","LSP","Skill","mcp__*"],a.env={...process.env,...e.envOverrides},a.canUseTool=this.createPermissionHandler(t,e.autoAccept),a}createPermissionHandler(t,e){return async(o,a,n)=>o==="AskUserQuestion"||o==="ask_user_question"?new Promise(i=>{this.pendingQuestions.set(t,{resolve:i,toolInput:a}),this.emit("ask-user-question",{sessionId:t,toolCallId:this.activeToolUseIds.get(t)||void 0,questions:a.questions})}):e?{behavior:"allow",updatedInput:a}:new Promise(i=>{this.pendingPermissions.set(t,{resolve:i,toolInput:a}),this.emit("permission-request",{sessionId:t,toolName:o,toolInput:a,permissionPrompt:`Allow ${o}?`})})}async consumeStream(t,e){const o=this.sessions.get(t);if(o)try{for await(const a of e){const n=a;this.handleSdkMessage(t,o,n)}}catch(a){if(this.abortControllers.get(t)?.signal.aborted)return;const n=a instanceof Error?a.message:String(a);this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Stream error: ${n}`}})}}applyUsage(t,e){e&&(Number.isFinite(e.input_tokens)&&(t.totalUsage.inputTokens=Math.max(t.totalUsage.inputTokens,e.input_tokens??0)),Number.isFinite(e.output_tokens)&&(t.totalUsage.outputTokens=Math.max(t.totalUsage.outputTokens,e.output_tokens??0)))}handleSdkMessage(t,e,o){const a=new Date().toISOString();switch(console.log(`[ClaudeSdkAdapter] Received message type: "${o.type}", subtype: "${o.subtype||""}"`),o.tool_name&&console.log(`[ClaudeSdkAdapter] Tool name: "${o.tool_name}"`),o.type){case"text":o.delta&&(e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),this.emitEvent(t,{type:"text_delta",sessionId:t,timestamp:a,data:{text:o.delta}}));break;case"thinking":e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),(o.content||o.delta)&&this.emitEvent(t,{type:"thinking",sessionId:t,timestamp:a,data:{text:o.delta||o.content}});break;case"tool_use":case"tool_use_start":{const n={...f(o.tool_name,o.tool_input),actionId:o.tool_use_id},i=n.actionType==="idle"?"waiting_input":"tool_using";e.status=i;const s=this.extractMcpServerName(o.tool_name||"");this.emit("status-change",t,i,{actionType:n.actionType,actionLabel:n.actionLabel,actionDetail:n.actionDetail,actionId:n.actionId,usage:e.totalUsage,...s?{metadata:{mcpServer:s}}:{}}),n.actionType!=="idle"&&this.stopIdleDetection(t),this.handleToolUse(t,e,o,a)}break;case"tool_result":case"tool_use_end":this.emitEvent(t,{type:"tool_use_end",sessionId:t,timestamp:a,data:{toolName:o.tool_name,toolResult:o.tool_result,isError:o.is_error,toolUseId:o.tool_use_id}});break;case"result":{const n=o.subtype==="success";this.applyUsage(e,o.usage),this.emitEvent(t,{type:"turn_complete",sessionId:t,timestamp:a,data:{usage:e.totalUsage,text:n?o.result:void 0}}),e.status="waiting_input",(()=>{const s=this.idleCommands.get(t);return!!(s?.idleInputCommand&&this.isMessagePollingIdleCommand(s.idleInputCommand))})()?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}break;case"system":o.subtype==="init"&&console.log(`[ClaudeSdkAdapter] Session ${t} initialized: model=${o.model}, tools=${o.tools?.length||0}`);break;case"assistant":if(this.applyUsage(e,o.message?.usage),o.message?.content){const n=o.message.content.filter(i=>i.type==="text"&&i.text).map(i=>i.text||"").join("");n&&e.messages.push({id:h(),sessionId:t,role:"assistant",content:n,timestamp:a})}break;case"user":o.tool_use_result;break;case"error":e.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:a,data:{text:o.content||"Unknown error"}});break;case"stream_event":this.handleStreamEvent(t,e,o,a);break;default:console.log(`[ClaudeSdkAdapter] Unknown message type: ${o.type}`,o)}}handleToolUse(t,e,o,a){const n=this.recentToolNames.get(t),i=this.extractToolNameSuffix(o.tool_name||"");if(n&&Date.now()-n.time<3e4&&n.name===i){console.log(`[ClaudeSdkAdapter] Tool use ${o.tool_name} matches recent stream_event (${n.name}), skipping duplicate event`),this.recentToolNames.delete(t),this.activeToolUseIds.delete(t),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${o.tool_name}: ${JSON.stringify(o.tool_input).slice(0,100)}`,timestamp:a,toolName:o.tool_name,toolInput:o.tool_input,toolUseId:o.tool_use_id});return}this.recentToolNames.delete(t),this.activeToolUseIds.delete(t);const s=f(o.tool_name,o.tool_input);console.log(`[ClaudeSdkAdapter] Tool use: ${o.tool_name}, actionType: ${s.actionType}, actionDetail: ${s.actionDetail}`);const r=this.extractMcpServerName(o.tool_name||"");this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:a,data:{toolName:o.tool_name,toolInput:o.tool_input,toolUseId:o.tool_use_id,actionType:s.actionType,actionLabel:s.actionLabel,actionDetail:s.actionDetail,...r?{metadata:{mcpServer:r}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${o.tool_name}: ${JSON.stringify(o.tool_input).slice(0,100)}`,timestamp:a,toolName:o.tool_name,toolInput:o.tool_input,toolUseId:o.tool_use_id})}handleStreamEvent(t,e,o,a){const n=o.event;if(n){if(n.type==="content_block_start"){const i=n.content_block;if(i?.type==="tool_use"&&i.name){const s=i.name,r=i.id||`stream_${Date.now()}`;console.log(`[ClaudeSdkAdapter] Tool use started via stream_event: ${s} (id: ${r})`),this.activeToolUseIds.set(t,r);const l=this.extractToolNameSuffix(s);this.recentToolNames.set(t,{name:l,time:Date.now()});const d=`${t}:${r}`;this.toolInputBuffers.set(d,"")}}if(n.type==="content_block_delta"&&n.delta?.type==="input_json_delta"&&n.delta.partial_json){const i=this.activeToolUseIds.get(t);if(i){const s=`${t}:${i}`,r=this.toolInputBuffers.get(s)||"";this.toolInputBuffers.set(s,r+n.delta.partial_json),console.log(`[ClaudeSdkAdapter] Tool input delta at index ${n.index}, buffer length: ${r.length+n.delta.partial_json.length}`)}}if(n.type==="content_block_stop"){const i=this.activeToolUseIds.get(t),s=this.recentToolNames.get(t);if(i&&s){const r=`${t}:${i}`,l=this.toolInputBuffers.get(r)||"";console.log(`[ClaudeSdkAdapter] Content block stopped at index ${n.index}, collected JSON length: ${l.length}`);let d;if(l)try{d=JSON.parse(l),console.log("[ClaudeSdkAdapter] Parsed tool input:",JSON.stringify(d).slice(0,200))}catch{console.warn("[ClaudeSdkAdapter] Failed to parse tool input JSON:",l.slice(0,100))}const u={...f(s.name,d),actionId:i},m=this.extractMcpServerName(s.name);e.status="tool_using",this.emit("status-change",t,"tool_using",{actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,usage:e.totalUsage,...m?{metadata:{mcpServer:m}}:{}}),this.stopIdleDetection(t),this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:a,data:{toolName:s.name,toolInput:d,toolUseId:i,actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,...m?{metadata:{mcpServer:m}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${s.name}: ${l.slice(0,100)}`,timestamp:a,toolName:s.name,toolInput:d,toolUseId:i}),this.toolInputBuffers.delete(r),this.activeToolUseIds.delete(t)}}}}extractMcpServerName(t){if(t.startsWith("mcp__")){const e=t.split("__");if(e.length>=3)return e[1]}}extractToolNameSuffix(t){if(t.includes("__"))return t.split("__").pop()||t;if(t.includes("-mcp__")){const e=t.indexOf("-mcp__");return t.substring(e+6)}return t}emitEvent(t,e){this.emit("event",e)}cleanupSession(t){this.stopIdleDetection(t),this.sessions.delete(t),this.sdkQueries.delete(t),this.inputStreams.delete(t),this.abortControllers.delete(t),this.pendingPermissions.delete(t),this.pendingQuestions.delete(t),this.idleCommands.delete(t),this.idlePollLoops.delete(t),this.lastActivityAt.delete(t)}}export{A as ClaudeSdkAdapter};
3
+ `}):n+=JSON.stringify(e),o.resolve({behavior:"deny",message:n}),this.pendingQuestions.delete(t)}async abortCurrentTurn(t){const e=this.abortControllers.get(t);e&&e.abort()}async terminateSession(t){const e=this.sessions.get(t),o=this.sdkQueries.get(t),a=this.inputStreams.get(t);if(a&&a.close(),o)try{o.close()}catch{}e&&(e.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent(t,{type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}));const n=this.sessionAgentIds.get(t);n&&f(n,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.cleanupSession(t)}getConversation(t){return this.sessions.get(t)?.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.providerSessionId}getSessionStatus(t){return this.sessions.get(t)?.status}getSessionPid(t){return this.sessions.get(t)?.pid}cleanup(){for(const t of this.sessions.keys())try{this.terminateSession(t)}catch{}this.sessions.clear(),this.sdkQueries.clear(),this.inputStreams.clear(),this.abortControllers.clear(),this.pendingPermissions.clear(),this.pendingQuestions.clear(),this.idleCommands.clear(),this.idleTimers.clear()}setIdleCommands(t,e){this.idleCommands.set(t,e);const o=this.sessions.get(t);o&&o.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.startIdleDetection(t)}startIdleDetection(t){this.stopIdleDetection(t);const e=this.idleCommands.get(t);if(!e?.idleInputCommand)return;if(this.isMessagePollingIdleCommand(e.idleInputCommand)){this.getIdlePollLoop(t).start();return}this.lastActivityAt.set(t,Date.now());const o=setInterval(()=>{this.checkIdleState(t)},500);this.idleTimers.set(t,o)}stopIdleDetection(t){this.idlePollLoops.get(t)?.stop();const e=this.idleTimers.get(t);e&&(clearInterval(e),this.idleTimers.delete(t))}checkIdleState(t){const e=this.sessions.get(t);if(!e||e.status!=="waiting_input")return;const o=this.idleCommands.get(t);if(!o||!o.idleInputCommand&&!o.nonInputCommand)return;const a=this.lastActivityAt.get(t)||0;if(!(Date.now()-a<1500)&&(this.lastActivityAt.set(t,Date.now()),o.idleInputCommand)){const s=o.idleInputCommand;this.isMessagePollingIdleCommand(s)?this.sendIdlePrompt(t,this.buildMessagePollingIdlePrompt()):this.sendIdlePrompt(t,s)}}sendIdlePrompt(t,e,o){const a=this.inputStreams.get(t);if(!a)return;const n=this.sessions.get(t);n&&!o?.keepWaitingStatus&&(n.status="thinking",this.emit("status-change",t,"thinking")),a.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:e}]}})}isMessagePollingIdleCommand(t){const e=t.trim();if(!e)return!1;const o=e.toLowerCase();return o.includes("poll_message")||o.includes("get_message")||e.includes("\u53D6\u6D88\u606F")}buildMessagePollingIdlePrompt(){return"\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"}getIdlePollLoop(t){const e=this.idlePollLoops.get(t);if(e)return e;const o=new _({getStatus:()=>this.sessions.get(t)?.status,getCommand:()=>this.idleCommands.get(t)?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),preDispatchHook:()=>null,dispatchPollingPrompt:(a,n)=>this.sendIdlePrompt(t,n?a:this.buildMessagePollingIdlePrompt(),{keepWaitingStatus:!0}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a)});return this.idlePollLoops.set(t,o),o}async sendShortcutInput(t,e){await this.executeIdleCommand(t,e)}async executeIdleCommand(t,e){const o=this.inputStreams.get(t);if(!o)return;const a=/\[(.+?)\]/g;let n=0;const i=[];let s=a.exec(e);for(;s!==null;){s.index>n&&i.push({type:"text",value:e.slice(n,s.index)});const r=s[1];if(r.startsWith("wait:")){const l=parseFloat(r.slice(5));isNaN(l)||i.push({type:"wait",value:l*1e3})}else{const l={enter:"\r",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C",tab:" ",esc:"\x1B",escape:"\x1B",space:" ","ctrl+c":""};i.push({type:"key",value:l[r.toLowerCase()]||r})}n=s.index+s[0].length,s=a.exec(e)}n<e.length&&i.push({type:"text",value:e.slice(n)});for(const r of i)if(r.type==="wait")await new Promise(l=>setTimeout(l,r.value));else{const l=String(r.value);o.enqueue({type:"user",message:{role:"user",content:[{type:"text",text:l}]}})}}updateActivity(t){this.lastActivityAt.set(t,Date.now())}async resumeSession(t,e,o){const a={sessionId:t,providerSessionId:e,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,a);try{await this.startSession(t,o),a.providerSessionId=e}catch(n){throw a.status="error",this.emit("status-change",t,"error"),n}}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await v("@anthropic-ai/claude-agent-sdk")}catch(t){throw new Error(`Failed to load @anthropic-ai/claude-agent-sdk. Please install: npm install @anthropic-ai/claude-agent-sdk. Original error: ${t}`)}return this.sdkModule}findClaudeExecutable(t){const e=this.extractExecutableCommand(t);if(c.isAbsolute(e)&&p.existsSync(e)){const i=this.resolveWindowsWrapper(e);if(i)return i;if(this.isWindowsWrapperPath(e)){console.warn(`[ClaudeSdkAdapter] Skipping wrapper script for Claude Code executable: ${e}`);return}return e}const o=this.resolveExecutableFromPath(e);if(o)return o;if(process.platform==="win32"&&this.shouldUseDefaultClaudeFallbacks(e)){const i=process.env.USERPROFILE||"",s=process.env.LOCALAPPDATA||"",r=process.env.APPDATA||"",l=[c.join(s,"Volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(s,"Volta","tools","image","packages","@anthropic-ai","claude-code","cli.js")];for(const u of l)if(p.existsSync(u))return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI via Volta: ${u}`),u;const d=[c.join(r,"npm","node_modules","@anthropic-ai","claude-code","cli.js"),c.join(s,"Programs","claude-code","claude.exe"),c.join(i,".local","bin","claude.exe")];for(const u of d)if(u&&p.existsSync(u))return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI: ${u}`),u}const a=process.env.HOME||"",n=[c.join(a,".local","bin","claude"),c.join(a,".npm-global","bin","claude"),c.join(a,".local","share","mise","shims","claude"),c.join(a,".asdf","shims","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude","/usr/bin/claude","/usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js","/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js",c.join(a,".local","share","volta","tools","shared","@anthropic-ai","claude-code","cli.js"),c.join(a,".volta","tools","shared","@anthropic-ai","claude-code","cli.js")];if(this.shouldUseDefaultClaudeFallbacks(e)){for(const i of n)if(i&&p.existsSync(i))return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI: ${i}`),i}if(this.shouldUseDefaultClaudeFallbacks(e))try{const i=k("npm root -g",{encoding:"utf8",timeout:5e3}).trim(),s=c.join(i,"@anthropic-ai","claude-code","cli.js");if(p.existsSync(s))return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI via npm root: ${s}`),s}catch{}console.warn(`[ClaudeSdkAdapter] Claude Code executable not found for command: ${e}`)}extractExecutableCommand(t){const o=((t||"claude").trim()||"claude").match(/^\s*(?:"([^"]+)"|'([^']+)'|(\S+))/);return o?.[1]||o?.[2]||o?.[3]||"claude"}resolveExecutableFromPath(t){const e=process.env.PATH||"";if(!e)return;const o=c.extname(t).length>0,a=process.platform==="win32"?this.getWindowsPathExtensions(o):[""];for(const n of e.split(c.delimiter))if(n)for(const i of a){const s=c.join(n,`${t}${i}`);if(p.existsSync(s)){if(this.isWindowsWrapperPath(s)){const r=this.resolveWindowsWrapper(s);if(r)return r;continue}return console.log(`[ClaudeSdkAdapter] Found Claude Code CLI via PATH: ${s}`),s}}}getWindowsPathExtensions(t){return t?[""]:(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM;.PS1").split(";").map(o=>o.trim()).filter(o=>o.length>0)}shouldUseDefaultClaudeFallbacks(t){return["claude","claude-code","claudecode"].includes(t.toLowerCase())}isWindowsWrapperPath(t){const e=c.extname(t).toLowerCase();return[".cmd",".bat",".ps1"].includes(e)}resolveWindowsWrapper(t){if(this.isWindowsWrapperPath(t))return this.resolveCliJsFromWrapper(t)}resolveCliJsFromWrapper(t){try{if(p.readFileSync(t,"utf8").includes("volta run")){const n=c.join(process.env.LOCALAPPDATA||"","Volta","tools","shared","@anthropic-ai","claude-code","cli.js");if(p.existsSync(n))return n}const o=c.dirname(t),a=c.join(o,"node_modules","@anthropic-ai","claude-code","cli.js");if(p.existsSync(a))return a}catch{}}buildQueryOptions(t,e,o){const a={cwd:e.workingDirectory,abortController:o,settingSources:["user","project","local"],includePartialMessages:!0},n=this.findClaudeExecutable(e.command);if(n?(a.pathToClaudeCodeExecutable=n,console.log(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u4F7F\u7528 Claude Code \u53EF\u6267\u884C\u6587\u4EF6 \u2605\u2605\u2605 path="${n}"`)):console.warn(`[ClaudeSdkAdapter] \u2605\u2605\u2605 \u8B66\u544A\uFF1A\u672A\u627E\u5230 Claude Code \u53EF\u6267\u884C\u6587\u4EF6 \u2605\u2605\u2605 command="${e.command}"`),e.model&&(a.model=e.model),e.maxTurns&&e.maxTurns>0&&(a.maxTurns=e.maxTurns),e.mcpConfigPath)try{const i=p.readFileSync(e.mcpConfigPath,"utf-8"),s=JSON.parse(i);a.mcpServers={...e.extraMcpServers,...s.mcpServers}}catch{a.mcpServers=e.extraMcpServers||{}}else a.mcpServers=e.extraMcpServers||{};return e.allowedTools&&e.allowedTools.length>0?a.allowedTools=e.allowedTools:a.allowedTools=["Read","Write","Edit","Bash","Glob","Grep","WebSearch","WebFetch","Task","NotebookEdit","LSP","Skill","mcp__*"],a.env={...process.env,...e.envOverrides},a.canUseTool=this.createPermissionHandler(t,e.autoAccept),a}createPermissionHandler(t,e){return async(o,a,n)=>o==="AskUserQuestion"||o==="ask_user_question"?new Promise(i=>{this.pendingQuestions.set(t,{resolve:i,toolInput:a}),this.emit("ask-user-question",{sessionId:t,toolCallId:this.activeToolUseIds.get(t)||void 0,questions:a.questions})}):e?{behavior:"allow",updatedInput:a}:new Promise(i=>{this.pendingPermissions.set(t,{resolve:i,toolInput:a}),this.emit("permission-request",{sessionId:t,toolName:o,toolInput:a,permissionPrompt:`Allow ${o}?`})})}async consumeStream(t,e){const o=this.sessions.get(t);if(o)try{for await(const a of e){const n=a;this.handleSdkMessage(t,o,n)}}catch(a){if(this.abortControllers.get(t)?.signal.aborted)return;const n=a instanceof Error?a.message:String(a);this.emitEvent(t,{type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Stream error: ${n}`}})}}applyUsage(t,e){e&&(Number.isFinite(e.input_tokens)&&(t.totalUsage.inputTokens=Math.max(t.totalUsage.inputTokens,e.input_tokens??0)),Number.isFinite(e.output_tokens)&&(t.totalUsage.outputTokens=Math.max(t.totalUsage.outputTokens,e.output_tokens??0)))}handleSdkMessage(t,e,o){const a=new Date().toISOString();switch(console.log(`[ClaudeSdkAdapter] Received message type: "${o.type}", subtype: "${o.subtype||""}"`),o.tool_name&&console.log(`[ClaudeSdkAdapter] Tool name: "${o.tool_name}"`),o.type){case"text":o.delta&&(e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),this.emitEvent(t,{type:"text_delta",sessionId:t,timestamp:a,data:{text:o.delta}}));break;case"thinking":e.status!=="thinking"&&(e.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t)),(o.content||o.delta)&&this.emitEvent(t,{type:"thinking",sessionId:t,timestamp:a,data:{text:o.delta||o.content}});break;case"tool_use":case"tool_use_start":{const n={...g(o.tool_name,o.tool_input),actionId:o.tool_use_id},i=n.actionType==="idle"?"waiting_input":"tool_using";e.status=i;const s=this.extractMcpServerName(o.tool_name||"");this.emit("status-change",t,i,{actionType:n.actionType,actionLabel:n.actionLabel,actionDetail:n.actionDetail,actionId:n.actionId,usage:e.totalUsage,...s?{metadata:{mcpServer:s}}:{}}),n.actionType!=="idle"&&this.stopIdleDetection(t),this.handleToolUse(t,e,o,a)}break;case"tool_result":case"tool_use_end":this.emitEvent(t,{type:"tool_use_end",sessionId:t,timestamp:a,data:{toolName:o.tool_name,toolResult:o.tool_result,isError:o.is_error,toolUseId:o.tool_use_id}});break;case"result":{const n=o.subtype==="success";this.applyUsage(e,o.usage),this.emitEvent(t,{type:"turn_complete",sessionId:t,timestamp:a,data:{usage:e.totalUsage,text:n?o.result:void 0}}),e.status="waiting_input",(()=>{const s=this.idleCommands.get(t);return!!(s?.idleInputCommand&&this.isMessagePollingIdleCommand(s.idleInputCommand))})()?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:e.totalUsage}):this.emit("status-change",t,"waiting_input",{usage:e.totalUsage}),this.idleCommands.has(t)&&this.startIdleDetection(t)}break;case"system":o.subtype==="init"&&console.log(`[ClaudeSdkAdapter] Session ${t} initialized: model=${o.model}, tools=${o.tools?.length||0}`);break;case"assistant":if(this.applyUsage(e,o.message?.usage),o.message?.content){const n=o.message.content.filter(i=>i.type==="text"&&i.text).map(i=>i.text||"").join("");n&&e.messages.push({id:h(),sessionId:t,role:"assistant",content:n,timestamp:a})}break;case"user":o.tool_use_result;break;case"error":e.status="error",this.emit("status-change",t,"error"),this.emitEvent(t,{type:"error",sessionId:t,timestamp:a,data:{text:o.content||"Unknown error"}});break;case"stream_event":this.handleStreamEvent(t,e,o,a);break;default:console.log(`[ClaudeSdkAdapter] Unknown message type: ${o.type}`,o)}}handleToolUse(t,e,o,a){const n=this.recentToolNames.get(t),i=this.extractToolNameSuffix(o.tool_name||"");if(n&&Date.now()-n.time<3e4&&n.name===i){console.log(`[ClaudeSdkAdapter] Tool use ${o.tool_name} matches recent stream_event (${n.name}), skipping duplicate event`),this.recentToolNames.delete(t),this.activeToolUseIds.delete(t),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${o.tool_name}: ${JSON.stringify(o.tool_input).slice(0,100)}`,timestamp:a,toolName:o.tool_name,toolInput:o.tool_input,toolUseId:o.tool_use_id});return}this.recentToolNames.delete(t),this.activeToolUseIds.delete(t);const s=g(o.tool_name,o.tool_input);console.log(`[ClaudeSdkAdapter] Tool use: ${o.tool_name}, actionType: ${s.actionType}, actionDetail: ${s.actionDetail}`);const r=this.extractMcpServerName(o.tool_name||"");this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:a,data:{toolName:o.tool_name,toolInput:o.tool_input,toolUseId:o.tool_use_id,actionType:s.actionType,actionLabel:s.actionLabel,actionDetail:s.actionDetail,...r?{metadata:{mcpServer:r}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${o.tool_name}: ${JSON.stringify(o.tool_input).slice(0,100)}`,timestamp:a,toolName:o.tool_name,toolInput:o.tool_input,toolUseId:o.tool_use_id})}handleStreamEvent(t,e,o,a){const n=o.event;if(n){if(n.type==="content_block_start"){const i=n.content_block;if(i?.type==="tool_use"&&i.name){const s=i.name,r=i.id||`stream_${Date.now()}`;console.log(`[ClaudeSdkAdapter] Tool use started via stream_event: ${s} (id: ${r})`),this.activeToolUseIds.set(t,r);const l=this.extractToolNameSuffix(s);this.recentToolNames.set(t,{name:l,time:Date.now()});const d=`${t}:${r}`;this.toolInputBuffers.set(d,"")}}if(n.type==="content_block_delta"&&n.delta?.type==="input_json_delta"&&n.delta.partial_json){const i=this.activeToolUseIds.get(t);if(i){const s=`${t}:${i}`,r=this.toolInputBuffers.get(s)||"";this.toolInputBuffers.set(s,r+n.delta.partial_json),console.log(`[ClaudeSdkAdapter] Tool input delta at index ${n.index}, buffer length: ${r.length+n.delta.partial_json.length}`)}}if(n.type==="content_block_stop"){const i=this.activeToolUseIds.get(t),s=this.recentToolNames.get(t);if(i&&s){const r=`${t}:${i}`,l=this.toolInputBuffers.get(r)||"";console.log(`[ClaudeSdkAdapter] Content block stopped at index ${n.index}, collected JSON length: ${l.length}`);let d;if(l)try{d=JSON.parse(l),console.log("[ClaudeSdkAdapter] Parsed tool input:",JSON.stringify(d).slice(0,200))}catch{console.warn("[ClaudeSdkAdapter] Failed to parse tool input JSON:",l.slice(0,100))}const u={...g(s.name,d),actionId:i},m=this.extractMcpServerName(s.name);e.status="tool_using",this.emit("status-change",t,"tool_using",{actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,usage:e.totalUsage,...m?{metadata:{mcpServer:m}}:{}}),this.stopIdleDetection(t),this.emitEvent(t,{type:"tool_use_start",sessionId:t,timestamp:a,data:{toolName:s.name,toolInput:d,toolUseId:i,actionType:u.actionType,actionLabel:u.actionLabel,actionDetail:u.actionDetail,actionId:u.actionId,...m?{metadata:{mcpServer:m}}:{}}}),e.messages.push({id:h(),sessionId:t,role:"tool_use",content:`${s.name}: ${l.slice(0,100)}`,timestamp:a,toolName:s.name,toolInput:d,toolUseId:i}),this.toolInputBuffers.delete(r),this.activeToolUseIds.delete(t)}}}}extractMcpServerName(t){if(t.startsWith("mcp__")){const e=t.split("__");if(e.length>=3)return e[1]}}extractToolNameSuffix(t){if(t.includes("__"))return t.split("__").pop()||t;if(t.includes("-mcp__")){const e=t.indexOf("-mcp__");return t.substring(e+6)}return t}emitEvent(t,e){this.emit("event",e)}cleanupSession(t){this.stopIdleDetection(t),this.sessions.delete(t),this.sdkQueries.delete(t),this.inputStreams.delete(t),this.abortControllers.delete(t),this.pendingPermissions.delete(t),this.pendingQuestions.delete(t),this.idleCommands.delete(t),this.idlePollLoops.delete(t),this.sessionAgentIds.delete(t),this.lastActivityAt.delete(t)}}export{M as ClaudeSdkAdapter};
4
4
 
@@ -5,6 +5,8 @@ export declare class CodexSdkAdapter extends EventEmitter implements BaseProvide
5
5
  readonly providerId = "codex";
6
6
  readonly displayName = "Codex";
7
7
  private sessions;
8
+
9
+ private listenerWakeHooks;
8
10
  private sdkModule?;
9
11
  startSession(sessionId: string, config: AdapterSessionConfig): Promise<void>;
10
12
  sendMessage(sessionId: string, message: string): Promise<void>;
@@ -1,4 +1,4 @@
1
- import{EventEmitter as b}from"node:events";import{v4 as p}from"uuid";import{IdlePollLoop as m}from"./idle-poll-loop.js";import{getToolActionInfo as C}from"./types.js";function y(r){return r instanceof Error&&"code"in r&&typeof r.code=="string"}function _(r,t){return y(r)&&r.code==="ERR_MODULE_NOT_FOUND"&&r.message.includes(t)}const d=1500;function g(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function v(r){return g(r)?r:{value:r}}function E(r){if(typeof r=="string")return r;try{return JSON.stringify(r)}catch{return String(r)}}function T(r,t){const n={};for(const[e,s]of Object.entries(r))typeof s=="string"&&(n[e]=s);return{...n,...t??{}}}function D(r){const t=[];let n="",e=null,s=!1;for(const a of r.trim()){if(s){n+=a,s=!1;continue}if(a==="\\"&&e!=="'"){s=!0;continue}if((a==='"'||a==="'")&&e===null){e=a;continue}if(a===e){e=null;continue}if(/\s/.test(a)&&e===null){n.length>0&&(t.push(n),n="");continue}n+=a}return s&&(n+="\\"),n.length>0&&t.push(n),t}function f(r){const t=(r||"").replace(/\\/g,"/").toLowerCase();return(t.split("/").pop()||t).replace(/\.(cmd|exe)$/i,"")}function P(r){return r.includes("/")||r.includes("\\")||/^[a-zA-Z]:/.test(r)}function S(r){const t=D(r||"codex");if(t.length===0)return{args:[]};const[n,e,...s]=t,a=f(n);return P(n)?{executablePath:n,args:t.slice(1)}:(a==="npx"||a==="pnpm"||a==="yarn"||a==="bun")&&f(e)==="codex"?{args:s}:a==="codex"?{args:t.slice(1)}:{executablePath:n,args:t.slice(1)}}function w(r){if(/^(true|1|yes)$/i.test(r))return!0;if(/^(false|0|no)$/i.test(r))return!1}function c(r){return r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function A(r,t,n){const e=t.split(".").filter(Boolean);if(e.length===0)return;let s=r;for(const o of e.slice(0,-1)){const l=s[o];g(l)||(s[o]={}),s=s[o]}const a=c(n),i=w(a);s[e[e.length-1]]=i??a}function u(r,t,n){const e=r[t],s=`${n}=`;return e.startsWith(s)?{value:e.slice(s.length),nextIndex:t}:{value:r[t+1],nextIndex:t+1}}function k(r){const t={additionalDirectories:[],config:{}};for(let n=0;n<r.length;n++){const e=r[n];switch(e){case"--model":case"-m":{const s=u(r,n,e);t.model=s.value,n=s.nextIndex;break}case"--sandbox":{const s=u(r,n,e);(s.value==="read-only"||s.value==="workspace-write"||s.value==="danger-full-access")&&(t.sandboxMode=s.value),n=s.nextIndex;break}case"--skip-git-repo-check":t.skipGitRepoCheck=!0;break;case"--add-dir":{const s=u(r,n,e);s.value&&t.additionalDirectories.push(s.value),n=s.nextIndex;break}case"--config":case"-c":{const s=u(r,n,e);if(s.value){const a=s.value.indexOf("=");if(a>0){const i=s.value.slice(0,a),o=s.value.slice(a+1);if(i==="model_reasoning_effort"){const l=c(o);(l==="minimal"||l==="low"||l==="medium"||l==="high"||l==="xhigh")&&(t.modelReasoningEffort=l)}else if(i==="web_search"){const l=c(o);(l==="disabled"||l==="cached"||l==="live")&&(t.webSearchMode=l)}else if(i==="sandbox_workspace_write.network_access")t.networkAccessEnabled=w(c(o));else if(i==="approval_policy"){const l=c(o);(l==="never"||l==="on-request"||l==="on-failure"||l==="untrusted")&&(t.approvalPolicy=l)}else A(t.config,i,o)}}n=s.nextIndex;break}default:if(e.startsWith("--model="))t.model=e.slice(8);else if(e.startsWith("--sandbox=")){const s=e.slice(10);(s==="read-only"||s==="workspace-write"||s==="danger-full-access")&&(t.sandboxMode=s)}}}return t}function M(r){return{inputTokens:r?.input_tokens??0,outputTokens:r?.output_tokens??0}}class N extends b{constructor(){super(...arguments),this.providerId="codex",this.displayName="Codex",this.sessions=new Map}async startSession(t,n){console.log(`[CodexSdkAdapter] \u2605\u2605\u2605 \u542F\u52A8 Codex SDK \u4F1A\u8BDD \u2605\u2605\u2605 sessionId="${t}", workingDirectory="${n.workingDirectory}"`);const e={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};try{const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(n));this.warnUnsupportedMcpConfig(n);const i=a.startThread(this.buildThreadOptions(n)),o={adapterSession:e,config:n,thread:i,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()};this.sessions.set(t,o),n.initialPrompt?queueMicrotask(()=>{this.sendMessage(t,n.initialPrompt).catch(l=>{const x=l instanceof Error?l.message:String(l),h=this.sessions.get(t);h&&(h.adapterSession.status="error"),this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex initial prompt failed: ${x}`}})})}):(e.status="waiting_input",this.emit("status-change",t,"waiting_input"))}catch(s){const a=s instanceof Error?s.message:String(s);throw e.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex start failed: ${a}`}}),s}}async sendMessage(t,n){const e=this.sessions.get(t);if(!e)throw new Error(`Session ${t} not found`);if(e.runningTurn)throw new Error(`Session ${t} already has a running Codex turn`);const s={id:p(),sessionId:t,role:"user",content:n,timestamp:new Date().toISOString()};e.adapterSession.messages.push(s),this.emit("conversation-message",t,s),e.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t),e.lastActivityAt=Date.now();const a=new AbortController;e.currentAbortController=a,e.runningTurn=this.runTurn(t,e,n,a);try{await e.runningTurn}finally{e.runningTurn=void 0,e.currentAbortController=void 0}}async sendConfirmation(t,n){}async sendQuestionAnswer(t,n){}setIdleCommands(t,n){const e=this.sessions.get(t);e&&(e.idleCommands=n,e.adapterSession.status==="waiting_input"&&(n.idleInputCommand||n.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){this.sessions.get(t)?.currentAbortController?.abort()}async terminateSession(t){const n=this.sessions.get(t);n&&(this.stopIdleDetection(t),n.terminating=!0,n.currentAbortController?.abort(),n.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),this.sessions.delete(t))}async resumeSession(t,n,e){const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(e));this.warnUnsupportedMcpConfig(e);const i=a.resumeThread(n,this.buildThreadOptions(e)),o={sessionId:t,providerSessionId:n,status:"waiting_input",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,{adapterSession:o,config:e,thread:i,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()}),this.emit("status-change",t,"waiting_input")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.thread.id??void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){}cleanup(){for(const[t]of this.sessions)this.terminateSession(t);this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await import("@openai/codex-sdk")}catch(t){throw _(t,"@openai/codex-sdk")?new Error(["Codex SDK provider is not installed.","","aws-runtime-bridge keeps heavy provider SDKs optional to reduce global install size.",'To use SDK mode with command "codex", install:',""," npm install -g @openai/codex-sdk","","If aws-runtime-bridge is installed locally, install the SDK in the same project:",""," npm install @openai/codex-sdk","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
2
- `)):t}return this.sdkModule}buildCodexOptions(t){const n=T(process.env,t.envOverrides),e={env:n},s=n.CODEX_API_KEY||n.OPENAI_API_KEY;s&&(e.apiKey=s);const a=n.CODEX_BASE_URL||n.OPENAI_BASE_URL;a&&(e.baseUrl=a);const i=S(t.command);t.executablePath?e.codexPathOverride=t.executablePath:i.executablePath&&(e.codexPathOverride=i.executablePath);const o=k(i.args);return Object.keys(o.config).length>0&&(e.config=o.config),e}warnUnsupportedMcpConfig(t){const n=!!(t.extraMcpServers&&Object.keys(t.extraMcpServers).length>0);(t.mcpConfigPath||n)&&console.warn("[CodexSdkAdapter] Codex SDK ThreadOptions do not expose dynamic MCP server injection; mcpConfigPath/extraMcpServers are ignored for Codex SDK sessions.")}buildThreadOptions(t){const n=S(t.command),e=k(n.args),s={workingDirectory:t.workingDirectory,skipGitRepoCheck:e.skipGitRepoCheck??!1,approvalPolicy:e.approvalPolicy??(t.autoAccept?"never":"on-request")};return(t.model||e.model)&&(s.model=t.model??e.model),(t.additionalDirectories||e.additionalDirectories.length>0)&&(s.additionalDirectories=[...t.additionalDirectories??[],...e.additionalDirectories]),e.sandboxMode&&(s.sandboxMode=e.sandboxMode),e.modelReasoningEffort&&(s.modelReasoningEffort=e.modelReasoningEffort),e.networkAccessEnabled!==void 0&&(s.networkAccessEnabled=e.networkAccessEnabled),e.webSearchMode&&(s.webSearchMode=e.webSearchMode),e.webSearchEnabled!==void 0&&(s.webSearchEnabled=e.webSearchEnabled),s}async runTurn(t,n,e,s){try{const a=await n.thread.runStreamed(e,{signal:s.signal});for await(const i of a.events)this.handleThreadEvent(t,n,i)}catch(a){if(s.signal.aborted){if(!this.sessions.has(t)||n.terminating||n.adapterSession.status==="terminated")return;n.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input");return}const i=a instanceof Error?a.message:String(a);n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:i}})}}handleThreadEvent(t,n,e){const s=new Date().toISOString();switch(e.type){case"thread.started":n.adapterSession.providerSessionId=e.thread_id;break;case"turn.started":n.adapterSession.status="thinking",this.emit("status-change",t,"thinking");break;case"item.started":case"item.updated":case"item.completed":this.handleThreadItem(t,n,e.item,e.type,s);break;case"turn.completed":this.completeTurn(t,n,e.usage,s);break;case"turn.failed":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.error.message}});break;case"error":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.message}});break}}handleThreadItem(t,n,e,s,a){switch(e.type){case"agent_message":this.emitTextDelta(t,n,e.id,e.text,a);break;case"reasoning":this.emitReasoningDelta(t,n,e.id,e.text,a);break;case"command_execution":this.handleToolLikeItem(t,n,{id:e.id,toolName:"bash",toolInput:{command:e.command},result:e.aggregated_output,isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a});break;case"mcp_tool_call":{const i={mcpServer:e.server};this.handleToolLikeItem(t,n,{id:e.id,toolName:e.tool,toolInput:v(e.arguments),result:e.error?.message??E(e.result),isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a,metadata:i});break}case"file_change":this.handleToolLikeItem(t,n,{id:e.id,toolName:"apply_patch",toolInput:{changes:e.changes},result:e.status,isError:e.status==="failed",isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"web_search":this.handleToolLikeItem(t,n,{id:e.id,toolName:"web_search",toolInput:{query:e.query},result:e.query,isError:!1,isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"todo_list":this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:e.items.map(i=>`${i.completed?"\u2713":"\u2022"} ${i.text}`).join(`
3
- `)}});break;case"error":this.emitEvent({type:"error",sessionId:t,timestamp:a,data:{text:e.message}});break}}emitTextDelta(t,n,e,s,a){const i=n.emittedTextLengths.get(e)??0,o=s.slice(i);n.emittedTextLengths.set(e,s.length),o&&(n.currentAssistantText+=o,this.emitEvent({type:"text_delta",sessionId:t,timestamp:a,data:{text:o}}))}emitReasoningDelta(t,n,e,s,a){const i=n.emittedReasoningLengths.get(e)??0,o=s.slice(i);n.emittedReasoningLengths.set(e,s.length),o&&this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:o}})}handleToolLikeItem(t,n,e){if(!n.emittedToolStarts.has(e.id)){n.emittedToolStarts.add(e.id);const s={...C(e.toolName,e.toolInput,e.metadata),actionId:e.id};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id,...s}}),this.emit("status-change",t,"tool_using",{...s,usage:n.adapterSession.totalUsage}),n.adapterSession.messages.push({id:p(),sessionId:t,role:"tool_use",content:`${e.toolName}: ${JSON.stringify(e.toolInput).slice(0,100)}`,timestamp:e.timestamp,toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id})}e.isRunning||e.eventType!=="item.completed"||(this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolResult:e.result,isError:e.isError,toolUseId:e.id}}),n.emittedToolStarts.delete(e.id))}completeTurn(t,n,e,s){const a=M(e);n.adapterSession.totalUsage=a,n.currentAssistantText&&(n.adapterSession.messages.push({id:p(),sessionId:t,role:"assistant",content:n.currentAssistantText,timestamp:s}),n.currentAssistantText=""),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:s,data:{usage:a}}),n.adapterSession.status="waiting_input";const i=n.idleCommands?.idleInputCommand;!!(i&&this.isMessagePollingIdleCommand(i))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:a}):this.emit("status-change",t,"waiting_input"),n.lastActivityAt=Date.now(),this.startIdleDetection(t)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const n=this.sessions.get(t),e=n?.idleCommands?.idleInputCommand;if(!n||!e)return;if(this.isMessagePollingIdleCommand(e)){n.idlePollLoop||(n.idlePollLoop=new m({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),dispatchPollingPrompt:a=>this.sendIdlePrompt(t,a,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a),pollDelayMs:d,regularIdleDelayMs:d})),n.idlePollLoop.start();return}n.idlePollLoop||(n.idlePollLoop=new m({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),dispatchPollingPrompt:a=>this.sendIdlePrompt(t,a,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a),pollDelayMs:d,regularIdleDelayMs:d})),n.lastActivityAt=Date.now();const s=setInterval(()=>{this.checkIdleState(t)},500);n.idleTimer=s}stopIdleDetection(t){const n=this.sessions.get(t);n?.idlePollLoop?.stop(),n?.idleTimer&&(clearInterval(n.idleTimer),n.idleTimer=void 0)}checkIdleState(t){const n=this.sessions.get(t);if(!n||n.adapterSession.status!=="waiting_input"||!n.idleCommands?.idleInputCommand)return;const e=n.lastActivityAt??0;Date.now()-e<d||(n.lastActivityAt=Date.now(),this.sendIdlePrompt(t,n.idleCommands.idleInputCommand),this.stopIdleDetection(t))}async sendIdlePrompt(t,n,e){const s=this.sessions.get(t);if(!s||s.runningTurn)return;const a=this.toIdlePrompt(n);if(!a)return;e?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"));const i=new AbortController;s.currentAbortController=i,s.runningTurn=this.runTurn(t,s,a,i);try{await s.runningTurn}finally{s.runningTurn=void 0,s.currentAbortController=void 0}}toIdlePrompt(t){const n=t.trim();return this.isMessagePollingIdleCommand(n)?"\u7CFB\u7EDF\u63D0\u9192\uFF1A\u5F53\u524D\u5DE5\u4F5C\u5DF2\u5B8C\u6210\u6216\u8FD0\u884C\u65F6\u5DF2\u8FDB\u5165\u7A7A\u95F2\u72B6\u6001\u3002\u8BF7\u7ACB\u5373\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":n}isMessagePollingIdleCommand(t){const n=t.trim();if(!n)return!1;const e=n.toLowerCase();return e.includes("poll_message")||e.includes("get_message")||n.includes("\u53D6\u6D88\u606F")}}export{N as CodexSdkAdapter};
1
+ import{EventEmitter as C}from"node:events";import{v4 as p}from"uuid";import{IdlePollLoop as m}from"./idle-poll-loop.js";import{getToolActionInfo as y}from"./types.js";import{registerListenerWakeHook as _,unregisterListenerWakeHook as g}from"../services/browser-session-manager.js";function v(r){return r instanceof Error&&"code"in r&&typeof r.code=="string"}function D(r,t){return v(r)&&r.code==="ERR_MODULE_NOT_FOUND"&&r.message.includes(t)}const d=1500;function f(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function E(r){return f(r)?r:{value:r}}function T(r){if(typeof r=="string")return r;try{return JSON.stringify(r)}catch{return String(r)}}function P(r,t){const n={};for(const[e,s]of Object.entries(r))typeof s=="string"&&(n[e]=s);return{...n,...t??{}}}function A(r){const t=[];let n="",e=null,s=!1;for(const a of r.trim()){if(s){n+=a,s=!1;continue}if(a==="\\"&&e!=="'"){s=!0;continue}if((a==='"'||a==="'")&&e===null){e=a;continue}if(a===e){e=null;continue}if(/\s/.test(a)&&e===null){n.length>0&&(t.push(n),n="");continue}n+=a}return s&&(n+="\\"),n.length>0&&t.push(n),t}function k(r){const t=(r||"").replace(/\\/g,"/").toLowerCase();return(t.split("/").pop()||t).replace(/\.(cmd|exe)$/i,"")}function M(r){return r.includes("/")||r.includes("\\")||/^[a-zA-Z]:/.test(r)}function S(r){const t=A(r||"codex");if(t.length===0)return{args:[]};const[n,e,...s]=t,a=k(n);return M(n)?{executablePath:n,args:t.slice(1)}:(a==="npx"||a==="pnpm"||a==="yarn"||a==="bun")&&k(e)==="codex"?{args:s}:a==="codex"?{args:t.slice(1)}:{executablePath:n,args:t.slice(1)}}function w(r){if(/^(true|1|yes)$/i.test(r))return!0;if(/^(false|0|no)$/i.test(r))return!1}function c(r){return r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'")?r.slice(1,-1):r}function O(r,t,n){const e=t.split(".").filter(Boolean);if(e.length===0)return;let s=r;for(const l of e.slice(0,-1)){const o=s[l];f(o)||(s[l]={}),s=s[l]}const a=c(n),i=w(a);s[e[e.length-1]]=i??a}function u(r,t,n){const e=r[t],s=`${n}=`;return e.startsWith(s)?{value:e.slice(s.length),nextIndex:t}:{value:r[t+1],nextIndex:t+1}}function x(r){const t={additionalDirectories:[],config:{}};for(let n=0;n<r.length;n++){const e=r[n];switch(e){case"--model":case"-m":{const s=u(r,n,e);t.model=s.value,n=s.nextIndex;break}case"--sandbox":{const s=u(r,n,e);(s.value==="read-only"||s.value==="workspace-write"||s.value==="danger-full-access")&&(t.sandboxMode=s.value),n=s.nextIndex;break}case"--skip-git-repo-check":t.skipGitRepoCheck=!0;break;case"--add-dir":{const s=u(r,n,e);s.value&&t.additionalDirectories.push(s.value),n=s.nextIndex;break}case"--config":case"-c":{const s=u(r,n,e);if(s.value){const a=s.value.indexOf("=");if(a>0){const i=s.value.slice(0,a),l=s.value.slice(a+1);if(i==="model_reasoning_effort"){const o=c(l);(o==="minimal"||o==="low"||o==="medium"||o==="high"||o==="xhigh")&&(t.modelReasoningEffort=o)}else if(i==="web_search"){const o=c(l);(o==="disabled"||o==="cached"||o==="live")&&(t.webSearchMode=o)}else if(i==="sandbox_workspace_write.network_access")t.networkAccessEnabled=w(c(l));else if(i==="approval_policy"){const o=c(l);(o==="never"||o==="on-request"||o==="on-failure"||o==="untrusted")&&(t.approvalPolicy=o)}else O(t.config,i,l)}}n=s.nextIndex;break}default:if(e.startsWith("--model="))t.model=e.slice(8);else if(e.startsWith("--sandbox=")){const s=e.slice(10);(s==="read-only"||s==="workspace-write"||s==="danger-full-access")&&(t.sandboxMode=s)}}}return t}function L(r){return{inputTokens:r?.input_tokens??0,outputTokens:r?.output_tokens??0}}class $ extends C{constructor(){super(...arguments),this.providerId="codex",this.displayName="Codex",this.sessions=new Map,this.listenerWakeHooks=new Map}async startSession(t,n){console.log(`[CodexSdkAdapter] \u2605\u2605\u2605 \u542F\u52A8 Codex SDK \u4F1A\u8BDD \u2605\u2605\u2605 sessionId="${t}", workingDirectory="${n.workingDirectory}"`);const e={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};try{const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(n));this.warnUnsupportedMcpConfig(n);const i=a.startThread(this.buildThreadOptions(n)),l={adapterSession:e,config:n,thread:i,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()};if(this.sessions.set(t,l),n.agentId){const o=()=>{this.sessions.get(t)?.idlePollLoop?.start()};this.listenerWakeHooks.set(t,o),_(n.agentId,o)}n.initialPrompt?queueMicrotask(()=>{this.sendMessage(t,n.initialPrompt).catch(o=>{const b=o instanceof Error?o.message:String(o),h=this.sessions.get(t);h&&(h.adapterSession.status="error"),this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex initial prompt failed: ${b}`}})})}):(e.status="waiting_input",this.emit("status-change",t,"waiting_input"))}catch(s){n.agentId&&g(n.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t);const a=s instanceof Error?s.message:String(s);throw e.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:`Codex start failed: ${a}`}}),s}}async sendMessage(t,n){const e=this.sessions.get(t);if(!e)throw new Error(`Session ${t} not found`);if(e.runningTurn)throw new Error(`Session ${t} already has a running Codex turn`);const s={id:p(),sessionId:t,role:"user",content:n,timestamp:new Date().toISOString()};e.adapterSession.messages.push(s),this.emit("conversation-message",t,s),e.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),this.stopIdleDetection(t),e.lastActivityAt=Date.now();const a=new AbortController;e.currentAbortController=a,e.runningTurn=this.runTurn(t,e,n,a);try{await e.runningTurn}finally{e.runningTurn=void 0,e.currentAbortController=void 0}}async sendConfirmation(t,n){}async sendQuestionAnswer(t,n){}setIdleCommands(t,n){const e=this.sessions.get(t);e&&(e.idleCommands=n,e.adapterSession.status==="waiting_input"&&(n.idleInputCommand||n.nonInputCommand)&&this.startIdleDetection(t))}async abortCurrentTurn(t){this.sessions.get(t)?.currentAbortController?.abort()}async terminateSession(t){const n=this.sessions.get(t);n&&(this.stopIdleDetection(t),n.terminating=!0,n.currentAbortController?.abort(),n.adapterSession.status="terminated",this.emit("status-change",t,"terminated"),this.emitEvent({type:"session_complete",sessionId:t,timestamp:new Date().toISOString(),data:{exitCode:0}}),n.config.agentId&&g(n.config.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),this.sessions.delete(t))}async resumeSession(t,n,e){const s=await this.loadSdk(),a=new s.Codex(this.buildCodexOptions(e));this.warnUnsupportedMcpConfig(e);const i=a.resumeThread(n,this.buildThreadOptions(e)),l={sessionId:t,providerSessionId:n,status:"waiting_input",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0}};this.sessions.set(t,{adapterSession:l,config:e,thread:i,terminating:!1,currentAssistantText:"",emittedToolStarts:new Set,emittedTextLengths:new Map,emittedReasoningLengths:new Map,lastActivityAt:Date.now()}),this.emit("status-change",t,"waiting_input")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.get(t)?.thread.id??void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}getSessionPid(t){}cleanup(){for(const[t]of this.sessions)this.terminateSession(t);this.sessions.clear()}async loadSdk(){if(!this.sdkModule)try{this.sdkModule=await import("@openai/codex-sdk")}catch(t){throw D(t,"@openai/codex-sdk")?new Error(["Codex SDK provider is not installed.","","aws-runtime-bridge keeps heavy provider SDKs optional to reduce global install size.",'To use SDK mode with command "codex", install:',""," npm install -g @openai/codex-sdk","","If aws-runtime-bridge is installed locally, install the SDK in the same project:",""," npm install @openai/codex-sdk","",`Original error: ${t instanceof Error?t.message:String(t)}`].join(`
2
+ `)):t}return this.sdkModule}buildCodexOptions(t){const n=P(process.env,t.envOverrides),e={env:n},s=n.CODEX_API_KEY||n.OPENAI_API_KEY;s&&(e.apiKey=s);const a=n.CODEX_BASE_URL||n.OPENAI_BASE_URL;a&&(e.baseUrl=a);const i=S(t.command);t.executablePath?e.codexPathOverride=t.executablePath:i.executablePath&&(e.codexPathOverride=i.executablePath);const l=x(i.args);return Object.keys(l.config).length>0&&(e.config=l.config),e}warnUnsupportedMcpConfig(t){const n=!!(t.extraMcpServers&&Object.keys(t.extraMcpServers).length>0);(t.mcpConfigPath||n)&&console.warn("[CodexSdkAdapter] Codex SDK ThreadOptions do not expose dynamic MCP server injection; mcpConfigPath/extraMcpServers are ignored for Codex SDK sessions.")}buildThreadOptions(t){const n=S(t.command),e=x(n.args),s={workingDirectory:t.workingDirectory,skipGitRepoCheck:e.skipGitRepoCheck??!1,approvalPolicy:e.approvalPolicy??(t.autoAccept?"never":"on-request")};return(t.model||e.model)&&(s.model=t.model??e.model),(t.additionalDirectories||e.additionalDirectories.length>0)&&(s.additionalDirectories=[...t.additionalDirectories??[],...e.additionalDirectories]),e.sandboxMode&&(s.sandboxMode=e.sandboxMode),e.modelReasoningEffort&&(s.modelReasoningEffort=e.modelReasoningEffort),e.networkAccessEnabled!==void 0&&(s.networkAccessEnabled=e.networkAccessEnabled),e.webSearchMode&&(s.webSearchMode=e.webSearchMode),e.webSearchEnabled!==void 0&&(s.webSearchEnabled=e.webSearchEnabled),s}async runTurn(t,n,e,s){try{const a=await n.thread.runStreamed(e,{signal:s.signal});for await(const i of a.events)this.handleThreadEvent(t,n,i)}catch(a){if(s.signal.aborted){if(!this.sessions.has(t)||n.terminating||n.adapterSession.status==="terminated")return;n.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input");return}const i=a instanceof Error?a.message:String(a);n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:new Date().toISOString(),data:{text:i}})}}handleThreadEvent(t,n,e){const s=new Date().toISOString();switch(e.type){case"thread.started":n.adapterSession.providerSessionId=e.thread_id;break;case"turn.started":n.adapterSession.status="thinking",this.emit("status-change",t,"thinking");break;case"item.started":case"item.updated":case"item.completed":this.handleThreadItem(t,n,e.item,e.type,s);break;case"turn.completed":this.completeTurn(t,n,e.usage,s);break;case"turn.failed":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.error.message}});break;case"error":n.adapterSession.status="error",this.emit("status-change",t,"error"),this.emitEvent({type:"error",sessionId:t,timestamp:s,data:{text:e.message}});break}}handleThreadItem(t,n,e,s,a){switch(e.type){case"agent_message":this.emitTextDelta(t,n,e.id,e.text,a);break;case"reasoning":this.emitReasoningDelta(t,n,e.id,e.text,a);break;case"command_execution":this.handleToolLikeItem(t,n,{id:e.id,toolName:"bash",toolInput:{command:e.command},result:e.aggregated_output,isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a});break;case"mcp_tool_call":{const i={mcpServer:e.server};this.handleToolLikeItem(t,n,{id:e.id,toolName:e.tool,toolInput:E(e.arguments),result:e.error?.message??T(e.result),isError:e.status==="failed",isRunning:e.status==="in_progress",eventType:s,timestamp:a,metadata:i});break}case"file_change":this.handleToolLikeItem(t,n,{id:e.id,toolName:"apply_patch",toolInput:{changes:e.changes},result:e.status,isError:e.status==="failed",isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"web_search":this.handleToolLikeItem(t,n,{id:e.id,toolName:"web_search",toolInput:{query:e.query},result:e.query,isError:!1,isRunning:s!=="item.completed",eventType:s,timestamp:a});break;case"todo_list":this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:e.items.map(i=>`${i.completed?"\u2713":"\u2022"} ${i.text}`).join(`
3
+ `)}});break;case"error":this.emitEvent({type:"error",sessionId:t,timestamp:a,data:{text:e.message}});break}}emitTextDelta(t,n,e,s,a){const i=n.emittedTextLengths.get(e)??0,l=s.slice(i);n.emittedTextLengths.set(e,s.length),l&&(n.currentAssistantText+=l,this.emitEvent({type:"text_delta",sessionId:t,timestamp:a,data:{text:l}}))}emitReasoningDelta(t,n,e,s,a){const i=n.emittedReasoningLengths.get(e)??0,l=s.slice(i);n.emittedReasoningLengths.set(e,s.length),l&&this.emitEvent({type:"thinking",sessionId:t,timestamp:a,data:{text:l}})}handleToolLikeItem(t,n,e){if(!n.emittedToolStarts.has(e.id)){n.emittedToolStarts.add(e.id);const s={...y(e.toolName,e.toolInput,e.metadata),actionId:e.id};this.emitEvent({type:"tool_use_start",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id,...s}}),this.emit("status-change",t,"tool_using",{...s,usage:n.adapterSession.totalUsage}),n.adapterSession.messages.push({id:p(),sessionId:t,role:"tool_use",content:`${e.toolName}: ${JSON.stringify(e.toolInput).slice(0,100)}`,timestamp:e.timestamp,toolName:e.toolName,toolInput:e.toolInput,toolUseId:e.id})}e.isRunning||e.eventType!=="item.completed"||(this.emitEvent({type:"tool_use_end",sessionId:t,timestamp:e.timestamp,data:{toolName:e.toolName,toolResult:e.result,isError:e.isError,toolUseId:e.id}}),n.emittedToolStarts.delete(e.id))}completeTurn(t,n,e,s){const a=L(e);n.adapterSession.totalUsage=a,n.currentAssistantText&&(n.adapterSession.messages.push({id:p(),sessionId:t,role:"assistant",content:n.currentAssistantText,timestamp:s}),n.currentAssistantText=""),this.emitEvent({type:"turn_complete",sessionId:t,timestamp:s,data:{usage:a}}),n.adapterSession.status="waiting_input";const i=n.idleCommands?.idleInputCommand;!!(i&&this.isMessagePollingIdleCommand(i))?this.emit("status-change",t,"waiting_input",{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message",usage:a}):this.emit("status-change",t,"waiting_input"),n.lastActivityAt=Date.now(),this.startIdleDetection(t)}emitEvent(t){this.emit("event",t)}startIdleDetection(t){this.stopIdleDetection(t);const n=this.sessions.get(t),e=n?.idleCommands?.idleInputCommand;if(!n||!e)return;if(this.isMessagePollingIdleCommand(e)){n.idlePollLoop||(n.idlePollLoop=new m({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),preDispatchHook:()=>null,dispatchPollingPrompt:(a,i)=>this.sendIdlePrompt(t,a,{keepWaitingStatus:!0,injected:i}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a),pollDelayMs:d,regularIdleDelayMs:d})),n.idlePollLoop.start();return}n.idlePollLoop||(n.idlePollLoop=new m({getStatus:()=>this.sessions.get(t)?.adapterSession.status,getCommand:()=>this.sessions.get(t)?.idleCommands?.idleInputCommand,isPollingCommand:a=>this.isMessagePollingIdleCommand(a),preDispatchHook:()=>null,dispatchPollingPrompt:(a,i)=>this.sendIdlePrompt(t,a,{keepWaitingStatus:!0,injected:i}),dispatchRegularIdleCommand:a=>this.sendIdlePrompt(t,a),pollDelayMs:d,regularIdleDelayMs:d})),n.lastActivityAt=Date.now();const s=setInterval(()=>{this.checkIdleState(t)},500);n.idleTimer=s}stopIdleDetection(t){const n=this.sessions.get(t);n?.idlePollLoop?.stop(),n?.idleTimer&&(clearInterval(n.idleTimer),n.idleTimer=void 0)}checkIdleState(t){const n=this.sessions.get(t);if(!n||n.adapterSession.status!=="waiting_input"||!n.idleCommands?.idleInputCommand)return;const e=n.lastActivityAt??0;Date.now()-e<d||(n.lastActivityAt=Date.now(),this.sendIdlePrompt(t,n.idleCommands.idleInputCommand),this.stopIdleDetection(t))}async sendIdlePrompt(t,n,e){const s=this.sessions.get(t);if(!s||s.runningTurn)return;const a=e?.injected?n.trim():this.toIdlePrompt(n);if(!a)return;e?.keepWaitingStatus||(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"));const i=new AbortController;s.currentAbortController=i,s.runningTurn=this.runTurn(t,s,a,i);try{await s.runningTurn}finally{s.runningTurn=void 0,s.currentAbortController=void 0}}toIdlePrompt(t){const n=t.trim();return this.isMessagePollingIdleCommand(n)?"\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":n}isMessagePollingIdleCommand(t){const n=t.trim();if(!n)return!1;const e=n.toLowerCase();return e.includes("poll_message")||e.includes("get_message")||n.includes("\u53D6\u6D88\u606F")}}export{$ as CodexSdkAdapter};
4
4
 
@@ -5,6 +5,8 @@ export declare class OpencodeSdkAdapter extends EventEmitter implements BaseProv
5
5
  readonly providerId = "opencode";
6
6
  readonly displayName = "OpenCode";
7
7
  private sessions;
8
+
9
+ private listenerWakeHooks;
8
10
  private sdkModule?;
9
11
  startSession(sessionId: string, config: AdapterSessionConfig): Promise<void>;
10
12
  sendMessage(sessionId: string, message: string, options?: {