@cicctencent/agent-core 1.0.34 → 1.0.37

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 (223) hide show
  1. package/dist/cjs/a2a/rest-runner.d.ts.map +1 -1
  2. package/dist/cjs/a2a/rest-runner.js +24 -5
  3. package/dist/cjs/a2a/rest-runner.js.map +1 -1
  4. package/dist/cjs/a2a/runner.d.ts.map +1 -1
  5. package/dist/cjs/a2a/runner.js +33 -8
  6. package/dist/cjs/a2a/runner.js.map +1 -1
  7. package/dist/cjs/agent/compaction.d.ts.map +1 -1
  8. package/dist/cjs/agent/compaction.js +1 -4
  9. package/dist/cjs/agent/compaction.js.map +1 -1
  10. package/dist/cjs/agent/constants.d.ts +14 -0
  11. package/dist/cjs/agent/constants.d.ts.map +1 -0
  12. package/dist/cjs/agent/constants.js +30 -0
  13. package/dist/cjs/agent/constants.js.map +1 -0
  14. package/dist/cjs/agent/engine.d.ts +57 -2
  15. package/dist/cjs/agent/engine.d.ts.map +1 -1
  16. package/dist/cjs/agent/engine.js +139 -379
  17. package/dist/cjs/agent/engine.js.map +1 -1
  18. package/dist/cjs/agent/guard-controller.d.ts +64 -0
  19. package/dist/cjs/agent/guard-controller.d.ts.map +1 -0
  20. package/dist/cjs/agent/guard-controller.js +265 -0
  21. package/dist/cjs/agent/guard-controller.js.map +1 -0
  22. package/dist/cjs/agent/llm-caller.d.ts +22 -5
  23. package/dist/cjs/agent/llm-caller.d.ts.map +1 -1
  24. package/dist/cjs/agent/llm-caller.js +119 -30
  25. package/dist/cjs/agent/llm-caller.js.map +1 -1
  26. package/dist/cjs/agent/rate-limit-manager.d.ts +8 -0
  27. package/dist/cjs/agent/rate-limit-manager.d.ts.map +1 -1
  28. package/dist/cjs/agent/rate-limit-manager.js +36 -0
  29. package/dist/cjs/agent/rate-limit-manager.js.map +1 -1
  30. package/dist/cjs/agent/runtime-builder.d.ts +44 -0
  31. package/dist/cjs/agent/runtime-builder.d.ts.map +1 -1
  32. package/dist/cjs/agent/runtime-builder.js +78 -20
  33. package/dist/cjs/agent/runtime-builder.js.map +1 -1
  34. package/dist/cjs/agent/session-state-manager.d.ts +47 -0
  35. package/dist/cjs/agent/session-state-manager.d.ts.map +1 -0
  36. package/dist/cjs/agent/session-state-manager.js +85 -0
  37. package/dist/cjs/agent/session-state-manager.js.map +1 -0
  38. package/dist/cjs/agent/tool-executor.d.ts +26 -3
  39. package/dist/cjs/agent/tool-executor.d.ts.map +1 -1
  40. package/dist/cjs/agent/tool-executor.js +101 -20
  41. package/dist/cjs/agent/tool-executor.js.map +1 -1
  42. package/dist/cjs/agent/tool-section-builder.d.ts +55 -0
  43. package/dist/cjs/agent/tool-section-builder.d.ts.map +1 -0
  44. package/dist/cjs/agent/tool-section-builder.js +191 -0
  45. package/dist/cjs/agent/tool-section-builder.js.map +1 -0
  46. package/dist/cjs/agent/types.d.ts +6 -2
  47. package/dist/cjs/agent/types.d.ts.map +1 -1
  48. package/dist/cjs/agent/types.js.map +1 -1
  49. package/dist/cjs/index.d.ts +7 -3
  50. package/dist/cjs/index.d.ts.map +1 -1
  51. package/dist/cjs/index.js +20 -11
  52. package/dist/cjs/index.js.map +1 -1
  53. package/dist/cjs/llm/anthropic-provider.d.ts +5 -0
  54. package/dist/cjs/llm/anthropic-provider.d.ts.map +1 -1
  55. package/dist/cjs/llm/anthropic-provider.js +25 -1
  56. package/dist/cjs/llm/anthropic-provider.js.map +1 -1
  57. package/dist/cjs/llm/ollama-provider.d.ts +8 -1
  58. package/dist/cjs/llm/ollama-provider.d.ts.map +1 -1
  59. package/dist/cjs/llm/ollama-provider.js +19 -0
  60. package/dist/cjs/llm/ollama-provider.js.map +1 -1
  61. package/dist/cjs/llm/openai-provider.d.ts.map +1 -1
  62. package/dist/cjs/llm/openai-provider.js +24 -0
  63. package/dist/cjs/llm/openai-provider.js.map +1 -1
  64. package/dist/cjs/llm/types.d.ts +40 -0
  65. package/dist/cjs/llm/types.d.ts.map +1 -1
  66. package/dist/cjs/llm/types.js +83 -0
  67. package/dist/cjs/llm/types.js.map +1 -1
  68. package/dist/cjs/mcp/base-client.js +2 -2
  69. package/dist/cjs/mcp/base-client.js.map +1 -1
  70. package/dist/cjs/mcp/client.js +4 -4
  71. package/dist/cjs/mcp/client.js.map +1 -1
  72. package/dist/cjs/mcp/factory.d.ts +6 -1
  73. package/dist/cjs/mcp/factory.d.ts.map +1 -1
  74. package/dist/cjs/mcp/factory.js +7 -2
  75. package/dist/cjs/mcp/factory.js.map +1 -1
  76. package/dist/cjs/mcp/http-client.js +5 -5
  77. package/dist/cjs/mcp/http-client.js.map +1 -1
  78. package/dist/cjs/observability/logger.d.ts.map +1 -1
  79. package/dist/cjs/observability/logger.js +56 -2
  80. package/dist/cjs/observability/logger.js.map +1 -1
  81. package/dist/cjs/pool/engine-pool.d.ts +4 -4
  82. package/dist/cjs/pool/engine-pool.d.ts.map +1 -1
  83. package/dist/cjs/pool/engine-pool.js +21 -50
  84. package/dist/cjs/pool/engine-pool.js.map +1 -1
  85. package/dist/cjs/runtime/run-registry-interface.d.ts +6 -0
  86. package/dist/cjs/runtime/run-registry-interface.d.ts.map +1 -1
  87. package/dist/cjs/runtime/run-registry.d.ts +8 -0
  88. package/dist/cjs/runtime/run-registry.d.ts.map +1 -1
  89. package/dist/cjs/runtime/run-registry.js +25 -0
  90. package/dist/cjs/runtime/run-registry.js.map +1 -1
  91. package/dist/cjs/security/guard.d.ts +12 -1
  92. package/dist/cjs/security/guard.d.ts.map +1 -1
  93. package/dist/cjs/security/guard.js +42 -10
  94. package/dist/cjs/security/guard.js.map +1 -1
  95. package/dist/cjs/security/types.d.ts +11 -0
  96. package/dist/cjs/security/types.d.ts.map +1 -1
  97. package/dist/cjs/tool/ask-user.js +3 -3
  98. package/dist/cjs/tool/delegate.d.ts.map +1 -1
  99. package/dist/cjs/tool/delegate.js +4 -2
  100. package/dist/cjs/tool/delegate.js.map +1 -1
  101. package/dist/cjs/types.d.ts +15 -1
  102. package/dist/cjs/types.d.ts.map +1 -1
  103. package/dist/cjs/utils/dsml-parser.d.ts +1 -1
  104. package/dist/cjs/utils/dsml-parser.js +1 -1
  105. package/dist/cjs/utils/event-adapter.d.ts.map +1 -1
  106. package/dist/cjs/utils/event-adapter.js +6 -0
  107. package/dist/cjs/utils/event-adapter.js.map +1 -1
  108. package/dist/cjs/utils/ttl-lru-cache.d.ts +49 -0
  109. package/dist/cjs/utils/ttl-lru-cache.d.ts.map +1 -0
  110. package/dist/cjs/utils/ttl-lru-cache.js +108 -0
  111. package/dist/cjs/utils/ttl-lru-cache.js.map +1 -0
  112. package/dist/esm/a2a/rest-runner.d.ts.map +1 -1
  113. package/dist/esm/a2a/rest-runner.js +24 -5
  114. package/dist/esm/a2a/rest-runner.js.map +1 -1
  115. package/dist/esm/a2a/runner.d.ts.map +1 -1
  116. package/dist/esm/a2a/runner.js +33 -8
  117. package/dist/esm/a2a/runner.js.map +1 -1
  118. package/dist/esm/agent/compaction.d.ts.map +1 -1
  119. package/dist/esm/agent/compaction.js +1 -4
  120. package/dist/esm/agent/compaction.js.map +1 -1
  121. package/dist/esm/agent/constants.d.ts +14 -0
  122. package/dist/esm/agent/constants.d.ts.map +1 -0
  123. package/dist/esm/agent/constants.js +27 -0
  124. package/dist/esm/agent/constants.js.map +1 -0
  125. package/dist/esm/agent/engine.d.ts +57 -2
  126. package/dist/esm/agent/engine.d.ts.map +1 -1
  127. package/dist/esm/agent/engine.js +140 -380
  128. package/dist/esm/agent/engine.js.map +1 -1
  129. package/dist/esm/agent/guard-controller.d.ts +64 -0
  130. package/dist/esm/agent/guard-controller.d.ts.map +1 -0
  131. package/dist/esm/agent/guard-controller.js +256 -0
  132. package/dist/esm/agent/guard-controller.js.map +1 -0
  133. package/dist/esm/agent/llm-caller.d.ts +22 -5
  134. package/dist/esm/agent/llm-caller.d.ts.map +1 -1
  135. package/dist/esm/agent/llm-caller.js +119 -30
  136. package/dist/esm/agent/llm-caller.js.map +1 -1
  137. package/dist/esm/agent/rate-limit-manager.d.ts +8 -0
  138. package/dist/esm/agent/rate-limit-manager.d.ts.map +1 -1
  139. package/dist/esm/agent/rate-limit-manager.js +36 -0
  140. package/dist/esm/agent/rate-limit-manager.js.map +1 -1
  141. package/dist/esm/agent/runtime-builder.d.ts +44 -0
  142. package/dist/esm/agent/runtime-builder.d.ts.map +1 -1
  143. package/dist/esm/agent/runtime-builder.js +75 -20
  144. package/dist/esm/agent/runtime-builder.js.map +1 -1
  145. package/dist/esm/agent/session-state-manager.d.ts +47 -0
  146. package/dist/esm/agent/session-state-manager.d.ts.map +1 -0
  147. package/dist/esm/agent/session-state-manager.js +78 -0
  148. package/dist/esm/agent/session-state-manager.js.map +1 -0
  149. package/dist/esm/agent/tool-executor.d.ts +26 -3
  150. package/dist/esm/agent/tool-executor.d.ts.map +1 -1
  151. package/dist/esm/agent/tool-executor.js +101 -20
  152. package/dist/esm/agent/tool-executor.js.map +1 -1
  153. package/dist/esm/agent/tool-section-builder.d.ts +55 -0
  154. package/dist/esm/agent/tool-section-builder.d.ts.map +1 -0
  155. package/dist/esm/agent/tool-section-builder.js +182 -0
  156. package/dist/esm/agent/tool-section-builder.js.map +1 -0
  157. package/dist/esm/agent/types.d.ts +6 -2
  158. package/dist/esm/agent/types.d.ts.map +1 -1
  159. package/dist/esm/agent/types.js.map +1 -1
  160. package/dist/esm/index.d.ts +7 -3
  161. package/dist/esm/index.d.ts.map +1 -1
  162. package/dist/esm/index.js +4 -1
  163. package/dist/esm/index.js.map +1 -1
  164. package/dist/esm/llm/anthropic-provider.d.ts +5 -0
  165. package/dist/esm/llm/anthropic-provider.d.ts.map +1 -1
  166. package/dist/esm/llm/anthropic-provider.js +25 -1
  167. package/dist/esm/llm/anthropic-provider.js.map +1 -1
  168. package/dist/esm/llm/ollama-provider.d.ts +8 -1
  169. package/dist/esm/llm/ollama-provider.d.ts.map +1 -1
  170. package/dist/esm/llm/ollama-provider.js +19 -0
  171. package/dist/esm/llm/ollama-provider.js.map +1 -1
  172. package/dist/esm/llm/openai-provider.d.ts.map +1 -1
  173. package/dist/esm/llm/openai-provider.js +24 -0
  174. package/dist/esm/llm/openai-provider.js.map +1 -1
  175. package/dist/esm/llm/types.d.ts +40 -0
  176. package/dist/esm/llm/types.d.ts.map +1 -1
  177. package/dist/esm/llm/types.js +80 -0
  178. package/dist/esm/llm/types.js.map +1 -1
  179. package/dist/esm/mcp/base-client.js +2 -2
  180. package/dist/esm/mcp/base-client.js.map +1 -1
  181. package/dist/esm/mcp/client.js +4 -4
  182. package/dist/esm/mcp/client.js.map +1 -1
  183. package/dist/esm/mcp/factory.d.ts +6 -1
  184. package/dist/esm/mcp/factory.d.ts.map +1 -1
  185. package/dist/esm/mcp/factory.js +7 -2
  186. package/dist/esm/mcp/factory.js.map +1 -1
  187. package/dist/esm/mcp/http-client.js +5 -5
  188. package/dist/esm/mcp/http-client.js.map +1 -1
  189. package/dist/esm/observability/logger.d.ts.map +1 -1
  190. package/dist/esm/observability/logger.js +56 -2
  191. package/dist/esm/observability/logger.js.map +1 -1
  192. package/dist/esm/pool/engine-pool.d.ts +4 -4
  193. package/dist/esm/pool/engine-pool.d.ts.map +1 -1
  194. package/dist/esm/pool/engine-pool.js +21 -50
  195. package/dist/esm/pool/engine-pool.js.map +1 -1
  196. package/dist/esm/runtime/run-registry-interface.d.ts +6 -0
  197. package/dist/esm/runtime/run-registry-interface.d.ts.map +1 -1
  198. package/dist/esm/runtime/run-registry.d.ts +8 -0
  199. package/dist/esm/runtime/run-registry.d.ts.map +1 -1
  200. package/dist/esm/runtime/run-registry.js +25 -0
  201. package/dist/esm/runtime/run-registry.js.map +1 -1
  202. package/dist/esm/security/guard.d.ts +12 -1
  203. package/dist/esm/security/guard.d.ts.map +1 -1
  204. package/dist/esm/security/guard.js +42 -10
  205. package/dist/esm/security/guard.js.map +1 -1
  206. package/dist/esm/security/types.d.ts +11 -0
  207. package/dist/esm/security/types.d.ts.map +1 -1
  208. package/dist/esm/tool/ask-user.js +3 -3
  209. package/dist/esm/tool/delegate.d.ts.map +1 -1
  210. package/dist/esm/tool/delegate.js +4 -2
  211. package/dist/esm/tool/delegate.js.map +1 -1
  212. package/dist/esm/types.d.ts +15 -1
  213. package/dist/esm/types.d.ts.map +1 -1
  214. package/dist/esm/utils/dsml-parser.d.ts +1 -1
  215. package/dist/esm/utils/dsml-parser.js +1 -1
  216. package/dist/esm/utils/event-adapter.d.ts.map +1 -1
  217. package/dist/esm/utils/event-adapter.js +6 -0
  218. package/dist/esm/utils/event-adapter.js.map +1 -1
  219. package/dist/esm/utils/ttl-lru-cache.d.ts +49 -0
  220. package/dist/esm/utils/ttl-lru-cache.d.ts.map +1 -0
  221. package/dist/esm/utils/ttl-lru-cache.js +104 -0
  222. package/dist/esm/utils/ttl-lru-cache.js.map +1 -0
  223. package/package.json +1 -1
@@ -13,30 +13,11 @@ const tool_executor_ts_1 = require("./tool-executor.js");
13
13
  const logger_ts_1 = require("../observability/logger.js");
14
14
  const rate_limit_manager_ts_1 = require("./rate-limit-manager.js");
15
15
  const compaction_ts_1 = require("./compaction.js");
16
+ const tool_section_builder_ts_1 = require("./tool-section-builder.js");
17
+ const guard_controller_ts_1 = require("./guard-controller.js");
18
+ const session_state_manager_ts_1 = require("./session-state-manager.js");
16
19
  /** 默认系统提示词 */
17
20
  const DEFAULT_BASE_PROMPT = `You are a helpful AI assistant with access to tools. Use tools when needed to accomplish tasks. Always explain your actions clearly.`;
18
- /**
19
- * 核心工具集(summary-all 模式下保持全量 schema 的工具)。
20
- *
21
- * 这些工具是 Agent 执行绝大多数任务的基础(文件读写、代码搜索、命令执行、
22
- * 工具发现、委托派发),必须让 LLM 看到完整参数 schema 以保证调用可靠性。
23
- * 非核心工具(通讯、日历、自动化、文档生成等)仅以摘要形式呈现,
24
- * LLM 需通过 read_tool_doc 获取完整 schema 后再调用。
25
- */
26
- const CORE_TOOL_NAMES = new Set([
27
- 'read_file',
28
- 'write_file',
29
- 'edit_file',
30
- 'append_file',
31
- 'search_code',
32
- 'execute_command',
33
- 'run_script',
34
- 'read_terminal',
35
- 'read_tool_doc',
36
- 'read_tool_result',
37
- 'read_offload',
38
- 'delegate_task',
39
- ]);
40
21
  /** 进度叙述规则(追加到 system prompt,引导 LLM 在工具调用间输出可见文本)— 可通过 AgentConfig.progressNarrationRules 覆盖 */
41
22
  const DEFAULT_PROGRESS_NARRATION_RULES = `
42
23
 
@@ -102,10 +83,14 @@ class AgentEngine {
102
83
  abortMap = new Map();
103
84
  /** sessionId → steering messages(实时转向队列) */
104
85
  steeringMap = new Map();
86
+ /** sessionId -> pause state (user pause: agent loop suspends at turn boundary until resume) */
87
+ pauseMap = new Map();
105
88
  /** parentSessionId → Set<childSessionId>(父子会话关系跟踪,用于级联 abort) */
106
89
  childSessionMap = new Map();
107
90
  /** childSessionId → parentSessionId(反向索引,用于快速查找父会话) */
108
91
  parentSessionMap = new Map();
92
+ /** 被摘要化的工具名集合(progressive loading:这些工具的 prompt 不注入 system prompt) */
93
+ summarizedToolNames = new Set();
109
94
  /** 子模块:历史管理器 */
110
95
  historyManager;
111
96
  /** 子模块:LLM 调用器 */
@@ -126,6 +111,33 @@ class AgentEngine {
126
111
  guardConfig;
127
112
  /** 错误恢复策略配置 */
128
113
  errorRecovery;
114
+ /** 为 ToolSectionBuilder 提供依赖 */
115
+ get toolSectionDeps() {
116
+ return { config: this.config, summarizedToolNames: this.summarizedToolNames };
117
+ }
118
+ /** 为 GuardController 提供依赖 */
119
+ get guardControllerDeps() {
120
+ return {
121
+ historyManager: this.historyManager,
122
+ dataFetchTools: this.dataFetchTools,
123
+ outputTools: this.outputTools,
124
+ guardConfig: this.guardConfig,
125
+ maxIterations: this.config.maxIterations,
126
+ hasTool: (name) => this.hasTool(name),
127
+ runHooks: (event, ctx) => this.runHooks(event, ctx),
128
+ };
129
+ }
130
+ /** 为 SessionStateManager 提供依赖 */
131
+ get sessionStateDeps() {
132
+ return {
133
+ abortMap: this.abortMap,
134
+ steeringMap: this.steeringMap,
135
+ statusMap: this.statusMap,
136
+ childSessionMap: this.childSessionMap,
137
+ parentSessionMap: this.parentSessionMap,
138
+ historyManager: this.historyManager,
139
+ };
140
+ }
129
141
  constructor(config) {
130
142
  this.config = {
131
143
  ...config,
@@ -163,6 +175,9 @@ class AgentEngine {
163
175
  createEvent: this.createEvent.bind(this),
164
176
  historyManager: this.historyManager,
165
177
  getMiddleware: () => this.config.middleware,
178
+ // 流式工具早分发:存在 before_tool hook / onToolBefore middleware 时禁用(防 block/modify 语义被绕过)
179
+ hasBeforeToolInterceptors: () => (this.config.hooks ?? []).some((h) => h.event === 'before_tool') ||
180
+ (this.config.middleware ?? []).some((m) => m.onToolBefore !== undefined),
166
181
  });
167
182
  // 初始化工具分类集合(可通过 config 覆盖默认值)
168
183
  this.dataFetchTools = new Set(config.dataFetchTools ?? [
@@ -176,8 +191,7 @@ class AgentEngine {
176
191
  // 模型在收尾阶段无法再用它读取 data/ 下的结果文件。
177
192
  // 若某 agent 仍需将其纳入数据获取循环检测,可在 AgentConfig.dataFetchTools 中显式加回。
178
193
  this.outputTools = new Set(config.outputTools ?? [
179
- 'delegate_task', 'create_presentation', 'create_document',
180
- 'create_pdf', 'create_report', 'show_widget', 'save_artifact',
194
+ 'delegate_task', 'create_document', 'show_widget', 'save_artifact',
181
195
  ]);
182
196
  // 外部数据源获取工具(用于数据出处水印判定,仅含真正访问外部/实时数据源的工具,
183
197
  // 不含 read_file 等本地读取——本地读取不构成「实时数据核验」但也不代表数据源失败)
@@ -371,6 +385,8 @@ class AgentEngine {
371
385
  abortSignal.removeEventListener('abort', onExternalAbort);
372
386
  this.abortMap.delete(sessionId);
373
387
  this.steeringMap.delete(sessionId);
388
+ // 清理暂停状态(run 结束后不再保留标志)
389
+ this.pauseMap.delete(sessionId);
374
390
  // 注销主会话,清理限流状态和子会话映射
375
391
  rate_limit_manager_ts_1.rateLimitManager.unregisterMainSession(sessionId);
376
392
  }
@@ -694,67 +710,19 @@ ${textHistory.join('\n')}`;
694
710
  // ---- 工具定义 ----
695
711
  /** 获取工具定义列表(含预过滤 + 渐进式发现) */
696
712
  resolveToolDefs(options) {
697
- const toolNames = [...(this.config.defaultTools || []), ...(options.extraTools || [])];
698
- let defs = toolNames.length > 0
699
- ? this.config.toolRegistry.getDefinitions({ names: toolNames })
700
- : this.config.toolRegistry.getDefinitions();
701
- if (this.config.deniedTools?.length) {
702
- const denied = new Set(this.config.deniedTools);
703
- defs = defs.filter(d => !denied.has(d.function.name));
704
- }
705
- const discovery = this.config.toolDiscovery;
706
- // summary 模式:仅 MCP 工具摘要
707
- if (discovery === 'summary') {
708
- defs = defs.map(d => this.summarizeToolDef(d, 'mcp'));
709
- }
710
- // summary-all 模式:所有非核心工具摘要(MCP + 非核心内置工具)
711
- if (discovery === 'summary-all') {
712
- const coreOverride = this.config.coreToolNames
713
- ? new Set(this.config.coreToolNames)
714
- : CORE_TOOL_NAMES;
715
- defs = defs.map(d => {
716
- const isCore = coreOverride.has(d.function.name);
717
- return this.summarizeToolDef(d, isCore ? null : 'all');
718
- });
719
- }
720
- return defs;
713
+ return (0, tool_section_builder_ts_1.resolveToolDefs)(this.toolSectionDeps, options);
721
714
  }
722
715
  /**
723
716
  * 将工具定义转为摘要形式(截断 description + 清空 parameters)。
724
- * 实现抽离至 ./compaction.ts,保持单一来源。
717
+ * 实现抽离至 ./tool-section-builder.ts -> compaction.ts,保持单一来源。
725
718
  */
726
719
  summarizeToolDef(def, scope) {
727
- return (0, compaction_ts_1.summarizeToolDef)(def, {
728
- scope,
729
- maxDesc: this.config.toolSummaryMaxDesc ?? 100,
730
- getCategory: (name) => this.config.toolRegistry.get(name)?.category,
731
- });
720
+ return (0, tool_section_builder_ts_1.summarizeToolDefImpl)(this.toolSectionDeps, def, scope);
732
721
  }
733
722
  // ---- 准备阶段(续) ----
734
723
  /** 构建 ToolContext */
735
724
  buildToolContext(options, internalAbort) {
736
- const custom = options.context?.custom;
737
- return {
738
- sessionId: options.sessionId,
739
- shell: custom?.shell || this.createNoopShell(),
740
- fs: custom?.fs,
741
- env: options.context?.env,
742
- abortSignal: internalAbort.signal,
743
- custom: {
744
- ...custom,
745
- // Fix A:始终使用引擎授权注册表(已按 selectedTools/disabledTools 过滤),
746
- // 不接受 custom.toolRegistry 覆盖——防止 read_tool_doc/diagnose 泄漏被禁工具 schema。
747
- toolRegistry: this.config.toolRegistry,
748
- skillManager: custom?.skillManager ?? this.config.skillManager,
749
- },
750
- emitSubEvent: custom?.emitSubEvent,
751
- emitWidget: custom?.emitWidget,
752
- emitArtifact: custom?.emitArtifact,
753
- emitToolLog: custom?.emitToolLog,
754
- emitToolHeartbeat: custom?.emitToolHeartbeat,
755
- toolTimeout: this.config.toolTimeout,
756
- maxScriptTimeoutMs: this.config.maxScriptTimeoutMs,
757
- };
725
+ return (0, tool_section_builder_ts_1.buildToolContext)(this.toolSectionDeps, options, internalAbort);
758
726
  }
759
727
  /** 汇总准备阶段,生成 LoopState */
760
728
  async prepareRun(options, internalAbort) {
@@ -788,33 +756,14 @@ ${textHistory.join('\n')}`;
788
756
  hadFatalError: false,
789
757
  fatalErrorMsg: undefined,
790
758
  stableSystemPrompt,
759
+ // 请求级覆盖 Profile 级(AgentConfig.responseFormat)
760
+ responseFormat: options.responseFormat ?? this.config.responseFormat,
791
761
  };
792
762
  }
793
763
  /** 动态构建工具区 prompt(Available Tools + Tool Usage Guidelines)。
794
764
  * 从 state.toolDefs 现场拼装,确保与可执行工具集一致,消除静态穿透。 */
795
765
  buildDynamicToolSection(toolDefs) {
796
- if (this.config.buildToolSection) {
797
- return this.config.buildToolSection(toolDefs, this.config.toolRegistry);
798
- }
799
- if (toolDefs.length === 0)
800
- return '';
801
- // 可用工具名集合:用于占位符 {{TOOL:name}} 渲染时判定引用是否真实可用
802
- const available = new Set(toolDefs.map(d => d.function.name));
803
- const lines = toolDefs.map(d => `- \`${d.function.name}\`: ${this.renderToolRefs(d.function.description || '', available)}`);
804
- let section = `\n\n## Available Tools\n${lines.join('\n')}`;
805
- // 收集工具自带的使用引导(tool.prompt),并对其中对其他工具的引用做可用裁剪。
806
- // tool.relatedTools 是声明式的「本工具引用的其它工具」清单,
807
- // 用于:若某占位符 {{TOOL:x}} 未注册,则整段引用被剔除(见 renderToolRefs)。
808
- const prompts = [];
809
- for (const def of toolDefs) {
810
- const tool = this.config.toolRegistry.get(def.function.name);
811
- if (tool?.prompt)
812
- prompts.push(this.renderToolRefs(tool.prompt, available, tool.relatedTools));
813
- }
814
- if (prompts.length > 0) {
815
- section += `\n\n## Tool Usage Guidelines\n\n${prompts.join('\n\n')}`;
816
- }
817
- return section;
766
+ return (0, tool_section_builder_ts_1.buildDynamicToolSection)(this.toolSectionDeps, toolDefs);
818
767
  }
819
768
  /**
820
769
  * 渲染工具提示中对其它工具的引用,避免「提示穿透」:
@@ -829,51 +778,29 @@ ${textHistory.join('\n')}`;
829
778
  * 显式声明在 relatedTools 中的工具名也可被识别为「已知引用」参与裁剪。
830
779
  */
831
780
  renderToolRefs(text, available, relatedTools) {
832
- // relatedTools 声明本工具引用的「其他工具」。占位符 {{TOOL:name}} 只有在
833
- // - name 确实注册(available)时才渲染为 `name`;
834
- // - 否则用哨兵标记,后续做子句级清除,避免留下 "do NOT call after" 这类残缺。
835
- // 不在 relatedTools 且未注册的占位符视为误写,保留原文。
836
- const knownRefs = relatedTools && relatedTools.length > 0 ? new Set(relatedTools) : null;
837
- const SENTINEL = '\x00'; // 哨兵:标记被剔除的占位符位置
838
- // 1) 替换:可用 -> name;不可用且为已知引用 -> 哨兵;其余保留原文
839
- let out = text.replace(/\{\{TOOL:([a-zA-Z0-9_-]+)\}\}/g, (m, name) => {
840
- if (available.has(name))
841
- return `\`${name}\``;
842
- if (knownRefs && !knownRefs.has(name))
843
- return m;
844
- return SENTINEL;
845
- });
846
- // 2) 子句级清除:以 " - " 或 ", " 分隔的子句中含哨兵,则移除整个子句
847
- out = out
848
- .split(/(?<=\S)\s+-\s+|(?<=\S),\s+/)
849
- .filter(clause => !clause.includes(SENTINEL))
850
- .join(', ');
851
- // 3) 行级清除:多行 prompt 中,整行仅剩哨兵/标点/空白的予以移除
852
- out = out
853
- .split('\n')
854
- .filter(line => {
855
- const trimmed = line.trim();
856
- if (trimmed === '')
857
- return true;
858
- const meaningful = trimmed.replace(/[`.,;:()\-]+/g, '').replace(/\s+/g, '');
859
- return meaningful.length > 0 && !trimmed.includes(SENTINEL);
860
- })
861
- .join('\n');
862
- // 4) 清理残留哨兵 + 收缩多余空格
863
- out = out.replace(/\x00/g, '').replace(/ {2,}/g, ' ').replace(/\s+\n/g, '\n').trim();
864
- return out;
781
+ return (0, tool_section_builder_ts_1.renderToolRefs)(text, available, relatedTools);
865
782
  }
866
783
  /** 刷新 system prompt 中的工具区,确保与 state.toolDefs 一致 */
867
784
  refreshToolSection(state) {
868
- if (state.messages[0] && state.stableSystemPrompt != null) {
869
- state.messages[0].content = state.stableSystemPrompt + this.buildDynamicToolSection(state.toolDefs);
870
- }
785
+ (0, tool_section_builder_ts_1.refreshToolSection)(this.toolSectionDeps, state);
871
786
  }
872
787
  // ---- Agent Loop ----
873
788
  /** 主循环:迭代调用 LLM → 执行工具 → 直到完成或达到上限 */
874
789
  async *agentLoop(state) {
875
790
  while (state.iteration < this.config.maxIterations) {
876
791
  state.iteration++;
792
+ // Pause checkpoint: when user pauses, the current tool/LLM call has finished;
793
+ // the agent loop exits gracefully before the next LLM call (stream ends normally).
794
+ // Resume is implemented by starting a NEW SSE stream that rebuilds context from
795
+ // persisted message history - no in-memory suspension (survives process restart).
796
+ if (this.pauseMap.get(state.sessionId)?.paused === true) {
797
+ // 清理暂停标志(恢复由新建流完成,不再唤醒本循环)
798
+ this.pauseMap.delete(state.sessionId);
799
+ yield this.createEvent(state.sessionId, { type: 'paused' });
800
+ // 正常结束 SSE 流(run 状态 ok,与 abort 的 error 收尾区分)
801
+ yield this.emitDone(state);
802
+ return;
803
+ }
877
804
  // 中断检查
878
805
  if (state.internalAbort.signal.aborted) {
879
806
  // 外部中断(客户端断开 / 用户主动 abort / 看门狗超时):标记致命错误,
@@ -970,8 +897,38 @@ ${textHistory.join('\n')}`;
970
897
  });
971
898
  // 调用 LLM(流式,含重试与降级)
972
899
  this.statusMap.set(state.sessionId, 'thinking');
900
+ // 流式工具早分发:本轮 LLM 调用的预执行缓存(重试/降级时由 onToolCallReset 重置)
901
+ state.earlyToolResults = new Map();
902
+ state.earlyExecutions = [];
973
903
  const llmStart = Date.now();
974
- const { assistant, usage, observability } = yield* this.llmCaller.callWithRetry(state.sessionId, state.messages, state.toolDefs, state.internalAbort.signal);
904
+ // 透传 LLMCaller 事件流,同时捕获 error 事件的原始报文(服务商返回的 429/5xx 等),
905
+ // 用于 llm_exhausted 分支向用户透传服务商原始异常信息。
906
+ // 采用 next() 循环:转发所有 yield 事件,并在 done 时拿到 callWithRetry 的 return 值(assistant/usage/observability)。
907
+ let lastLlmErrorMsg;
908
+ const llmGen = this.llmCaller.callWithRetry(state.sessionId, state.messages, state.toolDefs, state.internalAbort.signal, {
909
+ // 工具调用参数聚合完成即预执行(纯优化:执行结果缓存后由 executeToolCalls 命中复用)
910
+ onToolCallReady: (tc) => this.toolExecutor.startEarlyExecution(state, tc),
911
+ onToolCallReset: () => {
912
+ state.earlyToolResults = new Map();
913
+ state.earlyExecutions = [];
914
+ },
915
+ }, state.responseFormat);
916
+ let llmResult = { assistant: null, usage: undefined, observability: undefined };
917
+ while (true) {
918
+ const { value: ev, done } = await llmGen.next();
919
+ if (done) {
920
+ if (ev)
921
+ llmResult = ev;
922
+ break;
923
+ }
924
+ if (ev && ev.type === 'error' && ev.error) {
925
+ lastLlmErrorMsg = ev.error;
926
+ }
927
+ yield ev;
928
+ }
929
+ const { assistant, usage, observability } = llmResult;
930
+ // 等待流中启动的预执行收尾(abort 场景同样先收尾再继续,保证资源不泄漏)
931
+ await this.toolExecutor.awaitEarlyExecutions(state);
975
932
  const llmDuration = Date.now() - llmStart;
976
933
  // 累加 Token 用量
977
934
  if (usage) {
@@ -981,6 +938,9 @@ ${textHistory.join('\n')}`;
981
938
  state.totalUsage.promptTokens += usage.promptTokens || 0;
982
939
  state.totalUsage.completionTokens += usage.completionTokens || 0;
983
940
  state.totalUsage.totalTokens += usage.totalTokens || 0;
941
+ state.totalUsage.cacheReadTokens = (state.totalUsage.cacheReadTokens || 0) + (usage.cacheReadTokens || 0);
942
+ state.totalUsage.cacheWriteTokens = (state.totalUsage.cacheWriteTokens || 0) + (usage.cacheWriteTokens || 0);
943
+ state.totalUsage.reasoningTokens = (state.totalUsage.reasoningTokens || 0) + (usage.reasoningTokens || 0);
984
944
  }
985
945
  if (!assistant) {
986
946
  // 所有 LLM provider 均已失败(callWithRetry 内部已重试+降级)。
@@ -989,7 +949,9 @@ ${textHistory.join('\n')}`;
989
949
  // 前端 onDone 回调不触发(无法更新 UI 状态)。
990
950
  // error 和 done 是不同的 SSE 事件类型,前端分别用 onError 和 onDone 处理,
991
951
  // done 事件携带 lastContent(之前成功迭代的输出)或兜底总结,不会覆盖 error 消息。
992
- const errorMsg = 'All LLM providers exhausted (all calls failed including retries and fallback)';
952
+ // 优先透传服务商原始异常报文(LLMCaller 经 error 事件发出的 429/5xx 原文,含 code 与重置时间等),
953
+ // 缺失时回退到固定概括文案,向后兼容。
954
+ const errorMsg = lastLlmErrorMsg || 'All LLM providers exhausted (all calls failed including retries and fallback)';
993
955
  (0, logger_ts_1.logEvent)({ event: 'engine.llm_exhausted', sessionId: state.sessionId, level: 'warn', data: { iteration: state.iteration } });
994
956
  this.statusMap.set(state.sessionId, 'idle');
995
957
  // 致命错误 → 自动 abort + 级联清理(级联清理子 Agent 运行中的子任务)
@@ -1187,6 +1149,9 @@ ${textHistory.join('\n')}`;
1187
1149
  state.totalUsage.promptTokens += finalUsage.promptTokens || 0;
1188
1150
  state.totalUsage.completionTokens += finalUsage.completionTokens || 0;
1189
1151
  state.totalUsage.totalTokens += finalUsage.totalTokens || 0;
1152
+ state.totalUsage.cacheReadTokens = (state.totalUsage.cacheReadTokens || 0) + (finalUsage.cacheReadTokens || 0);
1153
+ state.totalUsage.cacheWriteTokens = (state.totalUsage.cacheWriteTokens || 0) + (finalUsage.cacheWriteTokens || 0);
1154
+ state.totalUsage.reasoningTokens = (state.totalUsage.reasoningTokens || 0) + (finalUsage.reasoningTokens || 0);
1190
1155
  }
1191
1156
  if (finalAssistant) {
1192
1157
  state.messages.push(finalAssistant);
@@ -1278,27 +1243,11 @@ ${textHistory.join('\n')}`;
1278
1243
  * 消息将在下次 LLM 调用前注入对话上下文
1279
1244
  */
1280
1245
  steer(sessionId, message) {
1281
- if (!this.abortMap.has(sessionId))
1282
- return false;
1283
- if (!this.steeringMap.has(sessionId)) {
1284
- this.steeringMap.set(sessionId, []);
1285
- }
1286
- this.steeringMap.get(sessionId).push(message);
1287
- return true;
1246
+ return (0, session_state_manager_ts_1.steer)(this.sessionStateDeps, sessionId, message);
1288
1247
  }
1289
1248
  /** 消费当前会话的 steering 消息,注入到 messages 中 */
1290
1249
  drainSteering(state) {
1291
- const msgs = this.steeringMap.get(state.sessionId);
1292
- if (!msgs || msgs.length === 0)
1293
- return null;
1294
- const drained = [...msgs];
1295
- msgs.length = 0;
1296
- for (const msg of drained) {
1297
- const userMsg = { role: 'user', content: msg };
1298
- state.messages.push(userMsg);
1299
- this.historyManager.addHistory(state.sessionId, userMsg);
1300
- }
1301
- return { messages: drained, count: drained.length };
1250
+ return (0, session_state_manager_ts_1.drainSteering)(this.sessionStateDeps, state);
1302
1251
  }
1303
1252
  /**
1304
1253
  * 进度叙述提醒
@@ -1306,23 +1255,7 @@ ${textHistory.join('\n')}`;
1306
1255
  * 确保用户在对话中有可见的文字输出,而不是所有内容都收在执行步骤中。
1307
1256
  */
1308
1257
  injectProgressNudge(state) {
1309
- const msg = {
1310
- role: 'user',
1311
- content: [
1312
- '[SYSTEM: PROGRESS NARRATION]',
1313
- '',
1314
- 'You have been calling tools without providing visible text to the user.',
1315
- 'Please provide a brief progress update in the user\'s language:',
1316
- '- What have you accomplished so far?',
1317
- '- What are you working on next?',
1318
- '- If you found important data, summarize the key findings.',
1319
- '',
1320
- 'Keep it to 1-3 sentences. This text is displayed directly to the user.',
1321
- ].join('\n'),
1322
- };
1323
- state.messages.push(msg);
1324
- this.historyManager.addHistory(state.sessionId, msg);
1325
- (0, logger_ts_1.logEvent)({ event: 'engine.progress_nudge', sessionId: state.sessionId, data: { iteration: state.iteration } });
1258
+ (0, guard_controller_ts_1.injectProgressNudge)(this.guardControllerDeps, state);
1326
1259
  }
1327
1260
  /**
1328
1261
  * 迭代预算提醒
@@ -1330,49 +1263,7 @@ ${textHistory.join('\n')}`;
1330
1263
  * 解决 agent 在数据查询循环中耗尽迭代、永远无法进入文档生成/委托阶段的问题。
1331
1264
  */
1332
1265
  injectIterationGuard(state) {
1333
- if (state.iterationGuardInjected)
1334
- return;
1335
- const max = this.config.maxIterations;
1336
- const cur = state.iteration;
1337
- const remaining = max - cur;
1338
- const ratio = cur / max;
1339
- if (ratio >= this.guardConfig.iterationGuardThreshold && remaining > 0) {
1340
- state.iterationGuardInjected = true;
1341
- const toolCallCount = state.toolCallRecords.length;
1342
- const targets = this.guardConfig.delegateTargets;
1343
- const reportAgent = targets.report ? `"${targets.report}"` : 'the appropriate report agent';
1344
- const docAgent = targets.document ? `"${targets.document}"` : 'the appropriate document agent';
1345
- const pptAgent = targets.presentation ? `"${targets.presentation}"` : docAgent;
1346
- // P1 #6: 使用可配置的提示文本,默认为通用英文提示(不绑定业务 Agent 名称)
1347
- // 仅引用当前 registry 实际注册的工具,避免引导 LLM 调用未绑定工具
1348
- const hasDelegate = this.hasTool('delegate_task');
1349
- const delegateLines = [];
1350
- if (hasDelegate) {
1351
- delegateLines.push(` - For reports/dashboards: call \`delegate_task\` with agent ${reportAgent}.`);
1352
- delegateLines.push(` - For documents: call \`delegate_task\` with agent ${docAgent}.`);
1353
- delegateLines.push(` - For PPT: call \`delegate_task\` with agent ${pptAgent}.`);
1354
- }
1355
- const promptText = this.guardConfig.iterationGuardPrompt || [
1356
- `[SYSTEM ITERATION BUDGET: iteration ${cur}/${max}, ${remaining} remaining]`,
1357
- '',
1358
- `⚠️ You have used ${cur} of ${max} iterations (${toolCallCount} tool calls). Budget is running low.`,
1359
- '',
1360
- '**MANDATORY rules for remaining iterations — violating these will result in task failure:**',
1361
- '1. **STOP all data gathering immediately.** You already have enough data from previous tool calls.',
1362
- '2. **DO NOT call web_fetch, execute_command, write_file, or run_script again.**',
1363
- ...(hasDelegate ? [`3. **NOW delegate remaining work (only if the user explicitly requested file/document generation):**`, ...delegateLines] : []),
1364
- '4. If you cannot delegate, produce the final output NOW with the data you have.',
1365
- '5. **Do NOT proactively generate files (PPT/PDF/HTML/Word) unless the user explicitly asked for them.** If the user only asked for analysis or information, present your findings directly in the conversation as text/markdown.',
1366
- '',
1367
- 'Do NOT write any more scripts or fetch any more data. Your data collection phase is OVER.',
1368
- ].join('\n');
1369
- const msg = { role: 'user', content: promptText };
1370
- state.messages.push(msg);
1371
- this.historyManager.addHistory(state.sessionId, msg);
1372
- (0, logger_ts_1.logEvent)({ event: 'engine.iteration_guard', sessionId: state.sessionId, data: { iteration: cur, max } });
1373
- // 硬性禁用数据获取工具,防止 LLM 无视文字提示继续调用
1374
- this.disableDataFetchTools(state);
1375
- }
1266
+ (0, guard_controller_ts_1.injectIterationGuard)(this.guardControllerDeps, state);
1376
1267
  }
1377
1268
  /**
1378
1269
  * 从可用工具列表中移除数据获取类工具,强制 LLM 转向产出。
@@ -1380,20 +1271,7 @@ ${textHistory.join('\n')}`;
1380
1271
  * 仅移除尚未执行的 toolDefs,不影响正在执行的工具。
1381
1272
  */
1382
1273
  disableDataFetchTools(state) {
1383
- const before = state.toolDefs.length;
1384
- state.toolDefs = state.toolDefs.filter(t => !this.dataFetchTools.has(t.function.name));
1385
- const removed = before - state.toolDefs.length;
1386
- // 同步将禁用的工具名加入 blockedTools 集合,供 tool executor 在执行层拦截
1387
- // LLM 基于对话历史的幻觉调用(toolDefs 仅控制 LLM 可见的工具列表,
1388
- // 但 tool executor 检查的是 toolRegistry,不会拦截已注册但被禁用的工具)
1389
- if (!state.blockedTools)
1390
- state.blockedTools = new Set();
1391
- for (const name of this.dataFetchTools) {
1392
- state.blockedTools.add(name);
1393
- }
1394
- if (removed > 0) {
1395
- (0, logger_ts_1.logEvent)({ event: 'engine.tools_disabled', sessionId: state.sessionId, data: { removed, remaining: state.toolDefs.length, blocked: state.blockedTools.size } });
1396
- }
1274
+ (0, guard_controller_ts_1.disableDataFetchTools)(this.guardControllerDeps, state);
1397
1275
  }
1398
1276
  /**
1399
1277
  * 数据获取循环检测 + 连续失败熔断
@@ -1403,90 +1281,11 @@ ${textHistory.join('\n')}`;
1403
1281
  * 2. 连续失败熔断:最近 5+ 条工具调用中 4+ 条失败,强制停止试错、转向产出
1404
1282
  */
1405
1283
  checkDataFetchLoop(state) {
1406
- if (state.dataFetchGuardInjected)
1407
- return;
1408
- // 数据获取类工具(非产出型)— 使用实例配置
1409
- const DATA_FETCH_TOOLS = this.dataFetchTools;
1410
- // 产出型工具(有这些就不算数据获取循环)— 使用实例配置
1411
- const OUTPUT_TOOLS = this.outputTools;
1412
- const hasOutput = state.toolCallRecords.some(r => OUTPUT_TOOLS.has(r.tool));
1413
- if (hasOutput)
1414
- return; // 已调用过产出型工具,不再干预
1415
- const recent = state.toolCallRecords.slice(-6);
1416
- // --- 条件 1:数据获取循环(最近 N+ 条全是数据获取类) ---
1417
- const loopMin = this.guardConfig.dataFetchLoopMinCount;
1418
- if (recent.length >= loopMin) {
1419
- const lastN = recent.slice(-loopMin);
1420
- const allDataFetch = lastN.every(r => DATA_FETCH_TOOLS.has(r.tool));
1421
- if (allDataFetch) {
1422
- this.injectDataFetchGuard(state, recent, 'loop');
1423
- return;
1424
- }
1425
- }
1426
- // --- 条件 2:连续失败熔断(最近 N+ 条中 M+ 条失败) ---
1427
- const failMin = this.guardConfig.consecutiveFailMinCount;
1428
- if (recent.length >= failMin) {
1429
- const errorCount = recent.filter(r => r.isError).length;
1430
- if (errorCount >= this.guardConfig.consecutiveFailErrorThreshold) {
1431
- this.injectDataFetchGuard(state, recent, 'failures');
1432
- return;
1433
- }
1434
- }
1435
- // --- 条件 3:跨迭代累计失败(总调用 >=8 且失败率 >=70%) ---
1436
- // 解决 LLM 在不同迭代中切换工具类型(web_fetch -> http_request -> browser_navigate)
1437
- // 导致每种工具的连续失败计数都不够触发条件 2 的问题。
1438
- const totalCalls = state.toolCallRecords.length;
1439
- if (totalCalls >= 8) {
1440
- const totalErrors = state.toolCallRecords.filter(r => r.isError).length;
1441
- if (totalErrors >= Math.floor(totalCalls * 0.7)) {
1442
- this.injectDataFetchGuard(state, state.toolCallRecords.slice(-6), 'cumulative_failures');
1443
- return;
1444
- }
1445
- }
1284
+ (0, guard_controller_ts_1.checkDataFetchLoop)(this.guardControllerDeps, state);
1446
1285
  }
1447
1286
  /** 注入数据获取循环/连续失败熔断提示 */
1448
1287
  injectDataFetchGuard(state, recent, reason) {
1449
- state.dataFetchGuardInjected = true;
1450
- // 触发 guardrail 可观测事件(fire-and-forget,不阻塞主流程)
1451
- void this.runHooks('on_data_fetch_loop', {
1452
- sessionId: state.sessionId,
1453
- iteration: state.iteration,
1454
- traceId: state.toolContext?.custom?.traceId,
1455
- });
1456
- const toolSummary = recent.map(r => `${r.tool}(${r.isError ? 'err' : 'ok'})`).join(', ');
1457
- const errorCount = recent.filter(r => r.isError).length;
1458
- const reasonText = reason === 'loop'
1459
- ? `Your last ${recent.length} tool calls are all data-fetching without any output: ${toolSummary}`
1460
- : `${errorCount} of your last ${recent.length} tool calls FAILED: ${toolSummary}`;
1461
- const msg = {
1462
- role: 'user',
1463
- content: [
1464
- `[SYSTEM: ${reason === 'loop' ? 'DATA GATHERING LOOP' : 'CONSECUTIVE FAILURES'} DETECTED]`,
1465
- '',
1466
- reasonText,
1467
- '',
1468
- '⛔ **You MUST stop trying to fetch more data NOW.**',
1469
- '',
1470
- '**Required action — do ONE of the following immediately:**',
1471
- ...(this.hasTool('delegate_task')
1472
- ? ['1. Call `delegate_task` with whatever data/context you have to let a specialist generate the output.']
1473
- : []),
1474
- '2. If delegation is not suitable, produce the final output NOW with available data.',
1475
- '3. At minimum, provide a clear text summary to the user explaining what you found and what failed.',
1476
- '',
1477
- '**Do NOT:**',
1478
- '- Write another script to fetch data',
1479
- '- Try another API, URL, or npm package',
1480
- '- Debug the current failure — accept it and move on',
1481
- '',
1482
- 'The user is waiting for OUTPUT, not more failed attempts.',
1483
- ].join('\n'),
1484
- };
1485
- state.messages.push(msg);
1486
- this.historyManager.addHistory(state.sessionId, msg);
1487
- (0, logger_ts_1.logEvent)({ event: 'engine.data_fetch_guard', sessionId: state.sessionId, data: { reason, iteration: state.iteration, recent: toolSummary } });
1488
- // 硬性禁用数据获取工具,防止 LLM 无视文字提示继续调用
1489
- this.disableDataFetchTools(state);
1288
+ (0, guard_controller_ts_1.injectDataFetchGuard)(this.guardControllerDeps, state, recent, reason);
1490
1289
  }
1491
1290
  /**
1492
1291
  * 任务继续提示
@@ -1494,28 +1293,7 @@ ${textHistory.join('\n')}`;
1494
1293
  * 典型场景:多步委托任务中,第一步数据采集完成后 LLM 未生成后续步骤的 delegate_task。
1495
1294
  */
1496
1295
  injectContinuationNudge(state) {
1497
- const toolCallCount = state.toolCallRecords.length;
1498
- const msg = {
1499
- role: 'user',
1500
- content: [
1501
- '[SYSTEM: TASK CONTINUATION]',
1502
- '',
1503
- `You have completed ${toolCallCount} tool call(s) so far, but the original user request has NOT been fully fulfilled.`,
1504
- '',
1505
- 'Please review the original request and continue with the remaining steps:',
1506
- '- If you planned multi-step tasks (e.g., data gathering → PPT/report generation), **NOW execute the remaining steps**.',
1507
- ...(this.hasTool('delegate_task')
1508
- ? ['- Use `delegate_task` to delegate remaining work to appropriate specialists.']
1509
- : []),
1510
- '- Only if the user **explicitly requested** document/PPT/report generation, call the relevant tools now. Do NOT proactively generate files the user did not ask for.',
1511
- '- Do NOT re-gather data you already have. Use the results from previous tool calls.',
1512
- '',
1513
- 'Continue your work now.',
1514
- ].join('\n'),
1515
- };
1516
- state.messages.push(msg);
1517
- this.historyManager.addHistory(state.sessionId, msg);
1518
- (0, logger_ts_1.logEvent)({ event: 'engine.continuation_nudge_injected', sessionId: state.sessionId, data: { iteration: state.iteration, nudge: state.continuationNudges } });
1296
+ (0, guard_controller_ts_1.injectContinuationNudge)(this.guardControllerDeps, state);
1519
1297
  }
1520
1298
  /**
1521
1299
  * 渐进式结果交付
@@ -1523,28 +1301,7 @@ ${textHistory.join('\n')}`;
1523
1301
  * 而不是等所有结果全部返回后才开始输出。减少用户感知等待时间。
1524
1302
  */
1525
1303
  injectProgressiveNudge(state, toolCalls) {
1526
- const delegateCalls = toolCalls.filter(tc => tc.function.name === 'delegate_task');
1527
- if (delegateCalls.length < 2)
1528
- return;
1529
- const msg = {
1530
- role: 'user',
1531
- content: [
1532
- '[SYSTEM: PROGRESSIVE DELIVERY]',
1533
- '',
1534
- `You dispatched ${delegateCalls.length} sub-tasks in parallel. Some may succeed while others fail or take longer.`,
1535
- '',
1536
- 'When presenting results to the user:',
1537
- '1. **Present each completed result as it becomes available** — do NOT wait for all tasks to finish.',
1538
- '2. If a sub-agent reports network/sandbox restrictions or fails, **acknowledge it briefly and move on** with available data.',
1539
- '3. **Do NOT re-dispatch** a failed task to the same or different agent — use what you already have.',
1540
- '4. Start your final analysis/report with whatever data is available, noting which parts are missing.',
1541
- '',
1542
- 'The user values SPEED over COMPLETENESS. A partial result delivered in 2 minutes is better than a perfect result delivered in 15 minutes.',
1543
- ].join('\n'),
1544
- };
1545
- state.messages.push(msg);
1546
- this.historyManager.addHistory(state.sessionId, msg);
1547
- (0, logger_ts_1.logEvent)({ event: 'engine.progressive_nudge', sessionId: state.sessionId, data: { iteration: state.iteration, delegates: delegateCalls.length } });
1304
+ (0, guard_controller_ts_1.injectProgressiveNudge)(this.guardControllerDeps, state, toolCalls);
1548
1305
  }
1549
1306
  // ---- Hooks ----
1550
1307
  /** 执行指定事件类型的所有 Hook */
@@ -1664,13 +1421,34 @@ ${textHistory.join('\n')}`;
1664
1421
  }
1665
1422
  /** 中断指定会话的 Agent 执行 */
1666
1423
  abort(sessionId) {
1667
- const controller = this.abortMap.get(sessionId);
1668
- if (controller) {
1669
- controller.abort();
1670
- this.statusMap.set(sessionId, 'aborting');
1671
- (0, logger_ts_1.logEvent)({ event: 'engine.abort', sessionId, data: { reason: 'abort() called' } });
1424
+ (0, session_state_manager_ts_1.abortSession)(this.sessionStateDeps, sessionId);
1425
+ }
1426
+ /**
1427
+ * 暂停指定会话的 Agent 执行:当前工具/LLM 调用继续完成,
1428
+ * agent loop 在下一轮 turn 边界优雅退出(发送 paused 事件后正常结束流)。
1429
+ * 恢复由新建 SSE 流重建上下文实现(不唤醒本循环)。
1430
+ * 对不存在的会话调用是幂等 no-op。
1431
+ */
1432
+ pause(sessionId) {
1433
+ const entry = this.pauseMap.get(sessionId);
1434
+ if (entry) {
1435
+ entry.paused = true;
1436
+ }
1437
+ else {
1438
+ this.pauseMap.set(sessionId, { paused: true, waiters: [] });
1672
1439
  }
1673
1440
  }
1441
+ /**
1442
+ * 清理指定会话的暂停标志(恢复由新建 SSE 流完成,不再唤醒挂起循环)。
1443
+ * 对未暂停的会话调用是幂等 no-op。
1444
+ */
1445
+ resume(sessionId) {
1446
+ this.pauseMap.delete(sessionId);
1447
+ }
1448
+ /** 查询指定会话是否处于暂停状态 */
1449
+ isPaused(sessionId) {
1450
+ return this.pauseMap.get(sessionId)?.paused === true;
1451
+ }
1674
1452
  /**
1675
1453
  * 中断指定会话及其所有子会话的 Agent 执行(级联 abort)。
1676
1454
  *
@@ -1678,14 +1456,7 @@ ${textHistory.join('\n')}`;
1678
1456
  * 用于确保父会话异常终止时,所有 delegate_task 派生的子任务也被终止。
1679
1457
  */
1680
1458
  abortCascade(sessionId) {
1681
- this.abort(sessionId);
1682
- // 遍历直接子会话,递归 abort
1683
- const children = this.getChildSessions(sessionId);
1684
- for (const childId of children) {
1685
- this.abortCascade(childId);
1686
- }
1687
- // 清理父子关系
1688
- this.cleanupSessionRelations(sessionId);
1459
+ (0, session_state_manager_ts_1.abortCascade)(this.sessionStateDeps, sessionId);
1689
1460
  }
1690
1461
  /** 查询指定会话的 Agent 状态 */
1691
1462
  getStatus(sessionId) {
@@ -1765,25 +1536,14 @@ ${textHistory.join('\n')}`;
1765
1536
  * - 如果是子会话:从父会话的子集中移除自身
1766
1537
  */
1767
1538
  cleanupSessionRelations(sessionId) {
1768
- // 从父会话的子集中移除自身
1769
- const parentId = this.parentSessionMap.get(sessionId);
1770
- if (parentId) {
1771
- this.childSessionMap.get(parentId)?.delete(sessionId);
1772
- this.parentSessionMap.delete(sessionId);
1773
- }
1774
- // 删除自身作为父会话的所有子关系记录(但保留子会话本身仍在运行)
1775
- this.childSessionMap.delete(sessionId);
1539
+ (0, session_state_manager_ts_1.cleanupSessionRelations)(this.sessionStateDeps, sessionId);
1776
1540
  }
1777
1541
  // ---- 内部辅助 ----
1778
1542
  createEvent(sessionId, event) {
1779
1543
  return { ...event, timestamp: Date.now(), sessionId };
1780
1544
  }
1781
1545
  createNoopShell() {
1782
- return {
1783
- exec: async () => 'Error: Shell executor not configured',
1784
- write: () => { },
1785
- read: () => '',
1786
- };
1546
+ return (0, tool_section_builder_ts_1.createNoopShell)();
1787
1547
  }
1788
1548
  }
1789
1549
  exports.AgentEngine = AgentEngine;