aws-runtime-bridge 1.9.151 → 1.9.153

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 (30) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +27 -0
  3. package/dist/adapter/AcodeSdkAdapter.js +5 -5
  4. package/dist/adapter/types.d.ts +16 -0
  5. package/dist/desktop/built-in-desktop-tools.js +1 -1
  6. package/dist/routes/ltr.js +1 -1
  7. package/dist/routes/sessions.d.ts +87 -0
  8. package/dist/routes/sessions.js +1 -1
  9. package/dist/routes/terminal.js +20 -20
  10. package/dist/services/instance-features.d.ts +11 -1
  11. package/dist/services/instance-features.js +1 -1
  12. package/dist/utils/file-utils.d.ts +2 -0
  13. package/dist/utils/file-utils.js +2 -2
  14. package/package/acode/dist/capability-prompt.d.ts +16 -0
  15. package/package/acode/dist/capability-prompt.js +3 -0
  16. package/package/acode/dist/runtime.d.ts +6 -0
  17. package/package/acode/dist/runtime.js +23 -22
  18. package/package/acode/dist/types.d.ts +3 -0
  19. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +28 -4
  20. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  21. package/package/aws-client-agent-mcp/dist/http-client.d.ts +1 -1
  22. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  23. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +24 -17
  24. package/package/aws-client-agent-mcp/dist/mcp-server.js +28 -28
  25. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +20 -0
  26. package/package/aws-client-agent-mcp/dist/mcp-tools.js +25 -8
  27. package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +57 -0
  28. package/package/aws-client-agent-mcp/dist/tool-groups.js +3 -0
  29. package/package/aws-client-agent-mcp/dist/types.d.ts +23 -0
  30. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,104 @@ files 白名单),供调度中心「查看本次更新内容」弹窗按 `##
5
5
  展示。发布新版本时须在仓库中先写好 `## v<version>` 段(prepack-guard 校验缺段
6
6
  即阻断发布);Bridge 自更新成功后的运行时追加仅作为包内缺段时的兜底。
7
7
 
8
+ ## v1.9.153
9
+
10
+ _发布日期:2026-09-12_
11
+
12
+ - 工具集懒加载(Lazy Tool Expansion)全链路接入:受管控的大工具集(pencil / draw 各 15 个、
13
+ 启动项 9 个、招聘、浏览器 / 桌面桥接等)由「开启即全量暴露」升级为三态能力开关——
14
+ disabled(禁用)/ collapsed(收纳:工具不出现在工具列表,需先 expand_tools 展开)/ expanded(展开:工具全量直接可见),
15
+ 降低初始上下文占用。
16
+ - aws-mcp-server:`t_agent_ability_switch` 新增 `ability_state` 列(update.sql v1.30.0 迁移,存量行按
17
+ `enabled` 归一:1→expanded / 0→disabled,既有 agent 行为不变),`AgentAbilitySwitch` 实体 / Mapper /
18
+ Service 三态读写,`enabled` 布尔列写入时同步回填保持旧读取兼容。缺省口径(DB 无行):
19
+ browser / desktop / agentSys.launchItem / agentSys.hire 默认 collapsed(已授权但收纳),其余默认 disabled(显式授权)。
20
+ - aws-client-agent-mcp:新增常驻元工具 `expand_tools` / `call_tool`(不属于任何受控组,收纳组始终有展开与调度入口)。
21
+ ListTools 按三态过滤;展开不再把工具注入 runtime exposedTools、不再推送 tools/list_changed(ListTools
22
+ 载荷字节级稳定,LLM provider 前缀缓存全程命中),改为授予 call_tool 调度授权并把工具定义
23
+ (name/description/inputSchema)随 expand 结果下发,agent 当轮即可 call_tool 调用;执行期纵深防御:
24
+ disabled 拒绝、collapsed 未展开拒绝(同时兜住原生工具名直调的旁路)。配置为 expanded 的组不可在会话中
25
+ 收起(由用户决定)、重复展开按幂等 already-expanded 返回。browser / desktop 桥接能力经 HTTP 回传
26
+ bridge 新端点 `/runtime/sessions/:agentId/capability-tools[/call]`(X-Runtime-Token 鉴权),call 超时
27
+ 55s < runtime mcpToolTimeoutMs 60s。
28
+ - acode runtime:系统提示词注入能力清单(新增 capability-prompt.ts)——agent 知道哪些能力已展开 /
29
+ 已收纳 / 未开启,「我没有绘图工具」类请求会主动提示用户去能力配置开启;启动期 env 兜底改为携带三态值
30
+ (AWS_LAUNCH_CONFIG_TOOLS / AWS_HIRE_TOOLS / AWS_DRAW_TOOLS 等),消除首次 listTools 早于 token 就绪时
31
+ env 兜底把收纳组全量暴露的窗口。
32
+ - aws-dashboard:能力配置弹窗新增三态选择器(新组件 FeatureStatePicker.vue),capability-features.ts
33
+ 升级为三态模型(agentSys 主开关禁用时子能力级联禁用,跨层与 Java / bridge 口径一致)。
34
+ - Provider 请求失败不再默认无限重试:requestRetryCount 缺省由无限改为 0(持续 4xx 等不可恢复错误不再空转),
35
+ 错误信息从响应载荷提取 code + message 直接抛出,不再被静默重试吞掉;需恢复内部重试时在 config 显式配置
36
+ requestRetryCount(有限值或 -1 无限)。
37
+ - 消息中心「完整请求体」JSON 树视图:新增 JsonTreeNode.vue(层级树形展示、逐层懒展开)与 jsonRepair.ts
38
+ (截断 JSON 修复兜底,修复后可解析即以树形呈现),60KB 截断请求体支持全文搜索——输入防抖 200ms、
39
+ 命中计数、回车逐个定位、自动展开命中祖先链并高亮,未解析为 JSON 时回退原始文本。
40
+ - 图片预览缩放:新增 useImageZoom.ts(滚轮 / 双指缩放、拖拽平移、双击还原、缩放工具栏),接入 ChatPanel
41
+ 全屏图片预览与 MessageInput 附件预览。
42
+ - draw 卡片预览自愈:新增 drawCardPreview.ts 幽灵渲染管线——服务端从未渲染的 draw 消息卡片以发送者
43
+ (owner)身份补渲染生成预览,渲染成功事件即时补拉;pencil / draw 卡片渲染图 30s 定时补拉自愈
44
+ (消息离开列表即停止),有图即终态。
45
+ - 杂项:.gitignore 补充审查 / 调试期临时产物(tsc / TAP 输出、一次性统计脚本、本地 AI 助手工作区);
46
+ 修复 draw.ts 头注释在编辑中被截断损坏的问题。
47
+
48
+ ## v1.9.152
49
+
50
+ _发布日期:2026-09-10_
51
+
52
+ - 绘图(draw.io)能力全链路接入:新增「绘图 (draw)」能力开关(默认关闭,显式授权语义,同 desktop/hire/pencil),
53
+ Agent 可创建 / 编辑 / 导出 / 分享 draw.io 绘图文档,Dashboard 以独立面板内嵌官方 draw.io 编辑器。
54
+ - aws-mcp-server:新增 `t_draw_doc`(doc_id 唯一,`doc_xml` 为完整 `<mxfile>` 权威内容)、
55
+ `t_draw_doc_member`(协作权限 read|write)、`t_draw_doc_change`(事务型 Outbox 变更日志,与内容写入同事务
56
+ 落行,每 doc 保留最近 200 版;变更通知只作唤醒信号,丢失/离线时经 `draw_get_changes(sinceVersion)` 追赶);
57
+ `DrawDocController` 暴露 `/api/draw/*`(docs / doc / doc ops / doc render / counts / doc members);
58
+ `DrawDocMapper` 以 `doc_id + version` 乐观锁 CAS 写回,消除 check-then-act 竞态窗口。
59
+ - aws-runtime-bridge:新增 `DRAW_FEATURE_KEY` 能力标识与 `AWS_DRAW_TOOLS` 启动期 env 兜底;
60
+ `aws-client-agent-mcp` 注册 `draw_*` 工具组(create/list/open/close/get_diagram/get_changes/create_cells/
61
+ update_cells/delete_cells/delete_document/rename_document/share_document/revoke_share/export_document),
62
+ ListTools 按开关注实时过滤,服务端 `/mcp/call` 另有权威校验;`draw_export_document` 只回传
63
+ savedTo/sizeKb 等元信息,docXml 不回流 agent 上下文。
64
+ - aws-dashboard:新增 `DrawPanel.vue`(iframe 加载自托管 draw.io,经 embed postMessage 协议 load/autosave/export);
65
+ 会话列表新增绘图徽标(仅 Agent 有绘图文档时显示,附数量角标);文档列表改为工具事件驱动刷新
66
+ (`drawRevision` 信号 + 防抖),取代每 2.5s 高频轮询 `/api/draw/docs`,仅在 WS 断线/未覆盖时低频兜底;
67
+ 面板宽度与收缩优先级纳入 `draw`;移动端新增绘图覆盖层。
68
+ - 自托管编辑器资源置于 `aws-dashboard/public/draw/`(官方 draw.war 解包,v31.4.4,含 README 说明升级与授权注意),
69
+ 并加入 Service Worker `globIgnores` 排除预缓存(app.min.js 9MB+、integrate.min.js 22MB+ 体积超预缓存上限,
70
+ 仅打开绘图面板时按需加载)。
71
+ - 消息卡片:`send_group` / `send_private` 支持附带 `card`(`{type:pencil|draw,docId,title?,description?}`)
72
+ 文档引用卡片,`send_group`/`send_private` 工具描述同步说明。读取模型为「凭 docId 可读」——任何 Agent 拿到 docId
73
+ 即可用 `pencil_get_tree` / `draw_get_diagram` 读取,无需被邀请;写操作仍按 owner / 协作成员权限校验。
74
+ 为此 `PencilDocService` 的读取路径(readDoc / getTree / getRender / getChanges)去掉「非 owner/成员即拒绝」
75
+ 的拦截,`resolvePermission` 返回 null 时读取归一为 read;新增 `validateCardDoc` 供卡片发送前确认文档存在。
76
+ 卡片只读引用不写入 `*_doc_member`,因此不改变协作者列表、shared 标记与文档列表徽标。
77
+ `t_direct_message` / `t_group_message` 新增 `card` 列(LONGTEXT,防富内容截断),
78
+ `GroupMessageService` / `DirectMessageService` 增加带卡片的 8 参重载(原 7 参签名保留并委托,向后兼容),
79
+ 卡片 JSON 落库前校验合法性(非法 JSON / 非对象直接拒绝,解析失败按无卡片降级渲染历史消息)。
80
+ Dashboard 侧 `ChatPanel.vue` 新增消息卡片渲染(仿小程序卡片:有渲染图显示预览、否则占位封面,
81
+ 带类型徽标与标题,点击直接打开对应绘图 / 画布面板)。
82
+ - 消息内容扩容 + 载荷剥离:`t_direct_message` / `t_group_message` / `t_meeting_message` 的 `content`
83
+ 由 TEXT(64KB) 扩为 LONGTEXT——富格式内嵌图片 base64(压缩后数百 KB ~ 数 MB)在 MySQL 非严格模式下会被
84
+ 静默截断到 64KB,Agent 经 `poll_message` 只拿到残缺 JSON、`JSON.parse` 失败,表现为 agent 看不到图
85
+ (`[image omitted]`)。配套在 acode runtime 的 poll 结果中剥离 directMessages/groupMessages 内嵌的
86
+ 图片与附件 base64,仅保留可读文本摘要,避免 base64 以纯文本污染后续上下文。
87
+ Dashboard 发送侧新增 `buildRichAttachmentContent`——图片附件以内嵌 base64 随消息下发(Agent 直接以
88
+ 多模态 data URL 读取,无需 fetch 图片 URL / 落盘再读),非图片附件仍为 URL 描述(语义等价 `[文件: ...]`),
89
+ 这正是 content 必须扩容到 LONGTEXT 的直接原因。
90
+ 新增 `ACODE_IMAGE_DIAG=1` 开启的图片注入诊断日志(默认关闭,异步追加且吞掉 I/O 异常)。
91
+ - 发布前修复:群消息仅卡片(无正文)时 Java 侧校验误拒绝,已与 mcp-server 侧「content/attachments/card
92
+ 至少其一非空」对齐;`draw_export_document` 工具 schema 与实现统一(仅 xml/drawio,svg/png 等渲染
93
+ 待阶段 2 管线,描述不再误导);`DrawPanel` 的 postMessage 接收仅接受同源自托管编辑器消息。
94
+ - 原子写健壮性:`atomicWriteFile` 改用 `renameFileWithRetry`——Windows 下 `fs.rename` 可能因目标被瞬时占用
95
+ (杀毒扫描 / 并发句柄)抛 EPERM/EBUSY/EACCES,按 40ms 递增退避重试 3 次,降低实际运行与测试并发下的假失败。
96
+ - 面板最大化(脱离为弹框):新增 `PanelDetachButton.vue`,终端 / 时间线 / 工作区 / 上下文 / 待办 / 后台任务 /
97
+ 子 Agent / 浏览器 / 画布等侧窗面板可一键脱离为弹框最大化,再点恢复回侧窗;脱离态保留强调色提示,
98
+ 标签栏场景支持右对齐 sticky 固定,移动端隐藏(已是全屏覆盖层)。
99
+ - 桌面工具 origin 判定明确化:`injectRememberedOrigin` 以 `originSet()`(非 null 且非 undefined)替代
100
+ `!= null` 判断,语义等价并消除隐式类型收窄告警。
101
+ - 轮询降频:在线成员列表的断连兜底轮询由 5s 放宽到 30s(`ONLINE_CHANGE` WS 事件已支持增量更新,
102
+ 断连时仅需兜底同步,无需高频拉取);绘图文档列表同样由固定间隔轮询改为工具事件驱动。
103
+ - 测试:vitest 单测超时由 30s 放宽到 90s——本机并行跑完整套件(103 个文件、真实 git/子进程)时 CPU 争用
104
+ 可把单个用例拖慢数倍,避免负载型假失败掩盖真实回归;补齐 `draw_*` 工具、git 路由与 acode runtime 用例。
105
+
8
106
  ## v1.9.151
9
107
 
10
108
  _发布日期:2026-09-07_
@@ -1,6 +1,7 @@
1
1
 
2
2
  import { EventEmitter } from "node:events";
3
3
  import type { SubAgentManager, TerminalManager } from "@agentswork/acode";
4
+ import { type FeatureState } from "../services/instance-features.js";
4
5
  import type { AdapterSessionConfig, BaseProviderAdapter, ConversationMessage, RuntimeCapabilities, SessionStatus } from "./types.js";
5
6
  type ACodeEvent = {
6
7
  type: string;
@@ -69,6 +70,8 @@ type ACodeRuntimeConstructor = new (config: {
69
70
  subAgentSuiteTools?: unknown[];
70
71
 
71
72
  subAgentSuiteToolProvider?: (patterns: string[]) => Promise<unknown[]>;
73
+
74
+ capabilityState?: (featureKey: string) => FeatureState;
72
75
  }) => ACodeRuntimeInstance;
73
76
  export declare function toAcodeEsmImportSpecifier(modulePath: string): string;
74
77
 
@@ -78,6 +81,10 @@ export declare class AcodeSdkAdapter extends EventEmitter implements BaseProvide
78
81
  readonly displayName = "ACode";
79
82
  private sessions;
80
83
 
84
+ private expandedBuiltInCapabilities;
85
+
86
+ private dispatchableCapabilityTools;
87
+
81
88
  private listenerWakeHooks;
82
89
  private runtimeConstructor?;
83
90
  constructor();
@@ -116,6 +123,26 @@ export declare class AcodeSdkAdapter extends EventEmitter implements BaseProvide
116
123
 
117
124
  private syncMcpToolsForAgent;
118
125
 
126
+ setBuiltInCapabilityTools(agentId: string, capability: string, action: "expand" | "collapse"): Promise<{
127
+ sessions: number;
128
+ tools: number;
129
+ manifests?: Array<{
130
+ name: string;
131
+ description?: string;
132
+ inputSchema?: unknown;
133
+ }>;
134
+ }>;
135
+
136
+ callBuiltInCapabilityTool(agentId: string, capability: string, toolName: string, args: Record<string, unknown>): Promise<{
137
+ ok: boolean;
138
+ result?: unknown;
139
+ error?: string;
140
+ }>;
141
+
142
+ private pruneDispatchableCapabilityTools;
143
+
144
+ private shouldInjectCapabilityTools;
145
+
119
146
  getPendingQuestion(sessionId: string): {
120
147
  toolCallId: string;
121
148
  questions: unknown[];
@@ -1,11 +1,11 @@
1
- import{EventEmitter as X}from"node:events";import V from"node:fs/promises";import U from"node:path";import{fileURLToPath as Z,pathToFileURL as tt}from"node:url";import{v4 as I}from"uuid";import{getBridgeInstancePluginsDir as et,getBridgeInstanceSkillsDir as st,getBridgeTemplateConfigFile as L,getBridgeTemplateSkillsDir as ot}from"../config.js";import{getReleasedAcodeEntryPath as it}from"../services/acode-package.js";import{syncAgentSkillFarm as F}from"../services/agent-capability-sync.js";import{agentPtyManager as at}from"../services/agent-pty-manager.js";import{getBrowserTools as v,closeBrowserSession as nt,registerListenerWakeHook as rt,unregisterListenerWakeHook as q}from"../services/browser-session-manager.js";import{getDesktopTools as D,getDesktopToolsIfReady as ut}from"../services/desktop-mcp-manager.js";import{redactForLog as B}from"../services/instance-ai-config-service.js";import{BROWSER_FEATURE_KEY as W,DESKTOP_FEATURE_KEY as x,getAgentToolPermissions as lt,isFeatureEnabled as P,resolveAgentToolPermissions as dt}from"../services/instance-features.js";import{pluginManager as $}from"../services/plugin-manager.js";import{subAgentManager as ct}from"../services/sub-agent-manager-instance.js";import{recordAgentFileChange as mt}from"../services/workspaceTaskChangeWatcher.js";import{getInstanceAiConfigDebugLogger as O}from"../utils/instance-ai-config-debug-logger.js";import{isMessagePollingIdleCommand as E,isPollMessageToolDescriptor as pt}from"./acode-tool-names.js";import{IdlePollLoop as gt}from"./idle-poll-loop.js";import{MESSAGE_POLLING_IDLE_PROMPT as ft}from"./prompts.js";import{resolveAcodeProviderConfig as ht}from"./instance-ai-config-resolver.js";import{getCanonicalMcpDetail as N,getToolActionInfo as Tt}from"./types.js";const At=process.env.ACODE_COMPACTION_DEBUG==="1";function l(...u){At&&console.log(...u)}const yt=process.env.ACODE_TOKEN_DEBUG==="1";function C(...u){yt&&console.log("[TokenDebug][Adapter]",...u)}const St=["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(" "),_t=5e3;function M(u,t){const e=process.env[u];if(e===void 0||e.trim()==="")return t;const s=Number(e.trim());return Number.isFinite(s)&&s>=0?Math.floor(s):t}const H=M("ACODE_DATA_FLOW_WATCHDOG_MS",12e4),bt=5*6e4,kt=M("ACODE_STUCK_AUTOPOLL_TIMEOUT_MS",5*6e4),Ct=250,K=[0,3e3,1e4,3e4,6e4],j=M("ACODE_SUBMIT_TIMEOUT_MS",12e4),Q=3e3,wt=ft;function Pt(){return U.resolve(it())}function $t(u){return tt(U.resolve(u)).href}const G=128e3,w={"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 Lt(u){if(!u)return G;const t=u.toLowerCase().trim(),e=w[t];if(e)return e.contextLimit;const s=Object.keys(w).filter(a=>t.startsWith(a)).sort((a,i)=>i.length-a.length),o=s[0]!==void 0?w[s[0]]:void 0;return o?o.contextLimit:G}const J=4096;function Dt(u){if(!u)return J;const t=u.toLowerCase().trim(),e=w[t];if(e)return e.maxOutput;const s=Object.keys(w).filter(a=>t.startsWith(a)).sort((a,i)=>i.length-a.length),o=s[0]!==void 0?w[s[0]]:void 0;return o?o.maxOutput:J}function xt(u){if(!u||typeof u!="object")return;const t=u,e=h(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),s=h(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(e===0&&s===0)return;let o=h(t.cacheHitTokens,t.promptCacheHitTokens,t.prompt_cache_hit_tokens),a=h(t.cacheMissTokens,t.promptCacheMissTokens,t.prompt_cache_miss_tokens),i=t.cacheHitTokens!==void 0||t.cacheMissTokens!==void 0||t.promptCacheHitTokens!==void 0||t.promptCacheMissTokens!==void 0||t.prompt_cache_hit_tokens!==void 0||t.prompt_cache_miss_tokens!==void 0;if(o===0&&a===0){const r=h(t.cache_read_input_tokens),n=h(t.cache_creation_input_tokens);r>0||n>0?(o=r,a=n+h(t.input_tokens),i=!0):(o=h(t.cache_hit_tokens),a=h(t.cache_miss_tokens),i=i||t.cache_hit_tokens!==void 0||t.cache_miss_tokens!==void 0)}if(o===0&&a===0){const r=h(t.prompt_tokens_details?.cached_tokens);r>0&&(o=r,a=e>r?e-r:0,i=!0)}return{inputTokens:e,outputTokens:s,...o>0||a>0?{cacheHitTokens:o,cacheMissTokens:a}:{},...i?{hasCache:!0}:{}}}function h(...u){for(const t of u){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function z(u){return h(u.estimatedContextTokens,u.contextTokens,u.context_tokens,u.contextUsedTokens,u.context_used_tokens)}function Ot(u){return u==="stderr"||u==="mixed"?u:"stdout"}function Et(u){if(!u||typeof u!="object"||Array.isArray(u))return;const t={};for(const[e,s]of Object.entries(u))typeof s=="string"&&(t[e]=s);return Object.keys(t).length>0?t:void 0}function Mt(u){return u.failed===!0}function Y(u,t,e){if(!u)return e?`${t}/${e}`:t;const s=`${t}__`;return u.startsWith(s)?N(`${t}__${u.slice(s.length)}`):N(u.replace("/","__"))}function Rt(u){return u==="read_file"||u==="edit_file"||u==="write_file"||u==="bash"}function Ut(u){const t=It(u);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof u=="string"&&u.trim().length>0}function It(u){if(u&&typeof u=="object"&&!Array.isArray(u))return u;if(!(typeof u!="string"||!u.trim()))try{const t=JSON.parse(u);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class ae extends X{constructor(){super(),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.listenerWakeHooks=new Map,$.setOnPluginsChanged(t=>{this.syncPluginCommands(t)})}async syncPluginCommands(t){try{const e=await $.getPluginCommands(t);for(const s of this.sessions.values())s.config.agentId===t&&s.runtime.addPluginCommands?.(e)}catch(e){l(`[acode-adapter] syncPluginCommands failed for agent ${t}:`,e.message)}}async startSession(t,e){const s=e.mcpConfigPath||L(),{resolved:o,configContextLimit:a,supportsImage:i}=await this.resolveAcodeProvider(e,s),r=o.model,n=a??Lt(r),d=Dt(r),p={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:n,maxOutput:d,cacheHitTokens:0,cacheMissTokens:0}};this.sessions.set(t,{adapterSession:p,config:e,runtime:await this.createRuntime(t,r,e,o,i),autoPollActive:!1,retryAttempt:0,retryActive:!1}),this.emit("status-change",t,"starting");const m=this.sessions.get(t);if(!m)throw new Error("ACode session was not initialized");const c=()=>{const g=this.sessions.get(t);g&&this.getIdlePollLoop(g).start()};this.listenerWakeHooks.set(t,c),rt(e.agentId,c);try{await m.runtime.start(),p.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:m.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(g){p.status="error",this.emitRuntimeErrorEvent(t,g),this.emit("status-change",t,"error");const f=this.sessions.get(t);throw f?.capabilitiesFallbackTimer&&clearTimeout(f.capabilitiesFallbackTimer),this.sessions.delete(t),q(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),g}}async sendMessage(t,e){const s=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 o=this.requireSession(t),a=o.adapterSession.status;l(`[ACode] Previous status: ${a}`),this.cancelScheduledAutoPoll(o),o.failedTurnRecoveryScheduled=!1,o.idlePollLoop?.stop(),this.cancelRequestRetry(o),o.retryAttempt=0;const i={id:I(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};o.adapterSession.messages.push(i),this.emit("conversation-message",t,i),l(`[ACode] Changing status: ${a} \u2192 thinking`),o.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),o.lastSubmittedPrompt=e,this.startSubmitTimeoutDetection(t,o,"sendMessage");try{l("[ACode] \u25B6\uFE0F Calling runtime.submit()...");const r=Date.now();await o.runtime.submit(e);const n=Date.now()-r;this.cancelSubmitTimeoutDetection(o),l(`[ACode] \u2705 runtime.submit() completed in ${n}ms`),l(`[ACode] Current status after submit: ${o.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Calling recoverResolvedTurnWithoutTerminalEvent()..."),this.recoverResolvedTurnWithoutTerminalEvent(t),l(`[ACode] Status after recovery: ${o.adapterSession.status}`);const d=Date.now()-s;l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),l(`[ACode] \u2705 sendMessage COMPLETED in ${d}ms`),l("[ACode] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}catch(r){const n=Date.now()-s;console.error(`[ACode] \u274C sendMessage FAILED after ${n}ms:`,r instanceof Error?r.message:String(r)),this.cancelSubmitTimeoutDetection(o),l("[ACode] \u25B6\uFE0F sendMessage failed, scheduling request retry..."),this.emitRuntimeErrorEvent(t,r),this.scheduleRequestRetry(t,"sendMessage"),l(`[ACode] Status after failure: ${o.adapterSession.status}`)}}async sendConfirmation(t,e){}submitToolPermissionDecision(t,e,s){const o=this.sessions.get(t);if(!o)return!1;o.pendingToolAuthRequests?.delete(e);const a=o.runtime.submitToolPermissionDecision?.(e,s)??!1;return a&&this.startSubmitTimeoutDetection(t,o,"submitToolPermissionDecision"),a}getPendingToolAuthRequests(t){const e=this.sessions.get(t);return e?.pendingToolAuthRequests?Array.from(e.pendingToolAuthRequests.entries()).map(([s,o])=>({requestId:s,capability:o.capability,detail:o.detail,requestedAt:o.requestedAt})):[]}async sendQuestionAnswer(t,e){const s=this.sessions.get(t);if(!s)return;const o=s.pendingQuestionToolCallId;if(!o){l(`[AcodeSdkAdapter] sendQuestionAnswer: no pending question for session ${t}`);return}s.pendingQuestionToolCallId=void 0,s.pendingQuestions=void 0,s.runtime.submitQuestionAnswer&&s.runtime.submitQuestionAnswer(o,e),this.startSubmitTimeoutDetection(t,s,"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 s=e.adapterSession.totalUsage;if(e.adapterSession.totalUsage={inputTokens:0,outputTokens:0,contextLimit:s.contextLimit,maxOutput:s.maxOutput,inputLimit:s.inputLimit,compactionThreshold:s.compactionThreshold,cacheHitTokens:s.cacheHitTokens,cacheMissTokens:s.cacheMissTokens},e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),e.config.initialPrompt?.trim()){this.startInitialPromptTurn(t,e.config.initialPrompt);return}this.armIdleLoopOrAutoPoll(t)}async terminateSession(t){const e=this.sessions.get(t);if(!e)return;this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),this.cancelRequestRetry(e),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),await e.runtime.stop();const s=e.config.agentId;s&&(q(s,this.listenerWakeHooks.get(t)),nt(s)),this.listenerWakeHooks.delete(t),e.adapterSession.status="terminated",this.sessions.delete(t),this.emit("status-change",t,"terminated")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.has(t)?t:void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}notifyForceMessage(t){const e=this.sessions.get(t);return e?.runtime?.notifyForceMessage?(e.runtime.notifyForceMessage(),!0):!1}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}async resolveAgentAiInfo(t){try{const e=[...this.sessions.values()].find(i=>i.config.agentId===t);if(!e)return;const s=e.config.mcpConfigPath||L(),{resolved:o,supportsImage:a}=await this.resolveAcodeProvider(e.config,s);return o?.model?{model:o.model,supportsImage:a===!0,...o.baseURL?{baseURL:o.baseURL}:{},...o.apiKey?{apiKey:o.apiKey}:{}}:void 0}catch{return}}resolveAgentSkillsDir(t){if(t){try{const e=F(t);if(e)return e}catch(e){l(`[acode-adapter] skill farm sync failed for agent ${t}:`,e.message)}return st(t)}return ot()}async applyAgentFeatures(t){if(!t)return;const e=P(t,x),s=P(t,W);for(const[a,i]of this.sessions){if(i.config.agentId!==t)continue;const r=i.runtime;try{if(e){const n=await D(t,await this.resolveAgentAiInfo(t)),d=r.addBuiltInTools?.(n)??0;d>0&&l(`[acode-adapter] session ${a}: ${d} desktop tools hot-added for agent ${t}`)}else{const n=r.removeBuiltInToolsByPrefix?.("desktop_")??0;n>0&&l(`[acode-adapter] session ${a}: ${n} desktop tools hot-removed for agent ${t}`)}}catch(n){l(`[acode-adapter] session ${a}: desktop feature hot-sync failed for agent ${t}:`,n.message)}if(s)try{const n=await v(t,i.config.scopeKey,typeof i.config.browserAllowPrivate=="boolean"?{allowPrivate:i.config.browserAllowPrivate}:void 0),d=r.addBuiltInTools?.(n)??0;d>0&&l(`[acode-adapter] session ${a}: ${d} browser tools hot-added for agent ${t}`)}catch(n){l(`[acode-adapter] session ${a}: browser feature hot-sync failed for agent ${t}:`,n.message)}}this.syncMcpToolsForAgent(t);try{F(t)}catch(a){l(`[acode-adapter] skill farm hot-sync failed for agent ${t}:`,a.message)}try{await $.applyCapabilities(t)}catch(a){l(`[acode-adapter] plugin capability hot-sync failed for agent ${t}:`,a.message)}const o=dt(t);for(const[a,i]of this.sessions)if(i.config.agentId===t)try{i.runtime.setToolPermissionPolicy?.(o)}catch(r){l(`[acode-adapter] session ${a}: tool permission policy hot-sync failed for agent ${t}:`,r.message)}}syncMcpToolsForAgent(t){if(t){for(const[e,s]of this.sessions)if(s.config.agentId===t)try{s.runtime.requestMcpToolsRefresh?.()}catch(o){l(`[acode-adapter] session ${e}: mcp tools refresh failed for agent ${t}:`,o.message)}}}getPendingQuestion(t){const e=this.sessions.get(t);if(e?.pendingQuestionToolCallId)return{toolCallId:e.pendingQuestionToolCallId,questions:e.pendingQuestions??[]}}cleanup(){for(const t of this.sessions.keys())this.terminateSession(t)}setIdleCommands(t,e){const s=this.sessions.get(t);if(s){if(s.idleCommands=e,this.cancelScheduledAutoPoll(s),e.idleInputCommand&&E(e.idleInputCommand)){this.getIdlePollLoop(s).start();return}s.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.getIdlePollLoop(s).start()}}setRuntimeConstructorForTest(t){this.runtimeConstructor=t}async loadAcodeProviderSection(t){try{const e=await V.readFile(t,"utf-8"),s=JSON.parse(e),a=s.provider?.default,i=a?.options,r=h(s.contextLimit),n={},d={},p=a?.models;if(p&&typeof p=="object"){for(const[m,c]of Object.entries(p))if(c&&typeof c=="object"){const g=h(c.contextLimit);g>0&&(n[m.trim()]=g);const f=c.modalities?.input,y=Array.isArray(f)&&f.includes("image")||c.supportsImageInput===!0;d[m.trim()]=y===!0}}return{...a?.model?{model:a.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...r>0?{contextLimit:r}:{},...Object.keys(n).length>0?{modelContextLimits:n}:{},...Object.keys(d).length>0?{modelImageSupport:d}:{}}}catch(e){const s=e instanceof Error?e.message:String(e);return O().log({level:"warn",category:"load",message:`loadAcodeProviderSection failed: ${t}: ${s}`,source:"bridge"}),{}}}async resolveAcodeProvider(t,e){const s=typeof t.model=="string"&&t.model.trim()?t.model.trim():void 0,o=O();o.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?B(t.instanceAiConfig):null,configPath:e}});const a={...t.instanceAiConfig?.model?{model:t.instanceAiConfig.model}:{},...t.instanceAiConfig?.baseURL?{baseURL:t.instanceAiConfig.baseURL}:{},...t.instanceAiConfig?.apiKey?{apiKey:t.instanceAiConfig.apiKey}:{},...t.instanceAiConfig?.effort?{effort:t.instanceAiConfig.effort}:{},...s?{model:s}:{}},i=await this.loadAcodeProviderSection(e);let r=i.contextLimit;if(!r&&i.modelContextLimits){const d=s||t.instanceAiConfig?.model||i.model;d&&i.modelContextLimits[d]&&(r=i.modelContextLimits[d])}const n=ht(a,i,"acode-default");return o.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:B(a),globalConfigModel:i?.model??null,resolvedModel:n.model,resolvedBaseURL:n.baseURL??null,resolvedApiKey:n.apiKey?"[set]":null,configContextLimit:r,resolvedSource:n.source}}),{resolved:n,configPath:e,perSessionModel:s,configContextLimit:r,supportsImage:i.modelImageSupport?.[n.model]===!0}}async createRuntime(t,e,s,o,a){const i=await this.loadRuntimeConstructor(),r=s.mcpConfigPath||L();let n=[];try{n=await v(s.agentId,s.scopeKey,typeof s.browserAllowPrivate=="boolean"?{allowPrivate:s.browserAllowPrivate}:void 0)}catch(c){l(`[acode-adapter] browser tools injection skipped for agent ${s.agentId}:`,c.message)}let d=[];if(P(s.agentId??"",W)&&(d=n),s.agentId&&P(s.agentId,x))try{const c=o?.model?{model:o.model,supportsImage:a===!0,...o.baseURL?{baseURL:o.baseURL}:{},...o.apiKey?{apiKey:o.apiKey}:{}}:void 0,g=await D(s.agentId,c);g.length>0&&(d=[...d,...g])}catch(c){l(`[acode-adapter] desktop tools injection skipped for agent ${s.agentId}:`,c.message)}const p=new i({sessionId:t,agentId:s.agentId,workingDirectory:s.workingDirectory,configPath:r,skillsDir:this.resolveAgentSkillsDir(s.agentId),pluginsDir:s.agentId?et(s.agentId):void 0,model:e,systemPrompt:typeof s.systemPrompt=="string"?s.systemPrompt:void 0,globalPrompt:typeof s.globalPrompt=="string"?s.globalPrompt:void 0,rolePrompt:typeof s.rolePrompt=="string"?s.rolePrompt:void 0,memory:typeof s.memory=="string"?s.memory:void 0,env:s.envOverrides,subAgentManager:ct,terminalManager:at,pluginBridge:s.agentId?$.forAgent(s.agentId):void 0,commandDirs:[Z(new URL("../services/builtin-commands/",import.meta.url))],...s.subAgentModel?{subAgentModel:s.subAgentModel}:{},...s.subAgentEffort?{subAgentEffort:s.subAgentEffort}:{},...s.instanceAiConfig?.effort?{effort:s.instanceAiConfig.effort}:{},onFileChange:c=>mt({...c,agentId:s.agentId,workspacePath:s.workingDirectory}),extraBuiltInTools:d,...s.agentId?{toolPermissionPolicy:lt(s.agentId)??void 0}:{},subAgentSuiteTools:n,subAgentSuiteToolProvider:this.buildSubAgentSuiteToolProvider(s.agentId)});return O().log({level:"info",category:"resolve",message:"ACode provider resolved",source:"bridge",sessionId:t,details:{resolvedModel:e,perInstanceModel:s.instanceAiConfig?.model||null,perInstanceBaseURL:s.instanceAiConfig?.baseURL?"[set]":null,perInstanceApiKey:s.instanceAiConfig?.apiKey?"[set]":null,configPath:r}}),p.on("event",c=>this.forwardAcodeEvent(c)),p}buildSubAgentSuiteToolProvider(t){return async e=>{if(!t)return[];if(!P(t,x))return[];if(e.length===0)return ut();if(!e.some(a=>{const i=a.trim().replace(/[.*]+$/,"");return i==="desktop"||i.startsWith("desktop.")}))return[];const o=await this.resolveAgentAiInfo(t);return D(t,o)}}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=Pt(),e=await import($t(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 s=this.sessions.get(t);s&&(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),s.lastSubmittedPrompt=e,this.startSubmitTimeoutDetection(t,s,"startInitialPromptTurn"),s.runtime.submit(e).then(()=>{this.cancelSubmitTimeoutDetection(s),this.recoverResolvedTurnWithoutTerminalEvent(t)}).catch(o=>{const a=this.sessions.get(t);a&&(this.cancelSubmitTimeoutDetection(a),this.emitRuntimeErrorEvent(t,o),this.scheduleRequestRetry(t,"startInitialPromptTurn"))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(e.autoPollActive&&(e.autoPollLastActivityAt=Date.now()),t.type==="assistant_delta"){const s=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:I(),sessionId:t.sessionId,role:"assistant",content:s,timestamp:t.timestamp}),this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"text_delta",{text:s});return}if(t.type==="thinking_delta"){const s=typeof t.data.text=="string"?t.data.text:"";this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"thinking",{text:s});return}if(t.type==="command_output"){this.emitProviderEvent(t,"command_output",{text:typeof t.data.text=="string"?t.data.text:"",stream:Ot(t.data.stream),sequence:typeof t.data.sequence=="number"?t.data.sequence:void 0,cwd:typeof t.data.cwd=="string"?t.data.cwd:void 0,commandLineCount:typeof t.data.commandLineCount=="number"?t.data.commandLineCount:void 0,commandFilePath:typeof t.data.commandFilePath=="string"?t.data.commandFilePath:void 0});return}if(t.type==="background_command_completed"){this.emitProviderEvent(t,"background_command_completed",t.data);return}if(t.type==="ai_request"){const s=z(t.data),o=t.data.lastUsage,a=h(o?.inputTokens),i=h(o?.outputTokens),r=h(o?.cacheHitTokens),n=h(o?.cacheMissTokens),d=!!(o&&(a>0||i>0));let p;if(d&&(a>0&&(e.adapterSession.totalUsage.inputTokens=a),i>0&&(e.adapterSession.totalUsage.outputTokens=i),(o?.cacheHitTokens!==void 0||o?.cacheMissTokens!==void 0)&&(e.adapterSession.totalUsage.cacheHitTokens=r,e.adapterSession.totalUsage.cacheMissTokens=n),p={...e.adapterSession.totalUsage},C(`ai_request lastUsage applied: ${JSON.stringify(o)} -> totalUsage=${JSON.stringify(e.adapterSession.totalUsage)}`)),!d&&s>0){const g=e.adapterSession.totalUsage.inputTokens;g>0?e.adapterSession.totalUsage.inputTokens=Math.min(s,Math.floor(g*1.5)):e.adapterSession.totalUsage.inputTokens=s,p={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const c={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};p&&(c.usage=p),C(`ai_request handled: estimatedContextTokens=${t.data.estimatedContextTokens??"n/a"} totalUsage=${JSON.stringify(e.adapterSession.totalUsage)} displayUsage=${JSON.stringify(p??null)}`),this.emit("status-change",t.sessionId,e.adapterSession.status,c),this.startDataFlowWatchdog(t.sessionId,e),e.adapterSession.status==="thinking"&&e.watchdogSubmitStartTime&&(e.watchdogSubmitStartTime=Date.now()),this.emitProviderEvent(t,"ai_request",{model:typeof t.data.model=="string"?t.data.model:void 0,endpoint:typeof t.data.endpoint=="string"?t.data.endpoint:void 0,requestMethod:typeof t.data.requestMethod=="string"?t.data.requestMethod:void 0,requestUrl:typeof t.data.requestUrl=="string"?t.data.requestUrl:void 0,requestHeaders:Et(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 s=xt(t.data.usage);if(s){const a=e.adapterSession.totalUsage.inputTokens,i=a>0&&s.inputTokens<Math.floor(a*.2)&&!s.hasCache;C(`turn_complete usage: raw=${JSON.stringify(t.data.usage)} parsed=${JSON.stringify(s)} currentInput=${a} threshold20pct=${Math.floor(a*.2)} isFallbackUsage=${i}`),i?s.outputTokens>0&&(e.adapterSession.totalUsage.outputTokens=s.outputTokens):(e.adapterSession.totalUsage.inputTokens=s.inputTokens,e.adapterSession.totalUsage.outputTokens=s.outputTokens),(s.cacheHitTokens||s.cacheMissTokens)&&(e.adapterSession.totalUsage.cacheHitTokens=s.cacheHitTokens,e.adapterSession.totalUsage.cacheMissTokens=s.cacheMissTokens,l(`[ACode] \u{1F4B0} Cache usage (overwrite from runtime cumulative): hit=${e.adapterSession.totalUsage.cacheHitTokens}, miss=${e.adapterSession.totalUsage.cacheMissTokens} (turn delta: hit=${s.cacheHitTokens||0}, miss=${s.cacheMissTokens||0})`)),C(`totalUsage after turn_complete: ${JSON.stringify(e.adapterSession.totalUsage)}`)}else C(`turn_complete has NO parseable usage: raw=${JSON.stringify(t.data.usage)} failed=${t.data.failed===!0} aborted=${t.data.aborted===!0}`);const o=e.adapterSession.status;if(l(`[ACode] turn_complete event received (session: ${t.sessionId}), previous status: ${o}, failed: ${t.data.failed===!0}, aborted: ${t.data.aborted===!0}`),Mt(t.data)){l(`[ACode] Scheduling retry from failed turn_complete (session: ${t.sessionId})`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(t.data.aborted===!0&&(e.autoPollActive||e.retryActive||e.retryTimer)){l(`[ACode] Scheduling retry from aborted turn_complete (session: ${t.sessionId})`),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}),C(`status-change emitted (waiting_input after turn_complete): usage=${JSON.stringify(e.adapterSession.totalUsage)}`),l(`[ACode] Status changed to waiting_input after turn_complete (session: ${t.sessionId})`),e.autoPollActive&&e.autoPollObservedAssistantText&&!e.autoPollObservedPollingTool&&!e.autoPollObservedAnyTool){e.stopAutoPollAfterCurrentTurn=!0,console.warn(`[${this.displayName}] Auto-poll turn produced assistant text without calling any tool; stopping auto-poll rearm for session ${t.sessionId}`);return}this.armIdleLoopOrAutoPoll(t.sessionId);return}if(t.type==="session_complete"){this.cancelDataFlowWatchdog(e),this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.adapterSession.status="completed",this.emitProviderEvent(t,"session_complete",{exitCode:Number(t.data.exitCode)||0}),this.emit("status-change",t.sessionId,"completed");return}if(t.type==="question_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const s=typeof t.data.toolCallId=="string"?t.data.toolCallId:"",o=Array.isArray(t.data.questions)?t.data.questions:[];s&&(e.pendingQuestionToolCallId=s,e.pendingQuestions=o),this.emit("ask-user-question",{sessionId:t.sessionId,toolCallId:s||void 0,questions:o});return}if(t.type==="tool_permission_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const s=typeof t.data.requestId=="string"?t.data.requestId:"";s&&(e.pendingToolAuthRequests||(e.pendingToolAuthRequests=new Map),e.pendingToolAuthRequests.set(s,{capability:String(t.data.capability||""),detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation},requestedAt:Date.now()})),this.emit("tool-permission-request",{sessionId:t.sessionId,requestId:s,capability:String(t.data.capability||""),agentId:e.config.agentId,detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation}});return}if(t.type==="error"){if(t.data.nonFatal){this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")});return}this.cancelDataFlowWatchdog(e),e.adapterSession.status="error",this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")}),this.emit("status-change",t.sessionId,"error"),e.autoPollActive||this.recoverTurnFailure(t.sessionId,e);return}if(t.type==="mcp_status"){if(!t.data.action&&Array.isArray(t.data.tools)){const f=t.data.tools;f.some(T=>pt(T))||console.warn(`[${this.displayName}] ACode runtime is not exposing a poll_message tool. The LLM cannot call poll_message. Please configure an MCP server that provides poll_message (e.g. aws-mcp) in the dashboard panel for this runtime.`);const A=Array.isArray(t.data.servers)?t.data.servers:[],_=f.map(T=>({name:String(T.name??""),source:String(T.source??""),description:String(T.description??"")})).filter(T=>T.name),b={kind:"mcp",mcpServers:A,mcpTools:_};e.cachedMcpCapabilities=b,e.lastMcpCapabilities=b,e.lastCombinedCapabilities={kind:"combined",mcpServers:A,mcpTools:_,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},l(`[cap-diag] MCP capabilities cached: ${A.length} servers, ${_.length} tools`,{sessionId:t.sessionId,servers:A,toolNames:_.map(T=>T.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const T=e.cachedMcpCapabilities;if(!T)return;const k={...T,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:k,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(k)}),l(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${Q}ms)`,{sessionId:t.sessionId,mcpServers:T.mcpServers,mcpToolsCount:T.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},Q);return}const s=String(t.data.action??"");l(`[ACode] \u{1F4E1} mcp_status event: action=${s}, 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 o=typeof t.data.server=="string"?t.data.server:"mcp",a=typeof t.data.tool=="string"?t.data.tool:"",i=o&&a?`${o}__${a}`:a||o,r=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,n=Tt(i,r);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,n.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const d=Rt(n.actionType)?n.actionDetail||Y(void 0,o,a):Y(n.actionDetail,o,a),p=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,m=r?JSON.stringify(r,null,2):void 0,c={toolName:d,rawToolName:i,actionType:n.actionType,actionLabel:n.actionLabel,actionDetail:d,...m?{actionInput:m}:{},...r?{toolInput:r}:{},...p?{toolUseId:p,actionId:p}:{},metadata:{mcpServer:o}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...c,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const f=n.actionType==="idle"&&!Ut(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=f,n.actionType==="idle"&&(e.idleToolActiveAt=void 0),this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const y=n.actionType==="idle";this.emit("status-change",t.sessionId,f,y||f==="thinking"?void 0:c);return}const g=n.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=g,n.actionType==="idle"&&(e.idleToolActiveAt=Date.now()),g==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...c}),this.emitProviderEvent(t,"tool_use_start",c),this.emit("status-change",t.sessionId,g,c);return}if(t.type==="skill_status"){const o=(Array.isArray(t.data.skills)?t.data.skills:[]).map(m=>({name:String(m.name??""),description:typeof m.description=="string"?m.description:void 0,directory:typeof m.directory=="string"?m.directory:void 0})).filter(m=>m.name),a=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,r=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(m=>{const c=Array.isArray(m.skills)?m.skills:[];return{dir:typeof m.dir=="string"?m.dir:"",exists:m.exists===!0,skills:c.map(g=>({name:String(g.name??""),description:typeof g.description=="string"?g.description:void 0,directory:typeof g.directory=="string"?g.directory:void 0})).filter(g=>g.name)}}).filter(m=>m.dir),n=e.cachedMcpCapabilities??e.lastMcpCapabilities,d=e.cachedMcpCapabilities!==void 0,p={kind:"combined",mcpServers:n?.mcpServers??[],mcpTools:n?.mcpTools??[],skills:o,skillsDir:a,skillGroups:r};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:p,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(p)}),e.lastCombinedCapabilities=p,l(`[cap-diag] Combined capabilities emitted ${d?"(startup merge)":"(runtime refresh)"}: ${(n?.mcpTools??[]).length} MCP tools, ${o.length} skills`,{sessionId:t.sessionId,mcpServers:n?.mcpServers??[],skillsDir:a}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="startup_phase"){l(`[ACode] \u{1F680} startup_phase swallowed: ${String(t.data.phase??"unknown")}`,{sessionId:t.sessionId});return}if(t.type==="command_status"){if(t.data.action==="commands_loaded"){l(`[ACode] \u{1F4CB} command_status commands_loaded swallowed: ${typeof t.data.installedCommandCount=="number"?t.data.installedCommandCount:"?"} commands`,{sessionId:t.sessionId});return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)});return}if(t.type==="session_started"){const s=z(t.data),o=h(t.data.contextLimit)||void 0,a=h(t.data.maxOutput)||void 0,i=h(t.data.inputLimit)||void 0,r=h(t.data.compactionThreshold)||void 0;let n=!1;s>0&&(e.adapterSession.totalUsage.inputTokens=s,e.adapterSession.totalUsage.outputTokens=0,n=!0),o!==void 0&&(e.adapterSession.totalUsage.contextLimit=o,n=!0),a!==void 0&&(e.adapterSession.totalUsage.maxOutput=a,n=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,n=!0),r!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=r,n=!0),n&&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 s=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:s||"\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"}),this.emit("status-change",t.sessionId,"waiting_input",{actionLabel:"\u5BA1\u6279\u8BA1\u5212",actionDetail:s||"\u7B49\u5F85\u7528\u6237\u5BA1\u6279\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"});return}if(t.type==="context_compaction"){const s=t.data,o=s.action,a=o==="start",i=o==="end",r=o==="phase",n=s.parentId,d=s.compactionId;let p,m;if(a){const g=String(s.sizeKB??s.sizeBeforeKB??"?"),f=String(s.messageCount??s.messageCountBefore??"?"),y=s.estimatedTokens,A=s.actualInputTokens?`input=${s.actualInputTokens}`:"",_=s.actualOutputTokens?`output=${s.actualOutputTokens}`:"",b=s.trigger?`, \u89E6\u53D1: ${s.trigger}`:"";p="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",y!==void 0?m=`\u538B\u7F29\u524D: ~${y} tokens, \u6D88\u606F: ${f}\u6761`+(A?`, \u5B9E\u9645 tokens: ${A} ${_}`:"")+b:m=`\u538B\u7F29\u524D: ${g}KB, \u6D88\u606F: ${f}\u6761`+(A?`, \u5B9E\u9645 tokens: ${A} ${_}`:"")+b}else if(r)p=String(s.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),m=String(s.phaseDetail??"");else{const g=s.tokensBefore,f=s.tokensAfter,y=s.freedTokens,A=String(s.sizeBeforeKB??"?"),_=String(s.sizeAfterKB??"?"),b=String(s.freedKB??"?"),T=String(s.strategy??"?"),k=Number(s.prunedToolMessages??0),S=Number(s.summarizedMessages??0);p="\u538B\u7F29\u5B8C\u6210",g!==void 0&&f!==void 0?m=`\u91CA\u653E: ${y??g-f} tokens, ${g} tokens \u2192 ${f} tokens, \u7B56\u7565: ${T}`+(k?`, \u88C1\u526A\u5DE5\u5177: ${k}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:""):m=`\u91CA\u653E: ${b}KB, ${A}KB \u2192 ${_}KB, \u7B56\u7565: ${T}`+(k?`, \u88C1\u526A\u5DE5\u5177: ${k}\u6761`:"")+(S?`, \u6458\u8981\u5316: ${S}\u6761`:"")}a&&(e.adapterSession.status="compacting");const c={actionType:"context_compaction",actionLabel:p,actionDetail:m};if(a&&d)c.actionId=d;else if((r||i)&&d)if(c.parentId=d,r){const g=String(s.phase??"unknown");c.actionId=`${d}-phase-${g}`}else c.actionId=`${d}-end`;r&&n&&!c.parentId&&(c.parentId=n),i&&(e.adapterSession.totalUsage.inputTokens=h(s.tokensAfter),e.adapterSession.totalUsage.outputTokens=0,e.config.agentId&&$.markAgentCompacted(e.config.agentId),c.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",c),this.emit("status-change",t.sessionId,"compacting",c);return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)})}}emitProviderEvent(t,e,s){this.emit("event",{type:e,sessionId:t.sessionId,timestamp:t.timestamp,data:s})}armIdleLoopOrAutoPoll(t){const e=this.sessions.get(t);if(!(!e||this.isTerminalStatus(e.adapterSession.status))){if(this.cancelRequestRetry(e),e.retryAttempt=0,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 gt({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:s=>E(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,o)=>this.submitAutoPollPrompt(e,o?s:wt,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:s=>this.submitAutoPollPrompt(e,s)}),t.idlePollLoop}submitAutoPollPrompt(t,e,s){const o=this.sessions.get(t);if(!o||this.isTerminalStatus(o.adapterSession.status))return;const a=(o.autoPollToken??0)+1;o.autoPollToken=a,o.autoPollActive=!0,o.autoPollObservedPollingTool=!1,o.autoPollObservedAssistantText=!1,o.autoPollObservedAnyTool=!1,o.stopAutoPollAfterCurrentTurn=!1,o.autoPollQueuedAt=Date.now(),o.autoPollLastActivityAt=Date.now(),o.idleToolActiveAt=void 0,o.lastSubmittedPrompt=e,s?.keepWaitingStatus||(o.adapterSession.status="thinking",this.emit("status-change",t,"thinking")),this.startSubmitTimeoutDetection(t,o,"submitAutoPollPrompt"),o.runtime.submit(e).catch(i=>{this.emitRuntimeErrorEvent(t,i),this.scheduleRequestRetry(t,"submitAutoPollPrompt")}).finally(()=>{const i=this.sessions.get(t);if(i){if(i.autoPollToken!==a){l(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${a}, current=${i.autoPollToken}), skipping cleanup \u2014 newer turn has taken over`);return}if(this.cancelSubmitTimeoutDetection(i),i.autoPollActive=!1,i.failedTurnRecoveryScheduled||i.autoPollTimer){i.failedTurnRecoveryScheduled=!1;return}if(i.stopAutoPollAfterCurrentTurn){i.stopAutoPollAfterCurrentTurn=!1,i.autoPollObservedPollingTool=!1,i.autoPollObservedAssistantText=!1,i.autoPollObservedAnyTool=!1;return}if(i.adapterSession.status==="error"){this.recoverTurnFailure(t,i);return}if(i.adapterSession.status==="thinking"||i.adapterSession.status==="tool_using"){this.recoverResolvedTurnWithoutTerminalEvent(t);return}i.adapterSession.status==="waiting_input"&&this.armIdleLoopOrAutoPoll(t)}})}scheduleAutoPoll(t,e=Ct){const s=this.sessions.get(t);!s||s.autoPollActive||s.autoPollTimer||this.isTerminalStatus(s.adapterSession.status)||(s.autoPollTimer=setTimeout(()=>{const o=this.sessions.get(t);!o||o.autoPollActive||this.isTerminalStatus(o.adapterSession.status)||(o.autoPollTimer=void 0,this.submitAutoPollPrompt(t,St,{keepWaitingStatus:!0}))},e))}cancelScheduledAutoPoll(t){t.autoPollTimer&&(clearTimeout(t.autoPollTimer),t.autoPollTimer=void 0)}scheduleRequestRetry(t,e){const s=this.sessions.get(t);if(!s||this.isTerminalStatus(s.adapterSession.status)||s.retryActive||s.retryTimer)return;if(!s.lastSubmittedPrompt){s.adapterSession.status="error",this.emit("status-change",t,"error");return}s.retryAttempt+=1,s.retryActive=!0,this.cancelScheduledAutoPoll(s),s.idlePollLoop?.stop();const o=K[Math.min(s.retryAttempt-1,K.length-1)];s.adapterSession.status="error",this.emit("status-change",t,"error",{actionType:"retry",actionLabel:"\u91CD\u8BD5\u4E2D",actionDetail:`\u7B2C${s.retryAttempt}\u6B21 \xB7 ${Math.round(o/1e3)}s\u540E`}),l(`[ACode] scheduleRequestRetry(${e}): attempt=${s.retryAttempt} delay=${o}ms`),s.retryTimer=setTimeout(()=>{s.retryTimer=void 0,this.retryFailedRequest(t,e)},o)}retryFailedRequest(t,e){const s=this.sessions.get(t);if(!s)return;if(s.retryTimer=void 0,this.isTerminalStatus(s.adapterSession.status)||!s.lastSubmittedPrompt){s.retryActive=!1;return}s.retryActive=!1;const o=s.lastSubmittedPrompt;l(`[ACode] retryFailedRequest(${e}): attempt=${s.retryAttempt} re-submitting...`),s.adapterSession.status="thinking",this.emit("status-change",t,"thinking",{usage:s.adapterSession.totalUsage}),this.startSubmitTimeoutDetection(t,s,"retryFailedRequest"),s.runtime.submit(o).then(()=>{const a=this.sessions.get(t);!a||a.retryTimer||(this.cancelSubmitTimeoutDetection(a),a.retryAttempt=0,a.retryActive=!1,this.recoverResolvedTurnWithoutTerminalEvent(t))}).catch(a=>{const i=this.sessions.get(t);i&&(this.cancelSubmitTimeoutDetection(i),this.emitRuntimeErrorEvent(t,a),this.scheduleRequestRetry(t,`retry#${i.retryAttempt+1}`))})}cancelRequestRetry(t){t.retryTimer&&(clearTimeout(t.retryTimer),t.retryTimer=void 0),t.retryActive=!1}isTerminalStatus(t){return t==="completed"||t==="terminated"}emitRuntimeErrorEvent(t,e){const s=new Date().toISOString();this.emit("event",{type:"error",sessionId:t,timestamp:s,data:{text:e instanceof Error?e.message:String(e)}})}estimateOutputTokensFromMessages(t){const e=t.filter(s=>s.role==="assistant").map(s=>s.content).join("");return Math.max(0,Math.round(e.length/4))}recoverTurnFailure(t,e){if(this.isTerminalStatus(e.adapterSession.status))return;if(e.idleToolActiveAt=void 0,e.pendingToolAuthRequests?.size&&e.pendingToolAuthRequests.clear(),e.adapterSession.status==="tool_using"&&e.pendingToolEventData){const o=e.pendingToolEventData;l(`[ACode] recoverTurnFailure: \u8865\u53D1 tool_use_end (tool: ${o.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:{...o,toolResult:"[aborted] \u5DE5\u5177\u6267\u884C\u88AB\u6570\u636E\u6D41\u770B\u95E8\u72D7\u4E2D\u65AD"}}),e.pendingToolEventData=void 0}const s=this.estimateOutputTokensFromMessages(e.adapterSession.messages);if(s>0){const o=e.adapterSession.totalUsage.outputTokens;e.adapterSession.totalUsage.outputTokens=s,l(`[ACode] recoverTurnFailure: \u4F30\u7B97\u8986\u76D6 output tokens ${o} -> ${s} (totalUsage now: input=${e.adapterSession.totalUsage.inputTokens}, output=${e.adapterSession.totalUsage.outputTokens})`)}this.cancelScheduledAutoPoll(e),this.scheduleRequestRetry(t,"recoverTurnFailure")}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 s=e.idleCommands?.idleInputCommand,a=!!(s&&E(s))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",a),l(`[ACode] \u2705 Recovery complete, status now: ${e.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Arming idle loop or auto-poll..."),this.armIdleLoopOrAutoPoll(t),l("[ACode] \u2705 Idle loop armed, recovery process complete")}startSubmitTimeoutDetection(t,e,s){this.cancelSubmitTimeoutDetection(e),e.watchdogSubmitStartTime=Date.now(),e.watchdogLastDataFlowTime=Date.now(),e.watchdogTimer=setInterval(()=>{const o=this.sessions.get(t);if(!o){this.cancelSubmitTimeoutDetection(e);return}const a=o.adapterSession.status,i=Date.now();if(a==="waiting_input"){if(o.autoPollActive&&o.autoPollLastActivityAt&&o.idleToolActiveAt===void 0&&i-o.autoPollLastActivityAt>=kt){console.warn(`[ACode] CRITICAL: stuck auto-poll detected after ${Math.round((i-o.autoPollLastActivityAt)/1e3)}s (source: ${s}, session: ${t}): submit queued but no runtime events and no active poll_message tool. Forcing recovery (runtime force-settle will unblock submitQueue).`),this.executeWatchdogRecovery(t,o,s,"stuck_autopoll",i-o.autoPollLastActivityAt);return}o.watchdogSubmitStartTime=i,o.watchdogLastDataFlowTime=i;return}if(a==="tool_using"){const d=i-(o.watchdogLastDataFlowTime||i);if(d>=bt){const p=String(o.pendingToolEventData?.rawToolName??"");if((o.pendingToolAuthRequests?.size??0)>0){const m=o.pendingToolAuthRequests?.size??0;console.warn(`[ACode] tool_using elapsed ${Math.round(d/1e3)}s but ${m} tool permission request(s) awaiting user decision (session: ${t}), skipping recovery`),o.watchdogSubmitStartTime=i,o.watchdogLastDataFlowTime=i;return}if(p.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(d/1e3)}s but await_complete is running (session: ${t}, tool: ${p}), skipping recovery (sub-agents have their own watchdogs, bg commands have timeout limits)`),o.watchdogSubmitStartTime=i,o.watchdogLastDataFlowTime=i;return}if(console.warn(`[ACode] CRITICAL: tool_using slow timeout triggered after ${Math.round(d/1e3)}s (source: ${s}, session: ${t}). Tool execution likely hung. Forcing recovery via recoverTurnFailure.`),o.runtime.detachCurrentToolExecution?.()){console.warn(`[ACode] tool_using slow (${Math.round(d/1e3)}s): detached tool ${p} to background (session: ${t}); waiting for the real tool_result to continue the turn`),o.watchdogSubmitStartTime=i,o.watchdogLastDataFlowTime=i;return}this.executeWatchdogRecovery(t,o,s,"tool_using_slow",d);return}o.watchdogSubmitStartTime=i;return}if(a!=="thinking")return;const r=i-(o.watchdogSubmitStartTime||i),n=i-(o.watchdogLastDataFlowTime||i);if(H>0&&n>=H){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(n/1e3)}s (source: ${s}, session: ${t}, status: ${a}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,o,s,"data_flow",n);return}if(j>0&&r>=j){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(r/1e3)}s (source: ${s}, session: ${t}, status: ${a}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,o,s,"submit_timeout",r);return}},_t)}executeWatchdogRecovery(t,e,s,o,a){l(`[ACode] Watchdog (${o}): calling runtime.abort() after ${Math.round(a/1e3)}s...`);try{e.runtime.abort(),l(`[ACode] Watchdog (${o}): runtime.abort() called`)}catch(i){console.warn(`[ACode] \u26A0\uFE0F Watchdog (${o}): runtime.abort() threw: ${i instanceof Error?i.message:String(i)}`)}this.cancelSubmitTimeoutDetection(e),this.recoverTurnFailure(t,e),console.warn(`[ACode] \u26A0\uFE0F Watchdog (${o}) recovery complete. If abort() could not cancel the underlying operation, submitQueue may still be deadlocked.`)}cancelSubmitTimeoutDetection(t){t.watchdogTimer&&(clearInterval(t.watchdogTimer),t.watchdogTimer=void 0),t.watchdogSubmitStartTime=void 0,t.watchdogLastDataFlowTime=void 0}resetDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now(),e.watchdogSubmitStartTime=Date.now()}startDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now()}cancelDataFlowWatchdog(t){t.watchdogLastDataFlowTime=Date.now()}formatAiRequestActionDetail(t){const e=`
1
+ import{EventEmitter as X}from"node:events";import V from"node:fs/promises";import U from"node:path";import{fileURLToPath as Z,pathToFileURL as tt}from"node:url";import{v4 as v}from"uuid";import{getBridgeInstancePluginsDir as et,getBridgeInstanceSkillsDir as st,getBridgeTemplateConfigFile as x,getBridgeTemplateSkillsDir as ot}from"../config.js";import{getReleasedAcodeEntryPath as it}from"../services/acode-package.js";import{syncAgentSkillFarm as F}from"../services/agent-capability-sync.js";import{agentPtyManager as at}from"../services/agent-pty-manager.js";import{getBrowserTools as L,closeBrowserSession as nt,registerListenerWakeHook as rt,unregisterListenerWakeHook as q}from"../services/browser-session-manager.js";import{getDesktopTools as P,getDesktopToolsIfReady as lt}from"../services/desktop-mcp-manager.js";import{redactForLog as B}from"../services/instance-ai-config-service.js";import{BROWSER_FEATURE_KEY as W,DESKTOP_FEATURE_KEY as D,getAgentToolPermissions as ut,getFeatureState as O,isFeatureEnabled as dt,resolveAgentToolPermissions as ct}from"../services/instance-features.js";import{pluginManager as $}from"../services/plugin-manager.js";import{subAgentManager as mt}from"../services/sub-agent-manager-instance.js";import{recordAgentFileChange as pt}from"../services/workspaceTaskChangeWatcher.js";import{getInstanceAiConfigDebugLogger as E}from"../utils/instance-ai-config-debug-logger.js";import{isMessagePollingIdleCommand as M,isPollMessageToolDescriptor as gt}from"./acode-tool-names.js";import{IdlePollLoop as ft}from"./idle-poll-loop.js";import{resolveAcodeProviderConfig as ht}from"./instance-ai-config-resolver.js";import{MESSAGE_POLLING_IDLE_PROMPT as Tt}from"./prompts.js";import{getCanonicalMcpDetail as N,getToolActionInfo as At}from"./types.js";const yt=process.env.ACODE_COMPACTION_DEBUG==="1";function l(...d){yt&&console.log(...d)}const bt=process.env.ACODE_TOKEN_DEBUG==="1";function k(...d){bt&&console.log("[TokenDebug][Adapter]",...d)}const St=["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(" "),_t=5e3;function R(d,t){const e=process.env[d];if(e===void 0||e.trim()==="")return t;const s=Number(e.trim());return Number.isFinite(s)&&s>=0?Math.floor(s):t}const K=R("ACODE_DATA_FLOW_WATCHDOG_MS",12e4),Ct=5*6e4,kt=R("ACODE_STUCK_AUTOPOLL_TIMEOUT_MS",5*6e4),wt=250,H=[0,3e3,1e4,4e4],j=R("ACODE_SUBMIT_TIMEOUT_MS",12e4),Q=3e3,Pt=Tt;function $t(){return U.resolve(it())}function Lt(d){return tt(U.resolve(d)).href}const G=128e3,w={"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 xt(d){if(!d)return G;const t=d.toLowerCase().trim(),e=w[t];if(e)return e.contextLimit;const s=Object.keys(w).filter(a=>t.startsWith(a)).sort((a,i)=>i.length-a.length),o=s[0]!==void 0?w[s[0]]:void 0;return o?o.contextLimit:G}const J=4096;function Dt(d){if(!d)return J;const t=d.toLowerCase().trim(),e=w[t];if(e)return e.maxOutput;const s=Object.keys(w).filter(a=>t.startsWith(a)).sort((a,i)=>i.length-a.length),o=s[0]!==void 0?w[s[0]]:void 0;return o?o.maxOutput:J}function Ot(d){if(!d||typeof d!="object")return;const t=d,e=h(t.inputTokens,t.input_tokens,t.promptTokens,t.prompt_tokens),s=h(t.outputTokens,t.output_tokens,t.completionTokens,t.completion_tokens);if(e===0&&s===0)return;let o=h(t.cacheHitTokens,t.promptCacheHitTokens,t.prompt_cache_hit_tokens),a=h(t.cacheMissTokens,t.promptCacheMissTokens,t.prompt_cache_miss_tokens),i=t.cacheHitTokens!==void 0||t.cacheMissTokens!==void 0||t.promptCacheHitTokens!==void 0||t.promptCacheMissTokens!==void 0||t.prompt_cache_hit_tokens!==void 0||t.prompt_cache_miss_tokens!==void 0;if(o===0&&a===0){const r=h(t.cache_read_input_tokens),n=h(t.cache_creation_input_tokens);r>0||n>0?(o=r,a=n+h(t.input_tokens),i=!0):(o=h(t.cache_hit_tokens),a=h(t.cache_miss_tokens),i=i||t.cache_hit_tokens!==void 0||t.cache_miss_tokens!==void 0)}if(o===0&&a===0){const r=h(t.prompt_tokens_details?.cached_tokens);r>0&&(o=r,a=e>r?e-r:0,i=!0)}return{inputTokens:e,outputTokens:s,...o>0||a>0?{cacheHitTokens:o,cacheMissTokens:a}:{},...i?{hasCache:!0}:{}}}function h(...d){for(const t of d){const e=Number(t);if(Number.isFinite(e)&&e>0)return e}return 0}function z(d){return h(d.estimatedContextTokens,d.contextTokens,d.context_tokens,d.contextUsedTokens,d.context_used_tokens)}function Et(d){return d==="stderr"||d==="mixed"?d:"stdout"}function Mt(d){if(!d||typeof d!="object"||Array.isArray(d))return;const t={};for(const[e,s]of Object.entries(d))typeof s=="string"&&(t[e]=s);return Object.keys(t).length>0?t:void 0}function Rt(d){return d.failed===!0}function Y(d,t,e){if(!d)return e?`${t}/${e}`:t;const s=`${t}__`;return d.startsWith(s)?N(`${t}__${d.slice(s.length)}`):N(d.replace("/","__"))}function It(d){return d==="read_file"||d==="edit_file"||d==="write_file"||d==="bash"}function Ut(d){const t=vt(d);return t?[t.directMessages,t.groupMessages,t.messages].some(e=>Array.isArray(e)&&e.length>0):typeof d=="string"&&d.trim().length>0}function vt(d){if(d&&typeof d=="object"&&!Array.isArray(d))return d;if(!(typeof d!="string"||!d.trim()))try{const t=JSON.parse(d);return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}catch{return}}class ne extends X{constructor(){super(),this.providerId="acode",this.displayName="ACode",this.sessions=new Map,this.expandedBuiltInCapabilities=new Map,this.dispatchableCapabilityTools=new Map,this.listenerWakeHooks=new Map,$.setOnPluginsChanged(t=>{this.syncPluginCommands(t)})}async syncPluginCommands(t){try{const e=await $.getPluginCommands(t);for(const s of this.sessions.values())s.config.agentId===t&&s.runtime.addPluginCommands?.(e)}catch(e){l(`[acode-adapter] syncPluginCommands failed for agent ${t}:`,e.message)}}async startSession(t,e){const s=e.mcpConfigPath||x(),{resolved:o,configContextLimit:a,supportsImage:i}=await this.resolveAcodeProvider(e,s),r=o.model,n=a??xt(r),c=Dt(r),u={sessionId:t,status:"starting",messages:[],createdAt:new Date().toISOString(),totalUsage:{inputTokens:0,outputTokens:0,contextLimit:n,maxOutput:c,cacheHitTokens:0,cacheMissTokens:0}};this.sessions.set(t,{adapterSession:u,config:e,runtime:await this.createRuntime(t,r,e,o,i),autoPollActive:!1,retryAttempt:0,retryActive:!1}),this.emit("status-change",t,"starting");const m=this.sessions.get(t);if(!m)throw new Error("ACode session was not initialized");const p=()=>{const g=this.sessions.get(t);g&&this.getIdlePollLoop(g).start()};this.listenerWakeHooks.set(t,p),rt(e.agentId,p);try{await m.runtime.start(),u.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:m.adapterSession.totalUsage}),e.initialPrompt?.trim()?this.startInitialPromptTurn(t,e.initialPrompt):this.armIdleLoopOrAutoPoll(t)}catch(g){u.status="error",this.emitRuntimeErrorEvent(t,g),this.emit("status-change",t,"error");const f=this.sessions.get(t);throw f?.capabilitiesFallbackTimer&&clearTimeout(f.capabilitiesFallbackTimer),this.sessions.delete(t),this.expandedBuiltInCapabilities.delete(t),this.pruneDispatchableCapabilityTools(e.agentId),q(e.agentId,this.listenerWakeHooks.get(t)),this.listenerWakeHooks.delete(t),g}}async sendMessage(t,e){const s=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 o=this.requireSession(t),a=o.adapterSession.status;l(`[ACode] Previous status: ${a}`),this.cancelScheduledAutoPoll(o),o.failedTurnRecoveryScheduled=!1,o.idlePollLoop?.stop(),this.cancelRequestRetry(o),o.retryAttempt=0;const i={id:v(),sessionId:t,role:"user",content:e,timestamp:new Date().toISOString()};o.adapterSession.messages.push(i),this.emit("conversation-message",t,i),l(`[ACode] Changing status: ${a} \u2192 thinking`),o.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),o.lastSubmittedPrompt=e,this.startSubmitTimeoutDetection(t,o,"sendMessage");try{l("[ACode] \u25B6\uFE0F Calling runtime.submit()...");const r=Date.now();await o.runtime.submit(e);const n=Date.now()-r;this.cancelSubmitTimeoutDetection(o),l(`[ACode] \u2705 runtime.submit() completed in ${n}ms`),l(`[ACode] Current status after submit: ${o.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Calling recoverResolvedTurnWithoutTerminalEvent()..."),this.recoverResolvedTurnWithoutTerminalEvent(t),l(`[ACode] Status after recovery: ${o.adapterSession.status}`);const c=Date.now()-s;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(r){const n=Date.now()-s;console.error(`[ACode] \u274C sendMessage FAILED after ${n}ms:`,r instanceof Error?r.message:String(r)),this.cancelSubmitTimeoutDetection(o),l("[ACode] \u25B6\uFE0F sendMessage failed, scheduling request retry..."),this.emitRuntimeErrorEvent(t,r),this.scheduleRequestRetry(t,"sendMessage"),l(`[ACode] Status after failure: ${o.adapterSession.status}`)}}async sendConfirmation(t,e){}submitToolPermissionDecision(t,e,s){const o=this.sessions.get(t);if(!o)return!1;o.pendingToolAuthRequests?.delete(e);const a=o.runtime.submitToolPermissionDecision?.(e,s)??!1;return a&&this.startSubmitTimeoutDetection(t,o,"submitToolPermissionDecision"),a}getPendingToolAuthRequests(t){const e=this.sessions.get(t);return e?.pendingToolAuthRequests?Array.from(e.pendingToolAuthRequests.entries()).map(([s,o])=>({requestId:s,capability:o.capability,detail:o.detail,requestedAt:o.requestedAt})):[]}async sendQuestionAnswer(t,e){const s=this.sessions.get(t);if(!s)return;const o=s.pendingQuestionToolCallId;if(!o){l(`[AcodeSdkAdapter] sendQuestionAnswer: no pending question for session ${t}`);return}s.pendingQuestionToolCallId=void 0,s.pendingQuestions=void 0,s.runtime.submitQuestionAnswer&&s.runtime.submitQuestionAnswer(o,e),this.startSubmitTimeoutDetection(t,s,"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 s=e.adapterSession.totalUsage;if(e.adapterSession.totalUsage={inputTokens:0,outputTokens:0,contextLimit:s.contextLimit,maxOutput:s.maxOutput,inputLimit:s.inputLimit,compactionThreshold:s.compactionThreshold,cacheHitTokens:s.cacheHitTokens,cacheMissTokens:s.cacheMissTokens},e.adapterSession.status="waiting_input",this.emit("status-change",t,"waiting_input",{usage:e.adapterSession.totalUsage}),e.config.initialPrompt?.trim()){this.startInitialPromptTurn(t,e.config.initialPrompt);return}this.armIdleLoopOrAutoPoll(t)}async terminateSession(t){const e=this.sessions.get(t);if(!e)return;this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),this.cancelRequestRetry(e),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),await e.runtime.stop();const s=e.config.agentId;s&&(q(s,this.listenerWakeHooks.get(t)),nt(s)),this.listenerWakeHooks.delete(t),this.expandedBuiltInCapabilities.delete(t),this.pruneDispatchableCapabilityTools(s),e.adapterSession.status="terminated",this.sessions.delete(t),this.emit("status-change",t,"terminated")}getConversation(t){return this.sessions.get(t)?.adapterSession.messages??[]}hasSession(t){return this.sessions.has(t)}getProviderSessionId(t){return this.sessions.has(t)?t:void 0}getSessionStatus(t){return this.sessions.get(t)?.adapterSession.status}notifyForceMessage(t){const e=this.sessions.get(t);return e?.runtime?.notifyForceMessage?(e.runtime.notifyForceMessage(),!0):!1}getCapabilities(t){return this.sessions.get(t)?.lastCombinedCapabilities}async resolveAgentAiInfo(t){try{const e=[...this.sessions.values()].find(i=>i.config.agentId===t);if(!e)return;const s=e.config.mcpConfigPath||x(),{resolved:o,supportsImage:a}=await this.resolveAcodeProvider(e.config,s);return o?.model?{model:o.model,supportsImage:a===!0,...o.baseURL?{baseURL:o.baseURL}:{},...o.apiKey?{apiKey:o.apiKey}:{}}:void 0}catch{return}}resolveAgentSkillsDir(t){if(t){try{const e=F(t);if(e)return e}catch(e){l(`[acode-adapter] skill farm sync failed for agent ${t}:`,e.message)}return st(t)}return ot()}async applyAgentFeatures(t){if(!t)return;const e=this.shouldInjectCapabilityTools(t,D),s=this.shouldInjectCapabilityTools(t,W);for(const[a,i]of this.sessions){if(i.config.agentId!==t)continue;const r=i.runtime,n=e,c=s;try{if(n){const u=await P(t,await this.resolveAgentAiInfo(t)),m=r.addBuiltInTools?.(u)??0;m>0&&l(`[acode-adapter] session ${a}: ${m} desktop tools hot-added for agent ${t}`)}else{const u=r.removeBuiltInToolsByPrefix?.("desktop_")??0;u>0&&l(`[acode-adapter] session ${a}: ${u} desktop tools hot-removed for agent ${t}`)}}catch(u){l(`[acode-adapter] session ${a}: desktop feature hot-sync failed for agent ${t}:`,u.message)}if(c)try{const u=await L(t,i.config.scopeKey,typeof i.config.browserAllowPrivate=="boolean"?{allowPrivate:i.config.browserAllowPrivate}:void 0),m=r.addBuiltInTools?.(u)??0;m>0&&l(`[acode-adapter] session ${a}: ${m} browser tools hot-added for agent ${t}`)}catch(u){l(`[acode-adapter] session ${a}: browser feature hot-sync failed for agent ${t}:`,u.message)}else{const u=r.removeBuiltInToolsByPrefix?.("browser_")??0;u>0&&l(`[acode-adapter] session ${a}: ${u} browser tools hot-removed for agent ${t}`)}}this.syncMcpToolsForAgent(t);try{F(t)}catch(a){l(`[acode-adapter] skill farm hot-sync failed for agent ${t}:`,a.message)}try{await $.applyCapabilities(t)}catch(a){l(`[acode-adapter] plugin capability hot-sync failed for agent ${t}:`,a.message)}const o=ct(t);for(const[a,i]of this.sessions)if(i.config.agentId===t)try{i.runtime.setToolPermissionPolicy?.(o)}catch(r){l(`[acode-adapter] session ${a}: tool permission policy hot-sync failed for agent ${t}:`,r.message)}}syncMcpToolsForAgent(t){if(t){for(const[e,s]of this.sessions)if(s.config.agentId===t)try{s.runtime.requestMcpToolsRefresh?.()}catch(o){l(`[acode-adapter] session ${e}: mcp tools refresh failed for agent ${t}:`,o.message)}}}async setBuiltInCapabilityTools(t,e,s){if(!t)return{sessions:0,tools:0};const o=e==="browser"?"browser_":e==="desktop"?"desktop_":void 0;if(!o)return{sessions:0,tools:0};let a=0,i=0,r;const n=this.dispatchableCapabilityTools.get(t)?.get(e)?.length??0;let c=0;for(const[u,m]of this.sessions)if(m.config.agentId===t)try{if(s==="collapse"){const A=this.expandedBuiltInCapabilities.get(u)?.delete(e)??!1,y=m.runtime.removeBuiltInToolsByPrefix?.(o)??0;c+=y,(A||y>0)&&(a+=1,i+=y,l(`[acode-adapter] session ${u}: collapsed ${e} capability for agent ${t}`));continue}const p=e==="browser"?await L(t,m.config.scopeKey,typeof m.config.browserAllowPrivate=="boolean"?{allowPrivate:m.config.browserAllowPrivate}:void 0):await P(t,await this.resolveAgentAiInfo(t));if(!this.sessions.has(u))continue;let g=this.dispatchableCapabilityTools.get(t);g||(g=new Map,this.dispatchableCapabilityTools.set(t,g)),g.set(e,[...p]);let f=this.expandedBuiltInCapabilities.get(u);f||(f=new Set,this.expandedBuiltInCapabilities.set(u,f)),f.add(e),a+=1,i=p.length,r=p.map(A=>({name:A.toolName,description:A.description,inputSchema:A.inputSchema})),l(`[acode-adapter] session ${u}: ${p.length} ${e} tools dispatchable for agent ${t}`)}catch(p){l(`[acode-adapter] session ${u}: ${e} ${s} failed for agent ${t}:`,p.message)}return s==="collapse"?(this.dispatchableCapabilityTools.get(t)?.delete(e),{sessions:a,tools:n>0?n:c,manifests:r}):{sessions:a,tools:i,manifests:r}}async callBuiltInCapabilityTool(t,e,s,o){if(!t)return{ok:!1,error:"\u7F3A\u5C11 agentId"};if(e!=="browser"&&e!=="desktop")return{ok:!1,error:`\u672A\u77E5\u6865\u63A5\u80FD\u529B\u300C${e}\u300D`};if(!s.startsWith(`${e}_`))return{ok:!1,error:`\u5DE5\u5177\u300C${s}\u300D\u4E0D\u5C5E\u4E8E\u80FD\u529B\u300C${e}\u300D`};if(O(t,e)==="disabled")return{ok:!1,error:`\u80FD\u529B\u300C${e}\u300D\u672A\u5F00\u542F\uFF08\u5DF2\u7981\u7528\uFF0C\u8BF7\u5148\u5728\u80FD\u529B\u914D\u7F6E\u4E2D\u5F00\u542F\uFF09\u3002`};if(![...this.expandedBuiltInCapabilities.entries()].some(([n,c])=>c.has(e)&&this.sessions.get(n)?.config.agentId===t))return{ok:!1,error:`\u80FD\u529B\u300C${e}\u300D\u5C1A\u672A\u5C55\u5F00\uFF0C\u8BF7\u5148\u8C03\u7528 expand_tools({ group: "${e}" })\u3002`};let i=this.dispatchableCapabilityTools.get(t)?.get(e);if(!i||i.length===0)try{const n=[...this.sessions.values()].find(u=>u.config.agentId===t);i=e==="browser"?await L(t,n?.config.scopeKey,typeof n?.config.browserAllowPrivate=="boolean"?{allowPrivate:n.config.browserAllowPrivate}:void 0):await P(t,await this.resolveAgentAiInfo(t));let c=this.dispatchableCapabilityTools.get(t);c||(c=new Map,this.dispatchableCapabilityTools.set(t,c)),c.set(e,[...i])}catch(n){return{ok:!1,error:`\u6865\u63A5\u80FD\u529B\u5DE5\u5177\u6784\u5EFA\u5931\u8D25\uFF1A${n instanceof Error?n.message:String(n)}`}}const r=i.find(n=>n.toolName===s);if(!r)return{ok:!1,error:`\u80FD\u529B\u300C${e}\u300D\u4E0B\u4E0D\u5B58\u5728\u5DE5\u5177\u300C${s}\u300D`};try{return{ok:!0,result:await r.execute(o)}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}}pruneDispatchableCapabilityTools(t){if(!t)return;[...this.sessions.values()].some(s=>s.config.agentId===t)||this.dispatchableCapabilityTools.delete(t)}shouldInjectCapabilityTools(t,e){return t?O(t,e)==="expanded":!0}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 s=this.sessions.get(t);if(s){if(s.idleCommands=e,this.cancelScheduledAutoPoll(s),e.idleInputCommand&&M(e.idleInputCommand)){this.getIdlePollLoop(s).start();return}s.adapterSession.status==="waiting_input"&&(e.idleInputCommand||e.nonInputCommand)&&this.getIdlePollLoop(s).start()}}setRuntimeConstructorForTest(t){this.runtimeConstructor=t}async loadAcodeProviderSection(t){try{const e=await V.readFile(t,"utf-8"),s=JSON.parse(e),a=s.provider?.default,i=a?.options,r=h(s.contextLimit),n={},c={},u=a?.models;if(u&&typeof u=="object"){for(const[m,p]of Object.entries(u))if(p&&typeof p=="object"){const g=h(p.contextLimit);g>0&&(n[m.trim()]=g);const f=p.modalities?.input,A=Array.isArray(f)&&f.includes("image")||p.supportsImageInput===!0;c[m.trim()]=A===!0}}return{...a?.model?{model:a.model}:{},...i?.baseURL||i?.baseUrl?{baseURL:i?.baseURL||i?.baseUrl}:{},...i?.apiKey?{apiKey:i.apiKey}:{},...r>0?{contextLimit:r}:{},...Object.keys(n).length>0?{modelContextLimits:n}:{},...Object.keys(c).length>0?{modelImageSupport:c}:{}}}catch(e){const s=e instanceof Error?e.message:String(e);return E().log({level:"warn",category:"load",message:`loadAcodeProviderSection failed: ${t}: ${s}`,source:"bridge"}),{}}}async resolveAcodeProvider(t,e){const s=typeof t.model=="string"&&t.model.trim()?t.model.trim():void 0,o=E();o.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u8F93\u5165",source:"bridge",details:{configModel:t.model??null,configInstanceAiConfig:t.instanceAiConfig?B(t.instanceAiConfig):null,configPath:e}});const a={...t.instanceAiConfig?.model?{model:t.instanceAiConfig.model}:{},...t.instanceAiConfig?.baseURL?{baseURL:t.instanceAiConfig.baseURL}:{},...t.instanceAiConfig?.apiKey?{apiKey:t.instanceAiConfig.apiKey}:{},...t.instanceAiConfig?.effort?{effort:t.instanceAiConfig.effort}:{},...s?{model:s}:{}},i=await this.loadAcodeProviderSection(e);let r=i.contextLimit;if(!r&&i.modelContextLimits){const c=s||t.instanceAiConfig?.model||i.model;c&&i.modelContextLimits[c]&&(r=i.modelContextLimits[c])}const n=ht(a,i,"acode-default");return o.log({level:"info",category:"resolve",message:"resolveAcodeProvider \u89E3\u6790\u7ED3\u679C",source:"bridge",details:{instanceConfig:B(a),globalConfigModel:i?.model??null,resolvedModel:n.model,resolvedBaseURL:n.baseURL??null,resolvedApiKey:n.apiKey?"[set]":null,configContextLimit:r,resolvedSource:n.source}}),{resolved:n,configPath:e,perSessionModel:s,configContextLimit:r,supportsImage:i.modelImageSupport?.[n.model]===!0}}async createRuntime(t,e,s,o,a){const i=await this.loadRuntimeConstructor(),r=s.mcpConfigPath||x();let n=[];try{n=await L(s.agentId,s.scopeKey,typeof s.browserAllowPrivate=="boolean"?{allowPrivate:s.browserAllowPrivate}:void 0)}catch(p){l(`[acode-adapter] browser tools injection skipped for agent ${s.agentId}:`,p.message)}let c=[];if(this.shouldInjectCapabilityTools(s.agentId??"",W)&&(c=n),s.agentId&&this.shouldInjectCapabilityTools(s.agentId,D))try{const p=o?.model?{model:o.model,supportsImage:a===!0,...o.baseURL?{baseURL:o.baseURL}:{},...o.apiKey?{apiKey:o.apiKey}:{}}:void 0,g=await P(s.agentId,p);g.length>0&&(c=[...c,...g])}catch(p){l(`[acode-adapter] desktop tools injection skipped for agent ${s.agentId}:`,p.message)}const u=new i({sessionId:t,agentId:s.agentId,workingDirectory:s.workingDirectory,configPath:r,skillsDir:this.resolveAgentSkillsDir(s.agentId),pluginsDir:s.agentId?et(s.agentId):void 0,model:e,systemPrompt:typeof s.systemPrompt=="string"?s.systemPrompt:void 0,globalPrompt:typeof s.globalPrompt=="string"?s.globalPrompt:void 0,rolePrompt:typeof s.rolePrompt=="string"?s.rolePrompt:void 0,memory:typeof s.memory=="string"?s.memory:void 0,env:s.envOverrides,subAgentManager:mt,terminalManager:at,capabilityState:p=>O(s.agentId??"",p),pluginBridge:s.agentId?$.forAgent(s.agentId):void 0,commandDirs:[Z(new URL("../services/builtin-commands/",import.meta.url))],...s.subAgentModel?{subAgentModel:s.subAgentModel}:{},...s.subAgentEffort?{subAgentEffort:s.subAgentEffort}:{},...s.instanceAiConfig?.effort?{effort:s.instanceAiConfig.effort}:{},onFileChange:p=>pt({...p,agentId:s.agentId,workspacePath:s.workingDirectory}),extraBuiltInTools:c,...s.agentId?{toolPermissionPolicy:ut(s.agentId)??void 0}:{},subAgentSuiteTools:n,subAgentSuiteToolProvider:this.buildSubAgentSuiteToolProvider(s.agentId)});return E().log({level:"info",category:"resolve",message:"ACode provider resolved",source:"bridge",sessionId:t,details:{resolvedModel:e,perInstanceModel:s.instanceAiConfig?.model||null,perInstanceBaseURL:s.instanceAiConfig?.baseURL?"[set]":null,perInstanceApiKey:s.instanceAiConfig?.apiKey?"[set]":null,configPath:r}}),u.on("event",p=>this.forwardAcodeEvent(p)),u}buildSubAgentSuiteToolProvider(t){return async e=>{if(!t)return[];if(!dt(t,D))return[];if(e.length===0)return lt();if(!e.some(a=>{const i=a.trim().replace(/[.*]+$/,"");return i==="desktop"||i.startsWith("desktop.")}))return[];const o=await this.resolveAgentAiInfo(t);return P(t,o)}}async loadRuntimeConstructor(){if(this.runtimeConstructor)return this.runtimeConstructor;const t=$t(),e=await import(Lt(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 s=this.sessions.get(t);s&&(s.adapterSession.status="thinking",this.emit("status-change",t,"thinking"),s.lastSubmittedPrompt=e,this.startSubmitTimeoutDetection(t,s,"startInitialPromptTurn"),s.runtime.submit(e).then(()=>{this.cancelSubmitTimeoutDetection(s),this.recoverResolvedTurnWithoutTerminalEvent(t)}).catch(o=>{const a=this.sessions.get(t);a&&(this.cancelSubmitTimeoutDetection(a),this.emitRuntimeErrorEvent(t,o),this.scheduleRequestRetry(t,"startInitialPromptTurn"))}))}forwardAcodeEvent(t){const e=this.sessions.get(t.sessionId);if(e){if(e.autoPollActive&&(e.autoPollLastActivityAt=Date.now()),t.type==="assistant_delta"){const s=typeof t.data.text=="string"?t.data.text:"";e.autoPollActive&&(e.autoPollObservedAssistantText=!0),e.adapterSession.messages.push({id:v(),sessionId:t.sessionId,role:"assistant",content:s,timestamp:t.timestamp}),this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"text_delta",{text:s});return}if(t.type==="thinking_delta"){const s=typeof t.data.text=="string"?t.data.text:"";this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"thinking",{text:s});return}if(t.type==="command_output"){this.emitProviderEvent(t,"command_output",{text:typeof t.data.text=="string"?t.data.text:"",stream:Et(t.data.stream),sequence:typeof t.data.sequence=="number"?t.data.sequence:void 0,cwd:typeof t.data.cwd=="string"?t.data.cwd:void 0,commandLineCount:typeof t.data.commandLineCount=="number"?t.data.commandLineCount:void 0,commandFilePath:typeof t.data.commandFilePath=="string"?t.data.commandFilePath:void 0});return}if(t.type==="background_command_completed"){this.emitProviderEvent(t,"background_command_completed",t.data);return}if(t.type==="ai_request"){const s=z(t.data),o=t.data.lastUsage,a=h(o?.inputTokens),i=h(o?.outputTokens),r=h(o?.cacheHitTokens),n=h(o?.cacheMissTokens),c=!!(o&&(a>0||i>0));let u;if(c&&(a>0&&(e.adapterSession.totalUsage.inputTokens=a),i>0&&(e.adapterSession.totalUsage.outputTokens=i),(o?.cacheHitTokens!==void 0||o?.cacheMissTokens!==void 0)&&(e.adapterSession.totalUsage.cacheHitTokens=r,e.adapterSession.totalUsage.cacheMissTokens=n),u={...e.adapterSession.totalUsage},k(`ai_request lastUsage applied: ${JSON.stringify(o)} -> totalUsage=${JSON.stringify(e.adapterSession.totalUsage)}`)),!c&&s>0){const g=e.adapterSession.totalUsage.inputTokens;g>0?e.adapterSession.totalUsage.inputTokens=Math.min(s,Math.floor(g*1.5)):e.adapterSession.totalUsage.inputTokens=s,u={...e.adapterSession.totalUsage}}e.adapterSession.status==="compacting"&&(e.adapterSession.status="thinking"),e.adapterSession.status==="waiting_input"&&(e.adapterSession.status="thinking");const p={actionType:"ai_request",actionLabel:"AI\u8BF7\u6C42",actionDetail:this.formatAiRequestActionDetail(t.data)};u&&(p.usage=u),k(`ai_request handled: estimatedContextTokens=${t.data.estimatedContextTokens??"n/a"} totalUsage=${JSON.stringify(e.adapterSession.totalUsage)} displayUsage=${JSON.stringify(u??null)}`),this.emit("status-change",t.sessionId,e.adapterSession.status,p),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:Mt(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 s=Ot(t.data.usage);if(s){const a=e.adapterSession.totalUsage.inputTokens,i=a>0&&s.inputTokens<Math.floor(a*.2)&&!s.hasCache;k(`turn_complete usage: raw=${JSON.stringify(t.data.usage)} parsed=${JSON.stringify(s)} currentInput=${a} threshold20pct=${Math.floor(a*.2)} isFallbackUsage=${i}`),i?s.outputTokens>0&&(e.adapterSession.totalUsage.outputTokens=s.outputTokens):(e.adapterSession.totalUsage.inputTokens=s.inputTokens,e.adapterSession.totalUsage.outputTokens=s.outputTokens),(s.cacheHitTokens||s.cacheMissTokens)&&(e.adapterSession.totalUsage.cacheHitTokens=s.cacheHitTokens,e.adapterSession.totalUsage.cacheMissTokens=s.cacheMissTokens,l(`[ACode] \u{1F4B0} Cache usage (overwrite from runtime cumulative): hit=${e.adapterSession.totalUsage.cacheHitTokens}, miss=${e.adapterSession.totalUsage.cacheMissTokens} (turn delta: hit=${s.cacheHitTokens||0}, miss=${s.cacheMissTokens||0})`)),k(`totalUsage after turn_complete: ${JSON.stringify(e.adapterSession.totalUsage)}`)}else k(`turn_complete has NO parseable usage: raw=${JSON.stringify(t.data.usage)} failed=${t.data.failed===!0} aborted=${t.data.aborted===!0}`);const o=e.adapterSession.status;if(l(`[ACode] turn_complete event received (session: ${t.sessionId}), previous status: ${o}, failed: ${t.data.failed===!0}, aborted: ${t.data.aborted===!0}`),Rt(t.data)){l(`[ACode] Scheduling retry from failed turn_complete (session: ${t.sessionId})`),this.cancelDataFlowWatchdog(e),this.recoverTurnFailure(t.sessionId,e);return}if(t.data.aborted===!0&&(e.autoPollActive||e.retryActive||e.retryTimer)){l(`[ACode] Scheduling retry from aborted turn_complete (session: ${t.sessionId})`),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}),k(`status-change emitted (waiting_input after turn_complete): usage=${JSON.stringify(e.adapterSession.totalUsage)}`),l(`[ACode] Status changed to waiting_input after turn_complete (session: ${t.sessionId})`),e.autoPollActive&&e.autoPollObservedAssistantText&&!e.autoPollObservedPollingTool&&!e.autoPollObservedAnyTool){e.stopAutoPollAfterCurrentTurn=!0,console.warn(`[${this.displayName}] Auto-poll turn produced assistant text without calling any tool; stopping auto-poll rearm for session ${t.sessionId}`);return}this.armIdleLoopOrAutoPoll(t.sessionId);return}if(t.type==="session_complete"){this.cancelDataFlowWatchdog(e),this.cancelScheduledAutoPoll(e),e.failedTurnRecoveryScheduled=!1,e.idlePollLoop?.stop(),e.adapterSession.status="completed",this.emitProviderEvent(t,"session_complete",{exitCode:Number(t.data.exitCode)||0}),this.emit("status-change",t.sessionId,"completed");return}if(t.type==="question_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const s=typeof t.data.toolCallId=="string"?t.data.toolCallId:"",o=Array.isArray(t.data.questions)?t.data.questions:[];s&&(e.pendingQuestionToolCallId=s,e.pendingQuestions=o),this.emit("ask-user-question",{sessionId:t.sessionId,toolCallId:s||void 0,questions:o});return}if(t.type==="tool_permission_request"){this.cancelDataFlowWatchdog(e),this.cancelSubmitTimeoutDetection(e);const s=typeof t.data.requestId=="string"?t.data.requestId:"";s&&(e.pendingToolAuthRequests||(e.pendingToolAuthRequests=new Map),e.pendingToolAuthRequests.set(s,{capability:String(t.data.capability||""),detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation},requestedAt:Date.now()})),this.emit("tool-permission-request",{sessionId:t.sessionId,requestId:s,capability:String(t.data.capability||""),agentId:e.config.agentId,detail:{path:t.data.path,command:t.data.command,cwd:t.data.cwd,operation:t.data.operation}});return}if(t.type==="error"){if(t.data.nonFatal){this.resetDataFlowWatchdog(t.sessionId,e),this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")});return}this.cancelDataFlowWatchdog(e),e.adapterSession.status="error",this.emitProviderEvent(t,"error",{text:String(t.data.message||"ACode runtime error")}),this.emit("status-change",t.sessionId,"error"),e.autoPollActive||this.recoverTurnFailure(t.sessionId,e);return}if(t.type==="mcp_status"){if(!t.data.action&&Array.isArray(t.data.tools)){const f=t.data.tools;f.some(T=>gt(T))||console.warn(`[${this.displayName}] ACode runtime is not exposing a poll_message tool. The LLM cannot call poll_message. Please configure an MCP server that provides poll_message (e.g. aws-mcp) in the dashboard panel for this runtime.`);const y=Array.isArray(t.data.servers)?t.data.servers:[],S=f.map(T=>({name:String(T.name??""),source:String(T.source??""),description:String(T.description??"")})).filter(T=>T.name),_={kind:"mcp",mcpServers:y,mcpTools:S};e.cachedMcpCapabilities=_,e.lastMcpCapabilities=_,e.lastCombinedCapabilities={kind:"combined",mcpServers:y,mcpTools:S,skills:e.lastCombinedCapabilities?.skills??[],skillsDir:e.lastCombinedCapabilities?.skillsDir,skillGroups:e.lastCombinedCapabilities?.skillGroups??[]},l(`[cap-diag] MCP capabilities cached: ${y.length} servers, ${S.length} tools`,{sessionId:t.sessionId,servers:y,toolNames:S.map(T=>T.name)}),e.capabilitiesFallbackTimer&&clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=setTimeout(()=>{const T=e.cachedMcpCapabilities;if(!T)return;const C={...T,skills:[],skillGroups:[]};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:C,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(C)}),l(`[cap-diag] MCP capabilities emitted via fallback (skill_status not received within ${Q}ms)`,{sessionId:t.sessionId,mcpServers:T.mcpServers,mcpToolsCount:T.mcpTools?.length??0}),e.cachedMcpCapabilities=void 0,e.capabilitiesFallbackTimer=void 0},Q);return}const s=String(t.data.action??"");l(`[ACode] \u{1F4E1} mcp_status event: action=${s}, 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 o=typeof t.data.server=="string"?t.data.server:"mcp",a=typeof t.data.tool=="string"?t.data.tool:"",i=o&&a?`${o}__${a}`:a||o,r=t.data.arguments&&typeof t.data.arguments=="object"&&!Array.isArray(t.data.arguments)?t.data.arguments:void 0,n=At(i,r);e.autoPollActive&&(e.autoPollObservedAnyTool=!0,n.actionType==="idle"&&(e.autoPollObservedPollingTool=!0));const c=It(n.actionType)?n.actionDetail||Y(void 0,o,a):Y(n.actionDetail,o,a),u=typeof t.data.toolUseId=="string"?t.data.toolUseId:void 0,m=r?JSON.stringify(r,null,2):void 0,p={toolName:c,rawToolName:i,actionType:n.actionType,actionLabel:n.actionLabel,actionDetail:c,...m?{actionInput:m}:{},...r?{toolInput:r}:{},...u?{toolUseId:u,actionId:u}:{},metadata:{mcpServer:o}};if(t.data.action==="tool_result"){this.emitProviderEvent(t,"tool_use_end",{...p,toolResult:typeof t.data.result=="string"?t.data.result:JSON.stringify(t.data.result??"")});const f=n.actionType==="idle"&&!Ut(t.data.result)?"waiting_input":"thinking";e.adapterSession.status=f,n.actionType==="idle"&&(e.idleToolActiveAt=void 0),this.cancelDataFlowWatchdog(e),e.pendingToolEventData=void 0;const A=n.actionType==="idle";this.emit("status-change",t.sessionId,f,A||f==="thinking"?void 0:p);return}const g=n.actionType==="idle"?"waiting_input":"tool_using";e.adapterSession.status=g,n.actionType==="idle"&&(e.idleToolActiveAt=Date.now()),g==="tool_using"&&(this.resetDataFlowWatchdog(t.sessionId,e),e.pendingToolEventData={...p}),this.emitProviderEvent(t,"tool_use_start",p),this.emit("status-change",t.sessionId,g,p);return}if(t.type==="skill_status"){const o=(Array.isArray(t.data.skills)?t.data.skills:[]).map(m=>({name:String(m.name??""),description:typeof m.description=="string"?m.description:void 0,directory:typeof m.directory=="string"?m.directory:void 0})).filter(m=>m.name),a=typeof t.data.skillsDir=="string"?t.data.skillsDir:void 0,r=(Array.isArray(t.data.skillGroups)?t.data.skillGroups:[]).map(m=>{const p=Array.isArray(m.skills)?m.skills:[];return{dir:typeof m.dir=="string"?m.dir:"",exists:m.exists===!0,skills:p.map(g=>({name:String(g.name??""),description:typeof g.description=="string"?g.description:void 0,directory:typeof g.directory=="string"?g.directory:void 0})).filter(g=>g.name)}}).filter(m=>m.dir),n=e.cachedMcpCapabilities??e.lastMcpCapabilities,c=e.cachedMcpCapabilities!==void 0,u={kind:"combined",mcpServers:n?.mcpServers??[],mcpTools:n?.mcpTools??[],skills:o,skillsDir:a,skillGroups:r};this.emitProviderEvent(t,"runtime_capabilities",{capabilities:u,actionType:"runtime_capabilities",actionLabel:"\u8FD0\u884C\u65F6\u80FD\u529B",actionDetail:JSON.stringify(u)}),e.lastCombinedCapabilities=u,l(`[cap-diag] Combined capabilities emitted ${c?"(startup merge)":"(runtime refresh)"}: ${(n?.mcpTools??[]).length} MCP tools, ${o.length} skills`,{sessionId:t.sessionId,mcpServers:n?.mcpServers??[],skillsDir:a}),e.capabilitiesFallbackTimer&&(clearTimeout(e.capabilitiesFallbackTimer),e.capabilitiesFallbackTimer=void 0),e.cachedMcpCapabilities=void 0;return}if(t.type==="startup_phase"){l(`[ACode] \u{1F680} startup_phase swallowed: ${String(t.data.phase??"unknown")}`,{sessionId:t.sessionId});return}if(t.type==="command_status"){if(t.data.action==="commands_loaded"){l(`[ACode] \u{1F4CB} command_status commands_loaded swallowed: ${typeof t.data.installedCommandCount=="number"?t.data.installedCommandCount:"?"} commands`,{sessionId:t.sessionId});return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)});return}if(t.type==="session_started"){const s=z(t.data),o=h(t.data.contextLimit)||void 0,a=h(t.data.maxOutput)||void 0,i=h(t.data.inputLimit)||void 0,r=h(t.data.compactionThreshold)||void 0;let n=!1;s>0&&(e.adapterSession.totalUsage.inputTokens=s,e.adapterSession.totalUsage.outputTokens=0,n=!0),o!==void 0&&(e.adapterSession.totalUsage.contextLimit=o,n=!0),a!==void 0&&(e.adapterSession.totalUsage.maxOutput=a,n=!0),i!==void 0&&(e.adapterSession.totalUsage.inputLimit=i,n=!0),r!==void 0&&(e.adapterSession.totalUsage.compactionThreshold=r,n=!0),n&&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 s=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:s||"\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"}),this.emit("status-change",t.sessionId,"waiting_input",{actionLabel:"\u5BA1\u6279\u8BA1\u5212",actionDetail:s||"\u7B49\u5F85\u7528\u6237\u5BA1\u6279\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F"});return}if(t.type==="context_compaction"){const s=t.data,o=s.action,a=o==="start",i=o==="end",r=o==="phase",n=s.parentId,c=s.compactionId;let u,m;if(a){const g=String(s.sizeKB??s.sizeBeforeKB??"?"),f=String(s.messageCount??s.messageCountBefore??"?"),A=s.estimatedTokens,y=s.actualInputTokens?`input=${s.actualInputTokens}`:"",S=s.actualOutputTokens?`output=${s.actualOutputTokens}`:"",_=s.trigger?`, \u89E6\u53D1: ${s.trigger}`:"";u="\u4E0A\u4E0B\u6587\u538B\u7F29\u5F00\u59CB",A!==void 0?m=`\u538B\u7F29\u524D: ~${A} tokens, \u6D88\u606F: ${f}\u6761`+(y?`, \u5B9E\u9645 tokens: ${y} ${S}`:"")+_:m=`\u538B\u7F29\u524D: ${g}KB, \u6D88\u606F: ${f}\u6761`+(y?`, \u5B9E\u9645 tokens: ${y} ${S}`:"")+_}else if(r)u=String(s.phaseLabel??"\u538B\u7F29\u9636\u6BB5"),m=String(s.phaseDetail??"");else{const g=s.tokensBefore,f=s.tokensAfter,A=s.freedTokens,y=String(s.sizeBeforeKB??"?"),S=String(s.sizeAfterKB??"?"),_=String(s.freedKB??"?"),T=String(s.strategy??"?"),C=Number(s.prunedToolMessages??0),b=Number(s.summarizedMessages??0);u="\u538B\u7F29\u5B8C\u6210",g!==void 0&&f!==void 0?m=`\u91CA\u653E: ${A??g-f} tokens, ${g} tokens \u2192 ${f} tokens, \u7B56\u7565: ${T}`+(C?`, \u88C1\u526A\u5DE5\u5177: ${C}\u6761`:"")+(b?`, \u6458\u8981\u5316: ${b}\u6761`:""):m=`\u91CA\u653E: ${_}KB, ${y}KB \u2192 ${S}KB, \u7B56\u7565: ${T}`+(C?`, \u88C1\u526A\u5DE5\u5177: ${C}\u6761`:"")+(b?`, \u6458\u8981\u5316: ${b}\u6761`:"")}a&&(e.adapterSession.status="compacting");const p={actionType:"context_compaction",actionLabel:u,actionDetail:m};if(a&&c)p.actionId=c;else if((r||i)&&c)if(p.parentId=c,r){const g=String(s.phase??"unknown");p.actionId=`${c}-phase-${g}`}else p.actionId=`${c}-end`;r&&n&&!p.parentId&&(p.parentId=n),i&&(e.adapterSession.totalUsage.inputTokens=h(s.tokensAfter),e.adapterSession.totalUsage.outputTokens=0,e.config.agentId&&$.markAgentCompacted(e.config.agentId),p.usage={...e.adapterSession.totalUsage}),this.emitProviderEvent(t,"context_compaction",p),this.emit("status-change",t.sessionId,"compacting",p);return}this.emitProviderEvent(t,"thinking",{text:JSON.stringify(t.data)})}}emitProviderEvent(t,e,s){this.emit("event",{type:e,sessionId:t.sessionId,timestamp:t.timestamp,data:s})}armIdleLoopOrAutoPoll(t){const e=this.sessions.get(t);if(!(!e||this.isTerminalStatus(e.adapterSession.status))){if(this.cancelRequestRetry(e),e.retryAttempt=0,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 ft({getStatus:()=>this.sessions.get(e)?.adapterSession.status,getCommand:()=>this.sessions.get(e)?.idleCommands?.idleInputCommand,isPollingCommand:s=>M(s),preDispatchHook:()=>null,dispatchPollingPrompt:(s,o)=>this.submitAutoPollPrompt(e,o?s:Pt,{keepWaitingStatus:!0}),dispatchRegularIdleCommand:s=>this.submitAutoPollPrompt(e,s)}),t.idlePollLoop}submitAutoPollPrompt(t,e,s){const o=this.sessions.get(t);if(!o||this.isTerminalStatus(o.adapterSession.status))return;const a=(o.autoPollToken??0)+1;o.autoPollToken=a,o.autoPollActive=!0,o.autoPollObservedPollingTool=!1,o.autoPollObservedAssistantText=!1,o.autoPollObservedAnyTool=!1,o.stopAutoPollAfterCurrentTurn=!1,o.autoPollQueuedAt=Date.now(),o.autoPollLastActivityAt=Date.now(),o.idleToolActiveAt=void 0,o.lastSubmittedPrompt=e,s?.keepWaitingStatus||(o.adapterSession.status="thinking",this.emit("status-change",t,"thinking")),this.startSubmitTimeoutDetection(t,o,"submitAutoPollPrompt"),o.runtime.submit(e).catch(i=>{this.emitRuntimeErrorEvent(t,i),this.scheduleRequestRetry(t,"submitAutoPollPrompt")}).finally(()=>{const i=this.sessions.get(t);if(i){if(i.autoPollToken!==a){l(`[ACode] submitAutoPollPrompt.finally: token mismatch (my=${a}, current=${i.autoPollToken}), skipping cleanup \u2014 newer turn has taken over`);return}if(this.cancelSubmitTimeoutDetection(i),i.autoPollActive=!1,i.failedTurnRecoveryScheduled||i.autoPollTimer){i.failedTurnRecoveryScheduled=!1;return}if(i.stopAutoPollAfterCurrentTurn){i.stopAutoPollAfterCurrentTurn=!1,i.autoPollObservedPollingTool=!1,i.autoPollObservedAssistantText=!1,i.autoPollObservedAnyTool=!1;return}if(i.adapterSession.status==="error"){this.recoverTurnFailure(t,i);return}if(i.adapterSession.status==="thinking"||i.adapterSession.status==="tool_using"){this.recoverResolvedTurnWithoutTerminalEvent(t);return}i.adapterSession.status==="waiting_input"&&this.armIdleLoopOrAutoPoll(t)}})}scheduleAutoPoll(t,e=wt){const s=this.sessions.get(t);!s||s.autoPollActive||s.autoPollTimer||this.isTerminalStatus(s.adapterSession.status)||(s.autoPollTimer=setTimeout(()=>{const o=this.sessions.get(t);!o||o.autoPollActive||this.isTerminalStatus(o.adapterSession.status)||(o.autoPollTimer=void 0,this.submitAutoPollPrompt(t,St,{keepWaitingStatus:!0}))},e))}cancelScheduledAutoPoll(t){t.autoPollTimer&&(clearTimeout(t.autoPollTimer),t.autoPollTimer=void 0)}scheduleRequestRetry(t,e){const s=this.sessions.get(t);if(!s||this.isTerminalStatus(s.adapterSession.status)||s.retryActive||s.retryTimer)return;if(!s.lastSubmittedPrompt){s.adapterSession.status="error",this.emit("status-change",t,"error");return}s.retryAttempt+=1,s.retryActive=!0,this.cancelScheduledAutoPoll(s),s.idlePollLoop?.stop();const o=H[Math.min(s.retryAttempt-1,H.length-1)];s.adapterSession.status="error",this.emit("status-change",t,"error",{actionType:"retry",actionLabel:"\u91CD\u8BD5\u4E2D",actionDetail:`\u7B2C${s.retryAttempt}\u6B21 \xB7 ${Math.round(o/1e3)}s\u540E`}),l(`[ACode] scheduleRequestRetry(${e}): attempt=${s.retryAttempt} delay=${o}ms`),s.retryTimer=setTimeout(()=>{s.retryTimer=void 0,this.retryFailedRequest(t,e)},o)}retryFailedRequest(t,e){const s=this.sessions.get(t);if(!s)return;if(s.retryTimer=void 0,this.isTerminalStatus(s.adapterSession.status)||!s.lastSubmittedPrompt){s.retryActive=!1;return}s.retryActive=!1;const o=s.lastSubmittedPrompt;l(`[ACode] retryFailedRequest(${e}): attempt=${s.retryAttempt} re-submitting...`),s.adapterSession.status="thinking",this.emit("status-change",t,"thinking",{usage:s.adapterSession.totalUsage}),this.startSubmitTimeoutDetection(t,s,"retryFailedRequest"),s.runtime.submit(o).then(()=>{const a=this.sessions.get(t);!a||a.retryTimer||(this.cancelSubmitTimeoutDetection(a),a.retryAttempt=0,a.retryActive=!1,this.recoverResolvedTurnWithoutTerminalEvent(t))}).catch(a=>{const i=this.sessions.get(t);i&&(this.cancelSubmitTimeoutDetection(i),this.emitRuntimeErrorEvent(t,a),this.scheduleRequestRetry(t,`retry#${i.retryAttempt+1}`))})}cancelRequestRetry(t){t.retryTimer&&(clearTimeout(t.retryTimer),t.retryTimer=void 0),t.retryActive=!1}isTerminalStatus(t){return t==="completed"||t==="terminated"}emitRuntimeErrorEvent(t,e){const s=new Date().toISOString();this.emit("event",{type:"error",sessionId:t,timestamp:s,data:{text:e instanceof Error?e.message:String(e)}})}estimateOutputTokensFromMessages(t){const e=t.filter(s=>s.role==="assistant").map(s=>s.content).join("");return Math.max(0,Math.round(e.length/4))}recoverTurnFailure(t,e){if(this.isTerminalStatus(e.adapterSession.status))return;if(e.idleToolActiveAt=void 0,e.pendingToolAuthRequests?.size&&e.pendingToolAuthRequests.clear(),e.adapterSession.status==="tool_using"&&e.pendingToolEventData){const o=e.pendingToolEventData;l(`[ACode] recoverTurnFailure: \u8865\u53D1 tool_use_end (tool: ${o.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:{...o,toolResult:"[aborted] \u5DE5\u5177\u6267\u884C\u88AB\u6570\u636E\u6D41\u770B\u95E8\u72D7\u4E2D\u65AD"}}),e.pendingToolEventData=void 0}const s=this.estimateOutputTokensFromMessages(e.adapterSession.messages);if(s>0){const o=e.adapterSession.totalUsage.outputTokens;e.adapterSession.totalUsage.outputTokens=s,l(`[ACode] recoverTurnFailure: \u4F30\u7B97\u8986\u76D6 output tokens ${o} -> ${s} (totalUsage now: input=${e.adapterSession.totalUsage.inputTokens}, output=${e.adapterSession.totalUsage.outputTokens})`)}this.cancelScheduledAutoPoll(e),this.scheduleRequestRetry(t,"recoverTurnFailure")}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 s=e.idleCommands?.idleInputCommand,a=!!(s&&M(s))?{actionType:"idle",actionLabel:"\u76D1\u542C\u6D88\u606F",actionDetail:"aws-mcp/poll_message"}:void 0;this.emit("status-change",t,"waiting_input",a),l(`[ACode] \u2705 Recovery complete, status now: ${e.adapterSession.status}`),l("[ACode] \u25B6\uFE0F Arming idle loop or auto-poll..."),this.armIdleLoopOrAutoPoll(t),l("[ACode] \u2705 Idle loop armed, recovery process complete")}startSubmitTimeoutDetection(t,e,s){this.cancelSubmitTimeoutDetection(e),e.watchdogSubmitStartTime=Date.now(),e.watchdogLastDataFlowTime=Date.now(),e.watchdogTimer=setInterval(()=>{const o=this.sessions.get(t);if(!o){this.cancelSubmitTimeoutDetection(e);return}const a=o.adapterSession.status,i=Date.now();if(a==="waiting_input"){if(o.autoPollActive&&o.autoPollLastActivityAt&&o.idleToolActiveAt===void 0&&i-o.autoPollLastActivityAt>=kt){console.warn(`[ACode] CRITICAL: stuck auto-poll detected after ${Math.round((i-o.autoPollLastActivityAt)/1e3)}s (source: ${s}, session: ${t}): submit queued but no runtime events and no active poll_message tool. Forcing recovery (runtime force-settle will unblock submitQueue).`),this.executeWatchdogRecovery(t,o,s,"stuck_autopoll",i-o.autoPollLastActivityAt);return}o.watchdogSubmitStartTime=i,o.watchdogLastDataFlowTime=i;return}if(a==="tool_using"){const c=i-(o.watchdogLastDataFlowTime||i);if(c>=Ct){const u=String(o.pendingToolEventData?.rawToolName??"");if((o.pendingToolAuthRequests?.size??0)>0){const m=o.pendingToolAuthRequests?.size??0;console.warn(`[ACode] tool_using elapsed ${Math.round(c/1e3)}s but ${m} tool permission request(s) awaiting user decision (session: ${t}), skipping recovery`),o.watchdogSubmitStartTime=i,o.watchdogLastDataFlowTime=i;return}if(u.endsWith("await_complete")){console.warn(`[ACode] tool_using elapsed ${Math.round(c/1e3)}s but await_complete is running (session: ${t}, tool: ${u}), skipping recovery (sub-agents have their own watchdogs, bg commands have timeout limits)`),o.watchdogSubmitStartTime=i,o.watchdogLastDataFlowTime=i;return}if(console.warn(`[ACode] CRITICAL: tool_using slow timeout triggered after ${Math.round(c/1e3)}s (source: ${s}, session: ${t}). Tool execution likely hung. Forcing recovery via recoverTurnFailure.`),o.runtime.detachCurrentToolExecution?.()){console.warn(`[ACode] tool_using slow (${Math.round(c/1e3)}s): detached tool ${u} to background (session: ${t}); waiting for the real tool_result to continue the turn`),o.watchdogSubmitStartTime=i,o.watchdogLastDataFlowTime=i;return}this.executeWatchdogRecovery(t,o,s,"tool_using_slow",c);return}o.watchdogSubmitStartTime=i;return}if(a!=="thinking")return;const r=i-(o.watchdogSubmitStartTime||i),n=i-(o.watchdogLastDataFlowTime||i);if(K>0&&n>=K){console.warn(`[ACode] CRITICAL: Data flow watchdog triggered after ${Math.round(n/1e3)}s (source: ${s}, session: ${t}, status: ${a}). No stream data received. Forcing recovery via recoverTurnFailure.`),this.executeWatchdogRecovery(t,o,s,"data_flow",n);return}if(j>0&&r>=j){console.warn(`[ACode] CRITICAL: submit timeout detected after ${Math.round(r/1e3)}s (source: ${s}, session: ${t}, status: ${a}). Forcing recovery to prevent permanent state stuck.`),this.executeWatchdogRecovery(t,o,s,"submit_timeout",r);return}},_t)}executeWatchdogRecovery(t,e,s,o,a){l(`[ACode] Watchdog (${o}): calling runtime.abort() after ${Math.round(a/1e3)}s...`);try{e.runtime.abort(),l(`[ACode] Watchdog (${o}): runtime.abort() called`)}catch(i){console.warn(`[ACode] \u26A0\uFE0F Watchdog (${o}): runtime.abort() threw: ${i instanceof Error?i.message:String(i)}`)}this.cancelSubmitTimeoutDetection(e),this.recoverTurnFailure(t,e),console.warn(`[ACode] \u26A0\uFE0F Watchdog (${o}) recovery complete. If abort() could not cancel the underlying operation, submitQueue may still be deadlocked.`)}cancelSubmitTimeoutDetection(t){t.watchdogTimer&&(clearInterval(t.watchdogTimer),t.watchdogTimer=void 0),t.watchdogSubmitStartTime=void 0,t.watchdogLastDataFlowTime=void 0}resetDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now(),e.watchdogSubmitStartTime=Date.now()}startDataFlowWatchdog(t,e){e.watchdogLastDataFlowTime=Date.now()}cancelDataFlowWatchdog(t){t.watchdogLastDataFlowTime=Date.now()}formatAiRequestActionDetail(t){const e=`
2
2
 
3
3
  \u8BF7\u6C42\u5934:
4
4
  `,s=`
5
5
 
6
6
  \u8BF7\u6C42\u4F53:
7
- `,a=typeof t.model=="string"?t.model:"",i=typeof t.endpoint=="string"?t.endpoint:typeof t.requestUrl=="string"?t.requestUrl:"",r=typeof t.requestMethod=="string"?t.requestMethod:"",n=typeof t.stream=="boolean"?t.stream:void 0,d=typeof t.messageCount=="number"?t.messageCount:void 0,p=typeof t.toolCount=="number"?t.toolCount:void 0,m=typeof t.lastUserMessagePreview=="string"?t.lastUserMessagePreview:"",c=[a?`\u6A21\u578B: ${a}`:void 0,i?`\u63A5\u53E3: ${i}`:void 0,r?`\u65B9\u6CD5: ${r}`:void 0,n!==void 0?`\u6D41\u5F0F: ${n?"\u662F":"\u5426"}`:void 0,d!==void 0?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${d}`:void 0,p!==void 0?`\u53EF\u7528\u5DE5\u5177: ${p}`:void 0,m?`\u6700\u540E\u8BF7\u6C42: ${m}`:void 0].filter(S=>!!S),g=/^(authorization|x-api-key|api-key|cookie|set-cookie|x-auth-token|token)$/i,f=t.requestHeaders,y=f?Object.entries(f).filter(([S])=>!g.test(S)).map(([S,R])=>`${S}: ${R}`).filter(S=>S.trim().length>0):[],A=c.join(`
8
- `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",_=y.length>0?`${e}${y.join(`
9
- `)}`:"",b=typeof t.requestBody=="string"?t.requestBody:"",T=b.length>6e4?`${b.slice(0,6e4)}
10
- ...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:b,k=T?`${s}${T}`:"";return`${A}${_}${k}`}}export{ae as AcodeSdkAdapter,Mt as isFailedAcodeTurnComplete,$t as toAcodeEsmImportSpecifier};
7
+ `,a=typeof t.model=="string"?t.model:"",i=typeof t.endpoint=="string"?t.endpoint:typeof t.requestUrl=="string"?t.requestUrl:"",r=typeof t.requestMethod=="string"?t.requestMethod:"",n=typeof t.stream=="boolean"?t.stream:void 0,c=typeof t.messageCount=="number"?t.messageCount:void 0,u=typeof t.toolCount=="number"?t.toolCount:void 0,m=typeof t.lastUserMessagePreview=="string"?t.lastUserMessagePreview:"",p=[a?`\u6A21\u578B: ${a}`:void 0,i?`\u63A5\u53E3: ${i}`:void 0,r?`\u65B9\u6CD5: ${r}`:void 0,n!==void 0?`\u6D41\u5F0F: ${n?"\u662F":"\u5426"}`:void 0,c!==void 0?`\u4E0A\u4E0B\u6587\u6D88\u606F: ${c}`:void 0,u!==void 0?`\u53EF\u7528\u5DE5\u5177: ${u}`:void 0,m?`\u6700\u540E\u8BF7\u6C42: ${m}`:void 0].filter(b=>!!b),g=/^(authorization|x-api-key|api-key|cookie|set-cookie|x-auth-token|token)$/i,f=t.requestHeaders,A=f?Object.entries(f).filter(([b])=>!g.test(b)).map(([b,I])=>`${b}: ${I}`).filter(b=>b.trim().length>0):[],y=p.join(`
8
+ `)||"ACode \u6B63\u5728\u53D1\u9001 AI \u8BF7\u6C42",S=A.length>0?`${e}${A.join(`
9
+ `)}`:"",_=typeof t.requestBody=="string"?t.requestBody:"",T=_.length>6e4?`${_.slice(0,6e4)}
10
+ ...(\u8BF7\u6C42\u4F53\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)`:_,C=T?`${s}${T}`:"";return`${y}${S}${C}`}}export{ne as AcodeSdkAdapter,Rt as isFailedAcodeTurnComplete,Lt as toAcodeEsmImportSpecifier};
11
11
 
@@ -334,6 +334,22 @@ export declare abstract class BaseProviderAdapter extends EventEmitter {
334
334
 
335
335
  abstract applyAgentFeatures?(agentId: string): Promise<void>;
336
336
 
337
+ abstract setBuiltInCapabilityTools?(agentId: string, capability: string, action: "expand" | "collapse"): Promise<{
338
+ sessions: number;
339
+ tools: number;
340
+ manifests?: Array<{
341
+ name: string;
342
+ description?: string;
343
+ inputSchema?: unknown;
344
+ }>;
345
+ }>;
346
+
347
+ abstract callBuiltInCapabilityTool?(agentId: string, capability: string, toolName: string, args: Record<string, unknown>): Promise<{
348
+ ok: boolean;
349
+ result?: unknown;
350
+ error?: string;
351
+ }>;
352
+
337
353
  abstract resetContext?(sessionId: string): Promise<void>;
338
354
 
339
355
  abstract terminateSession(sessionId: string): Promise<void>;
@@ -1,2 +1,2 @@
1
- import{mkdir as S,readdir as _,rm as w,stat as N}from"node:fs/promises";import{dirname as O,join as f}from"node:path";const l=new Set(["desktop_screenshot","desktop_window_screenshot"]),x=" Note: when no `path` is given, the bridge auto-saves the PNG to a local file and returns its path (NOT base64). COORDINATES: the bridge remembers each auto-saved screenshot's screen origin \u2014 running desktop_perceive on that file returns SCREEN coordinates directly, ready for desktop_mouse. Never do coordinate arithmetic yourself. For native windows prefer desktop_uia_tree + desktop_uia_click instead \u2014 precise and vision-free.";function C(e){const{tools:t,forwarder:o}=e,i=e.screenshotDir??f(process.cwd(),".desktop-mcp","screenshots");return t.filter(r=>r.name.startsWith("desktop_")).map(r=>{const s=l.has(r.name),c=r.name==="desktop_perceive",p=s?`${r.description??r.name}${x}`:r.description??r.name;return{kind:"builtin",toolName:r.name,exposedName:r.name,description:p,inputSchema:D(r.inputSchema),category:"desktop",async execute(n){let u=n;s?u=await b(r.name,n,i):c&&(u=E(n));const h=await o(r.name,u);return s&&k(r.name,u,h),h}}})}const a=new Map,g=500;function d(e){return e.trim().replace(/\//g,"\\").toLowerCase()}function E(e){const t=typeof e.path=="string"?e.path.trim():"";if(!t||e.origin_x!=null||e.origin_y!=null)return e;const o=a.get(d(t));return o?{...e,origin_x:o.x,origin_y:o.y}:e}function k(e,t,o){let i=null;try{i=JSON.parse(o)}catch{i=null}const s=(typeof i?.path=="string"?i.path:"")||(typeof t.path=="string"?t.path:"");if(!s.trim())return;let c=null;if(e==="desktop_window_screenshot"){const n=i?.origin;n&&typeof n.x=="number"&&typeof n.y=="number"&&(c={x:n.x,y:n.y,at:Date.now()})}else{const n=t.region;n&&typeof n.x=="number"&&typeof n.y=="number"?c={x:n.x,y:n.y,at:Date.now()}:n||(c={x:0,y:0,at:Date.now()})}if(!c)return;const p=d(s);for(a.delete(p),a.set(p,c);a.size>g;){const n=a.keys().next().value;if(n===void 0)break;a.delete(n)}}function j(){a.clear()}async function b(e,t,o){if(!l.has(e)||typeof t.path=="string"&&t.path.trim())return t;const i=R(o);return await S(O(i),{recursive:!0}).catch(()=>{}),v(o).catch(()=>{}),{...t,path:i}}const m=(()=>{const e=Number.parseInt(process.env.AWS_DESKTOP_MCP_SCREENSHOT_RETENTION_DAYS??"",10);return Number.isFinite(e)&&e>=0?e:7})(),T=2*36e5;let y=0;async function v(e,t){const o=t?.now??Date.now();if(m===0||!t?.force&&o-y<T)return;y=o;const i=o-m*864e5;let r;try{r=await _(e)}catch{return}await Promise.all(r.filter(s=>s.startsWith("shot-")&&s.endsWith(".png")).map(async s=>{const c=f(e,s);try{(await N(c)).mtimeMs<i&&await w(c,{force:!0})}catch{}}))}let P=0;function R(e){const t=(++P).toString(36).padStart(3,"0"),o=new Date().toISOString().replace(/[:.]/g,"-");return f(e,`shot-${o}-${t}.png`)}function D(e){if(!e||typeof e!="object")return{type:"object",properties:{}};try{return JSON.parse(JSON.stringify(e))}catch{return{type:"object",properties:{}}}}export{j as clearScreenshotOrigins,C as createBuiltInDesktopTools,E as injectRememberedOrigin,b as injectScreenshotPath,R as nextScreenshotFilePath,v as pruneOldScreenshots,k as rememberScreenshotOrigin};
1
+ import{mkdir as _,readdir as w,rm as N,stat as O}from"node:fs/promises";import{dirname as x,join as f}from"node:path";const d=new Set(["desktop_screenshot","desktop_window_screenshot"]),g=" Note: when no `path` is given, the bridge auto-saves the PNG to a local file and returns its path (NOT base64). COORDINATES: the bridge remembers each auto-saved screenshot's screen origin \u2014 running desktop_perceive on that file returns SCREEN coordinates directly, ready for desktop_mouse. Never do coordinate arithmetic yourself. For native windows prefer desktop_uia_tree + desktop_uia_click instead \u2014 precise and vision-free.";function j(e){const{tools:t,forwarder:o}=e,i=e.screenshotDir??f(process.cwd(),".desktop-mcp","screenshots");return t.filter(r=>r.name.startsWith("desktop_")).map(r=>{const s=d.has(r.name),c=r.name==="desktop_perceive",p=s?`${r.description??r.name}${g}`:r.description??r.name;return{kind:"builtin",toolName:r.name,exposedName:r.name,description:p,inputSchema:I(r.inputSchema),category:"desktop",async execute(n){let u=n;s?u=await T(r.name,n,i):c&&(u=k(n));const h=await o(r.name,u);return s&&b(r.name,u,h),h}}})}const a=new Map,E=500;function l(e){return e.trim().replace(/\//g,"\\").toLowerCase()}function m(e){return e!=null}function k(e){const t=typeof e.path=="string"?e.path.trim():"";if(!t||m(e.origin_x)||m(e.origin_y))return e;const o=a.get(l(t));return o?{...e,origin_x:o.x,origin_y:o.y}:e}function b(e,t,o){let i=null;try{i=JSON.parse(o)}catch{i=null}const s=(typeof i?.path=="string"?i.path:"")||(typeof t.path=="string"?t.path:"");if(!s.trim())return;let c=null;if(e==="desktop_window_screenshot"){const n=i?.origin;n&&typeof n.x=="number"&&typeof n.y=="number"&&(c={x:n.x,y:n.y,at:Date.now()})}else{const n=t.region;n&&typeof n.x=="number"&&typeof n.y=="number"?c={x:n.x,y:n.y,at:Date.now()}:n||(c={x:0,y:0,at:Date.now()})}if(!c)return;const p=l(s);for(a.delete(p),a.set(p,c);a.size>E;){const n=a.keys().next().value;if(n===void 0)break;a.delete(n)}}function M(){a.clear()}async function T(e,t,o){if(!d.has(e)||typeof t.path=="string"&&t.path.trim())return t;const i=D(o);return await _(x(i),{recursive:!0}).catch(()=>{}),P(o).catch(()=>{}),{...t,path:i}}const y=(()=>{const e=Number.parseInt(process.env.AWS_DESKTOP_MCP_SCREENSHOT_RETENTION_DAYS??"",10);return Number.isFinite(e)&&e>=0?e:7})(),v=2*36e5;let S=0;async function P(e,t){const o=t?.now??Date.now();if(y===0||!t?.force&&o-S<v)return;S=o;const i=o-y*864e5;let r;try{r=await w(e)}catch{return}await Promise.all(r.filter(s=>s.startsWith("shot-")&&s.endsWith(".png")).map(async s=>{const c=f(e,s);try{(await O(c)).mtimeMs<i&&await N(c,{force:!0})}catch{}}))}let R=0;function D(e){const t=(++R).toString(36).padStart(3,"0"),o=new Date().toISOString().replace(/[:.]/g,"-");return f(e,`shot-${o}-${t}.png`)}function I(e){if(!e||typeof e!="object")return{type:"object",properties:{}};try{return JSON.parse(JSON.stringify(e))}catch{return{type:"object",properties:{}}}}export{M as clearScreenshotOrigins,j as createBuiltInDesktopTools,k as injectRememberedOrigin,T as injectScreenshotPath,D as nextScreenshotFilePath,P as pruneOldScreenshots,b as rememberScreenshotOrigin};
2
2
 
@@ -1,2 +1,2 @@
1
- import m from"node:os";import n from"node:path";import{promises as i}from"node:fs";import{randomUUID as p}from"node:crypto";import{Router as l}from"express";import{validateToken as u}from"../middleware/auth.js";import{createLogger as d}from"../utils/logger.js";const s=d("ltr"),w=l(),c=n.join(m.tmpdir(),"aw-temp","LTR"),y=7,f=512*1024;function g(o=new Date){const e=o.getFullYear(),t=String(o.getMonth()+1).padStart(2,"0"),r=String(o.getDate()).padStart(2,"0");return n.join(c,`${e}${t}${r}`)}async function h(){const o=Date.now()-y*24*60*60*1e3;try{const e=await i.readdir(c,{withFileTypes:!0});for(const t of e){if(!t.isDirectory())continue;const r=n.join(c,t.name);try{(await i.stat(r)).mtimeMs<o&&(await i.rm(r,{recursive:!0,force:!0}),s.info(`[ltr] removed expired temp dir: ${r}`))}catch{}}}catch(e){const t=e;t.code!=="ENOENT"&&s.warn("[ltr] cleanup expired dirs failed:",t)}}async function T(o){const e=String(o??"");if(!e.trim())throw new Error("ltr content is empty");const t=Buffer.byteLength(e,"utf8");if(t>f)throw new Error(`ltr content too large: ${t} bytes, max ${f} bytes`);const r=g();await i.mkdir(r,{recursive:!0});const a=n.join(r,`${p()}.txt`);return await i.writeFile(a,e,"utf8"),h(),a}w.post("/upload",u,async(o,e)=>{try{const{content:t}=o.body||{},r=await T(String(t??""));e.json({path:r})}catch(t){const r=t;s.error("[ltr] failed to write temp text file:",r),e.status(400).json({error:r.message})}});export{c as LTR_ROOT,w as ltrRouter};
1
+ import{randomUUID as m}from"node:crypto";import{promises as i}from"node:fs";import p from"node:os";import n from"node:path";import{Router as l}from"express";import{validateToken as u}from"../middleware/auth.js";import{createLogger as d}from"../utils/logger.js";const s=d("ltr"),w=l(),c=n.join(p.tmpdir(),"aw-temp","LTR"),y=7,f=512*1024;function g(o=new Date){const e=o.getFullYear(),t=String(o.getMonth()+1).padStart(2,"0"),r=String(o.getDate()).padStart(2,"0");return n.join(c,`${e}${t}${r}`)}async function h(){const o=Date.now()-y*24*60*60*1e3;try{const e=await i.readdir(c,{withFileTypes:!0});for(const t of e){if(!t.isDirectory())continue;const r=n.join(c,t.name);try{(await i.stat(r)).mtimeMs<o&&(await i.rm(r,{recursive:!0,force:!0}),s.info(`[ltr] removed expired temp dir: ${r}`))}catch{}}}catch(e){const t=e;t.code!=="ENOENT"&&s.warn("[ltr] cleanup expired dirs failed:",t)}}async function T(o){const e=String(o??"");if(!e.trim())throw new Error("ltr content is empty");const t=Buffer.byteLength(e,"utf8");if(t>f)throw new Error(`ltr content too large: ${t} bytes, max ${f} bytes`);const r=g();await i.mkdir(r,{recursive:!0});const a=n.join(r,`${m()}.txt`);return await i.writeFile(a,e,"utf8"),h(),a}w.post("/upload",u,async(o,e)=>{try{const{content:t}=o.body||{},r=await T(String(t??""));e.json({path:r})}catch(t){const r=t;s.error("[ltr] failed to write temp text file:",r),e.status(400).json({error:r.message})}});export{c as LTR_ROOT,w as ltrRouter};
2
2
 
@@ -1,4 +1,91 @@
1
1
 
2
2
  export declare const sessionsRouter: import("express-serve-static-core").Router;
3
3
 
4
+ export declare function handleCapabilityToolsRequest(input: {
5
+ agentId: string;
6
+ capability: string;
7
+ action: unknown;
8
+
9
+ resolveSession?: () => {
10
+ agentId: string;
11
+ providerId: string;
12
+ } | undefined;
13
+ resolveAdapter?: (providerId: string) => {
14
+ setBuiltInCapabilityTools?: (agentId: string, capability: string, action: 'expand' | 'collapse') => Promise<{
15
+ sessions: number;
16
+ tools: number;
17
+ manifests?: Array<{
18
+ name: string;
19
+ description?: string;
20
+ inputSchema?: unknown;
21
+ }>;
22
+ }>;
23
+ };
24
+ }): Promise<{
25
+ status: 400;
26
+ body: {
27
+ ok: false;
28
+ error: string;
29
+ };
30
+ } | {
31
+ status: 200;
32
+ body: {
33
+ ok: true;
34
+ changed: {
35
+ sessions: number;
36
+ tools: number;
37
+ };
38
+ manifests?: Array<{
39
+ name: string;
40
+ description?: string;
41
+ inputSchema?: unknown;
42
+ }>;
43
+ message?: string;
44
+ };
45
+ } | {
46
+ status: 500;
47
+ body: {
48
+ ok: false;
49
+ error: string;
50
+ };
51
+ }>;
52
+
53
+ export declare function handleCapabilityToolCallRequest(input: {
54
+ agentId: string;
55
+ capability: string;
56
+ tool: string;
57
+ args: Record<string, unknown>;
58
+
59
+ resolveSession?: () => {
60
+ agentId: string;
61
+ providerId: string;
62
+ } | undefined;
63
+ resolveAdapter?: (providerId: string) => {
64
+ callBuiltInCapabilityTool?: (agentId: string, capability: string, toolName: string, args: Record<string, unknown>) => Promise<{
65
+ ok: boolean;
66
+ result?: unknown;
67
+ error?: string;
68
+ }>;
69
+ };
70
+ }): Promise<{
71
+ status: 400;
72
+ body: {
73
+ ok: false;
74
+ error: string;
75
+ };
76
+ } | {
77
+ status: 200;
78
+ body: {
79
+ ok: boolean;
80
+ result?: unknown;
81
+ error?: string;
82
+ };
83
+ } | {
84
+ status: 500;
85
+ body: {
86
+ ok: false;
87
+ error: string;
88
+ };
89
+ }>;
90
+
4
91
  export declare function resolveActiveSdkSessionSnapshotStatus(adapterStatus?: string, currentRuntimeStatus?: string, currentRuntimeActionType?: string): string;