@zhin.js/agent 0.1.30 → 0.1.32

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 (371) hide show
  1. package/README.md +89 -24
  2. package/lib/builtin/memory-search-tool.d.ts +2 -0
  3. package/lib/builtin/memory-search-tool.d.ts.map +1 -0
  4. package/lib/builtin/memory-search-tool.js +61 -0
  5. package/lib/builtin/memory-search-tool.js.map +1 -0
  6. package/lib/builtin/memory-upsert-tool.d.ts +2 -0
  7. package/lib/builtin/memory-upsert-tool.d.ts.map +1 -0
  8. package/lib/builtin/memory-upsert-tool.js +75 -0
  9. package/lib/builtin/memory-upsert-tool.js.map +1 -0
  10. package/lib/builtin/orchestration-tools.d.ts +7 -0
  11. package/lib/builtin/orchestration-tools.d.ts.map +1 -0
  12. package/lib/builtin/orchestration-tools.js +283 -0
  13. package/lib/builtin/orchestration-tools.js.map +1 -0
  14. package/lib/builtin/run-deferred-task-tool.d.ts +1 -1
  15. package/lib/builtin/run-deferred-task-tool.d.ts.map +1 -1
  16. package/lib/builtin/run-deferred-task-tool.js +1 -1
  17. package/lib/builtin/run-deferred-task-tool.js.map +1 -1
  18. package/lib/builtin/run-spec-dry-run-tool.d.ts +6 -0
  19. package/lib/builtin/run-spec-dry-run-tool.d.ts.map +1 -0
  20. package/lib/builtin/run-spec-dry-run-tool.js +51 -0
  21. package/lib/builtin/run-spec-dry-run-tool.js.map +1 -0
  22. package/lib/builtin/run-validation-spec-tool.d.ts +8 -0
  23. package/lib/builtin/run-validation-spec-tool.d.ts.map +1 -0
  24. package/lib/builtin/run-validation-spec-tool.js +44 -0
  25. package/lib/builtin/run-validation-spec-tool.js.map +1 -0
  26. package/lib/builtin/spawn-task-tool.d.ts +1 -1
  27. package/lib/builtin/spawn-task-tool.d.ts.map +1 -1
  28. package/lib/builtin/spawn-task-tool.js +53 -1
  29. package/lib/builtin/spawn-task-tool.js.map +1 -1
  30. package/lib/builtin-tools.d.ts +2 -0
  31. package/lib/builtin-tools.d.ts.map +1 -1
  32. package/lib/builtin-tools.js +6 -0
  33. package/lib/builtin-tools.js.map +1 -1
  34. package/lib/config/normalize-ai-config.d.ts +4 -0
  35. package/lib/config/normalize-ai-config.d.ts.map +1 -1
  36. package/lib/config/normalize-ai-config.js +23 -6
  37. package/lib/config/normalize-ai-config.js.map +1 -1
  38. package/lib/config/provider-instance.d.ts.map +1 -1
  39. package/lib/config/provider-instance.js +26 -7
  40. package/lib/config/provider-instance.js.map +1 -1
  41. package/lib/config/types.d.ts +2 -1
  42. package/lib/config/types.d.ts.map +1 -1
  43. package/lib/config/types.js.map +1 -1
  44. package/lib/config/validate-ai-config.d.ts.map +1 -1
  45. package/lib/config/validate-ai-config.js +5 -0
  46. package/lib/config/validate-ai-config.js.map +1 -1
  47. package/lib/create-agent-session.d.ts +16 -0
  48. package/lib/create-agent-session.d.ts.map +1 -0
  49. package/lib/create-agent-session.js +15 -0
  50. package/lib/create-agent-session.js.map +1 -0
  51. package/lib/deferred-worker-runner.d.ts +2 -0
  52. package/lib/deferred-worker-runner.d.ts.map +1 -1
  53. package/lib/deferred-worker-runner.js +17 -34
  54. package/lib/deferred-worker-runner.js.map +1 -1
  55. package/lib/discovery/agents.d.ts +5 -0
  56. package/lib/discovery/agents.d.ts.map +1 -1
  57. package/lib/discovery/agents.js +7 -0
  58. package/lib/discovery/agents.js.map +1 -1
  59. package/lib/discovery/skills.d.ts +1 -1
  60. package/lib/discovery/skills.d.ts.map +1 -1
  61. package/lib/discovery/skills.js +2 -9
  62. package/lib/discovery/skills.js.map +1 -1
  63. package/lib/discovery/utils.d.ts +7 -1
  64. package/lib/discovery/utils.d.ts.map +1 -1
  65. package/lib/discovery/utils.js +66 -5
  66. package/lib/discovery/utils.js.map +1 -1
  67. package/lib/index.d.ts +19 -2
  68. package/lib/index.d.ts.map +1 -1
  69. package/lib/index.js +12 -2
  70. package/lib/index.js.map +1 -1
  71. package/lib/init/activate-ai-database-storage.d.ts +1 -1
  72. package/lib/init/activate-ai-database-storage.d.ts.map +1 -1
  73. package/lib/init/activate-ai-database-storage.js +38 -13
  74. package/lib/init/activate-ai-database-storage.js.map +1 -1
  75. package/lib/init/create-zhin-agent.d.ts.map +1 -1
  76. package/lib/init/create-zhin-agent.js +86 -9
  77. package/lib/init/create-zhin-agent.js.map +1 -1
  78. package/lib/init/introspection-args.d.ts +34 -0
  79. package/lib/init/introspection-args.d.ts.map +1 -0
  80. package/lib/init/introspection-args.js +71 -0
  81. package/lib/init/introspection-args.js.map +1 -0
  82. package/lib/init/introspection-collectors.d.ts +21 -0
  83. package/lib/init/introspection-collectors.d.ts.map +1 -0
  84. package/lib/init/introspection-collectors.js +74 -0
  85. package/lib/init/introspection-collectors.js.map +1 -0
  86. package/lib/init/introspection-commands-format.d.ts +1 -1
  87. package/lib/init/introspection-commands-format.js +4 -4
  88. package/lib/init/introspection-commands-format.js.map +1 -1
  89. package/lib/init/introspection-output.d.ts +6 -0
  90. package/lib/init/introspection-output.d.ts.map +1 -0
  91. package/lib/init/introspection-output.js +52 -0
  92. package/lib/init/introspection-output.js.map +1 -0
  93. package/lib/init/introspection-pagination.d.ts +14 -0
  94. package/lib/init/introspection-pagination.d.ts.map +1 -0
  95. package/lib/init/introspection-pagination.js +33 -0
  96. package/lib/init/introspection-pagination.js.map +1 -0
  97. package/lib/init/introspection-rest.d.ts +24 -0
  98. package/lib/init/introspection-rest.d.ts.map +1 -0
  99. package/lib/init/introspection-rest.js +65 -0
  100. package/lib/init/introspection-rest.js.map +1 -0
  101. package/lib/init/register-agent-mesh-mcp.d.ts +2 -0
  102. package/lib/init/register-agent-mesh-mcp.d.ts.map +1 -0
  103. package/lib/init/register-agent-mesh-mcp.js +13 -0
  104. package/lib/init/register-agent-mesh-mcp.js.map +1 -0
  105. package/lib/init/register-ai-trigger.d.ts.map +1 -1
  106. package/lib/init/register-ai-trigger.js +29 -4
  107. package/lib/init/register-ai-trigger.js.map +1 -1
  108. package/lib/init/register-builtin-tools.d.ts.map +1 -1
  109. package/lib/init/register-builtin-tools.js +4 -0
  110. package/lib/init/register-builtin-tools.js.map +1 -1
  111. package/lib/init/register-db-models.d.ts.map +1 -1
  112. package/lib/init/register-db-models.js +10 -8
  113. package/lib/init/register-db-models.js.map +1 -1
  114. package/lib/init/register-db-upgrade.d.ts +1 -1
  115. package/lib/init/register-db-upgrade.d.ts.map +1 -1
  116. package/lib/init/register-db-upgrade.js +22 -3
  117. package/lib/init/register-db-upgrade.js.map +1 -1
  118. package/lib/init/register-group-session-passive.d.ts +3 -0
  119. package/lib/init/register-group-session-passive.d.ts.map +1 -0
  120. package/lib/init/register-group-session-passive.js +55 -0
  121. package/lib/init/register-group-session-passive.js.map +1 -0
  122. package/lib/init/register-introspection-commands.d.ts.map +1 -1
  123. package/lib/init/register-introspection-commands.js +5 -6
  124. package/lib/init/register-introspection-commands.js.map +1 -1
  125. package/lib/init/register-management-tools.d.ts +1 -1
  126. package/lib/init/register-management-tools.d.ts.map +1 -1
  127. package/lib/init/register-management-tools.js +57 -36
  128. package/lib/init/register-management-tools.js.map +1 -1
  129. package/lib/init/upgrade-agent-db-schema.d.ts +41 -0
  130. package/lib/init/upgrade-agent-db-schema.d.ts.map +1 -0
  131. package/lib/init/upgrade-agent-db-schema.js +170 -0
  132. package/lib/init/upgrade-agent-db-schema.js.map +1 -0
  133. package/lib/init.d.ts.map +1 -1
  134. package/lib/init.js +4 -0
  135. package/lib/init.js.map +1 -1
  136. package/lib/mcp-server/agent-mesh-tools.d.ts +8 -0
  137. package/lib/mcp-server/agent-mesh-tools.d.ts.map +1 -0
  138. package/lib/mcp-server/agent-mesh-tools.js +138 -0
  139. package/lib/mcp-server/agent-mesh-tools.js.map +1 -0
  140. package/lib/media/deliver-subagent-result.d.ts +7 -0
  141. package/lib/media/deliver-subagent-result.d.ts.map +1 -1
  142. package/lib/media/deliver-subagent-result.js +3 -1
  143. package/lib/media/deliver-subagent-result.js.map +1 -1
  144. package/lib/media/media-normalize.d.ts +2 -0
  145. package/lib/media/media-normalize.d.ts.map +1 -1
  146. package/lib/media/media-normalize.js +89 -0
  147. package/lib/media/media-normalize.js.map +1 -1
  148. package/lib/media/subagent-user-delivery.d.ts +2 -9
  149. package/lib/media/subagent-user-delivery.d.ts.map +1 -1
  150. package/lib/media/subagent-user-delivery.js.map +1 -1
  151. package/lib/memory-entry-registry.d.ts +7 -0
  152. package/lib/memory-entry-registry.d.ts.map +1 -0
  153. package/lib/memory-entry-registry.js +8 -0
  154. package/lib/memory-entry-registry.js.map +1 -0
  155. package/lib/orchestration-memory-hook.d.ts +3 -0
  156. package/lib/orchestration-memory-hook.d.ts.map +1 -0
  157. package/lib/orchestration-memory-hook.js +22 -0
  158. package/lib/orchestration-memory-hook.js.map +1 -0
  159. package/lib/orchestration-runtime-registry.d.ts +14 -0
  160. package/lib/orchestration-runtime-registry.d.ts.map +1 -0
  161. package/lib/orchestration-runtime-registry.js +15 -0
  162. package/lib/orchestration-runtime-registry.js.map +1 -0
  163. package/lib/orchestrator/agent-dispatcher.d.ts +36 -3
  164. package/lib/orchestrator/agent-dispatcher.d.ts.map +1 -1
  165. package/lib/orchestrator/agent-dispatcher.js +203 -13
  166. package/lib/orchestrator/agent-dispatcher.js.map +1 -1
  167. package/lib/orchestrator/delegation-processor.d.ts +33 -0
  168. package/lib/orchestrator/delegation-processor.d.ts.map +1 -0
  169. package/lib/orchestrator/delegation-processor.js +140 -0
  170. package/lib/orchestrator/delegation-processor.js.map +1 -0
  171. package/lib/orchestrator/mission-milestone-notify.d.ts +17 -0
  172. package/lib/orchestrator/mission-milestone-notify.d.ts.map +1 -0
  173. package/lib/orchestrator/mission-milestone-notify.js +49 -0
  174. package/lib/orchestrator/mission-milestone-notify.js.map +1 -0
  175. package/lib/orchestrator/mission-negotiation.d.ts +17 -0
  176. package/lib/orchestrator/mission-negotiation.d.ts.map +1 -0
  177. package/lib/orchestrator/mission-negotiation.js +89 -0
  178. package/lib/orchestrator/mission-negotiation.js.map +1 -0
  179. package/lib/orchestrator/mission-patch-acl.d.ts +9 -0
  180. package/lib/orchestrator/mission-patch-acl.d.ts.map +1 -0
  181. package/lib/orchestrator/mission-patch-acl.js +29 -0
  182. package/lib/orchestrator/mission-patch-acl.js.map +1 -0
  183. package/lib/orchestrator/mission-runner.d.ts +24 -0
  184. package/lib/orchestrator/mission-runner.d.ts.map +1 -0
  185. package/lib/orchestrator/mission-runner.js +179 -0
  186. package/lib/orchestrator/mission-runner.js.map +1 -0
  187. package/lib/orchestrator/mission-spec.d.ts +44 -0
  188. package/lib/orchestrator/mission-spec.d.ts.map +1 -0
  189. package/lib/orchestrator/mission-spec.js +121 -0
  190. package/lib/orchestrator/mission-spec.js.map +1 -0
  191. package/lib/orchestrator/mission-state.d.ts +48 -0
  192. package/lib/orchestrator/mission-state.d.ts.map +1 -0
  193. package/lib/orchestrator/mission-state.js +66 -0
  194. package/lib/orchestrator/mission-state.js.map +1 -0
  195. package/lib/orchestrator/orchestration-repository.d.ts +85 -0
  196. package/lib/orchestrator/orchestration-repository.d.ts.map +1 -0
  197. package/lib/orchestrator/orchestration-repository.js +325 -0
  198. package/lib/orchestrator/orchestration-repository.js.map +1 -0
  199. package/lib/orchestrator/orchestration-service.d.ts +58 -0
  200. package/lib/orchestrator/orchestration-service.d.ts.map +1 -0
  201. package/lib/orchestrator/orchestration-service.js +221 -0
  202. package/lib/orchestrator/orchestration-service.js.map +1 -0
  203. package/lib/orchestrator/remote-agent-registry.d.ts +32 -0
  204. package/lib/orchestrator/remote-agent-registry.d.ts.map +1 -0
  205. package/lib/orchestrator/remote-agent-registry.js +120 -0
  206. package/lib/orchestrator/remote-agent-registry.js.map +1 -0
  207. package/lib/orchestrator/remote-task-executor.d.ts +10 -0
  208. package/lib/orchestrator/remote-task-executor.d.ts.map +1 -0
  209. package/lib/orchestrator/remote-task-executor.js +142 -0
  210. package/lib/orchestrator/remote-task-executor.js.map +1 -0
  211. package/lib/orchestrator/remote-task-poller.d.ts +16 -0
  212. package/lib/orchestrator/remote-task-poller.d.ts.map +1 -0
  213. package/lib/orchestrator/remote-task-poller.js +75 -0
  214. package/lib/orchestrator/remote-task-poller.js.map +1 -0
  215. package/lib/plugin-loop-hooks.d.ts +32 -0
  216. package/lib/plugin-loop-hooks.d.ts.map +1 -0
  217. package/lib/plugin-loop-hooks.js +69 -0
  218. package/lib/plugin-loop-hooks.js.map +1 -0
  219. package/lib/service.d.ts +38 -22
  220. package/lib/service.d.ts.map +1 -1
  221. package/lib/service.js +61 -19
  222. package/lib/service.js.map +1 -1
  223. package/lib/session-tree-runtime-registry.d.ts +20 -0
  224. package/lib/session-tree-runtime-registry.d.ts.map +1 -0
  225. package/lib/session-tree-runtime-registry.js +25 -0
  226. package/lib/session-tree-runtime-registry.js.map +1 -0
  227. package/lib/subagent-ai-events.d.ts +2 -2
  228. package/lib/subagent-ai-events.d.ts.map +1 -1
  229. package/lib/subagent-ai-events.js +17 -21
  230. package/lib/subagent-ai-events.js.map +1 -1
  231. package/lib/subagent-artifact.d.ts +7 -0
  232. package/lib/subagent-artifact.d.ts.map +1 -0
  233. package/lib/subagent-artifact.js +26 -0
  234. package/lib/subagent-artifact.js.map +1 -0
  235. package/lib/subagent-parent-context.d.ts +9 -0
  236. package/lib/subagent-parent-context.d.ts.map +1 -0
  237. package/lib/subagent-parent-context.js +50 -0
  238. package/lib/subagent-parent-context.js.map +1 -0
  239. package/lib/subagent-preset.d.ts +10 -0
  240. package/lib/subagent-preset.d.ts.map +1 -0
  241. package/lib/subagent-preset.js +44 -0
  242. package/lib/subagent-preset.js.map +1 -0
  243. package/lib/subagent-prompt.d.ts +7 -0
  244. package/lib/subagent-prompt.d.ts.map +1 -0
  245. package/lib/subagent-prompt.js +14 -0
  246. package/lib/subagent-prompt.js.map +1 -0
  247. package/lib/subagent.d.ts +19 -0
  248. package/lib/subagent.d.ts.map +1 -1
  249. package/lib/subagent.js +175 -92
  250. package/lib/subagent.js.map +1 -1
  251. package/lib/typing-indicator/adapter-integration.d.ts +7 -3
  252. package/lib/typing-indicator/adapter-integration.d.ts.map +1 -1
  253. package/lib/typing-indicator/adapter-integration.js +30 -6
  254. package/lib/typing-indicator/adapter-integration.js.map +1 -1
  255. package/lib/typing-indicator/index.d.ts +26 -3
  256. package/lib/typing-indicator/index.d.ts.map +1 -1
  257. package/lib/typing-indicator/index.js +94 -6
  258. package/lib/typing-indicator/index.js.map +1 -1
  259. package/lib/typing-indicator/integration.d.ts.map +1 -1
  260. package/lib/typing-indicator/integration.js +7 -2
  261. package/lib/typing-indicator/integration.js.map +1 -1
  262. package/lib/zhin-agent/agent-loop-standalone.d.ts +32 -0
  263. package/lib/zhin-agent/agent-loop-standalone.d.ts.map +1 -0
  264. package/lib/zhin-agent/agent-loop-standalone.js +144 -0
  265. package/lib/zhin-agent/agent-loop-standalone.js.map +1 -0
  266. package/lib/zhin-agent/agent-loop-turn.d.ts +52 -0
  267. package/lib/zhin-agent/agent-loop-turn.d.ts.map +1 -0
  268. package/lib/zhin-agent/agent-loop-turn.js +328 -0
  269. package/lib/zhin-agent/agent-loop-turn.js.map +1 -0
  270. package/lib/zhin-agent/branch-summarization-runtime.d.ts +16 -0
  271. package/lib/zhin-agent/branch-summarization-runtime.d.ts.map +1 -0
  272. package/lib/zhin-agent/branch-summarization-runtime.js +58 -0
  273. package/lib/zhin-agent/branch-summarization-runtime.js.map +1 -0
  274. package/lib/zhin-agent/builtin-tools.d.ts +3 -2
  275. package/lib/zhin-agent/builtin-tools.d.ts.map +1 -1
  276. package/lib/zhin-agent/builtin-tools.js +15 -16
  277. package/lib/zhin-agent/builtin-tools.js.map +1 -1
  278. package/lib/zhin-agent/compaction-runtime.d.ts +25 -0
  279. package/lib/zhin-agent/compaction-runtime.d.ts.map +1 -0
  280. package/lib/zhin-agent/compaction-runtime.js +78 -0
  281. package/lib/zhin-agent/compaction-runtime.js.map +1 -0
  282. package/lib/zhin-agent/config.d.ts +22 -2
  283. package/lib/zhin-agent/config.d.ts.map +1 -1
  284. package/lib/zhin-agent/config.js +25 -2
  285. package/lib/zhin-agent/config.js.map +1 -1
  286. package/lib/zhin-agent/deferred-auto-continue.d.ts +11 -0
  287. package/lib/zhin-agent/deferred-auto-continue.d.ts.map +1 -0
  288. package/lib/zhin-agent/deferred-auto-continue.js +41 -0
  289. package/lib/zhin-agent/deferred-auto-continue.js.map +1 -0
  290. package/lib/zhin-agent/deferred-delivery.d.ts +9 -0
  291. package/lib/zhin-agent/deferred-delivery.d.ts.map +1 -0
  292. package/lib/zhin-agent/deferred-delivery.js +35 -0
  293. package/lib/zhin-agent/deferred-delivery.js.map +1 -0
  294. package/lib/zhin-agent/index.d.ts +60 -11
  295. package/lib/zhin-agent/index.d.ts.map +1 -1
  296. package/lib/zhin-agent/index.js +264 -22
  297. package/lib/zhin-agent/index.js.map +1 -1
  298. package/lib/zhin-agent/model-resolver.d.ts +0 -1
  299. package/lib/zhin-agent/model-resolver.d.ts.map +1 -1
  300. package/lib/zhin-agent/model-resolver.js.map +1 -1
  301. package/lib/zhin-agent/multimodal-message.d.ts +9 -0
  302. package/lib/zhin-agent/multimodal-message.d.ts.map +1 -0
  303. package/lib/zhin-agent/multimodal-message.js +69 -0
  304. package/lib/zhin-agent/multimodal-message.js.map +1 -0
  305. package/lib/zhin-agent/persist-deferred-context.d.ts +5 -0
  306. package/lib/zhin-agent/persist-deferred-context.d.ts.map +1 -0
  307. package/lib/zhin-agent/persist-deferred-context.js +40 -0
  308. package/lib/zhin-agent/persist-deferred-context.js.map +1 -0
  309. package/lib/zhin-agent/prompt-access.d.ts +4 -0
  310. package/lib/zhin-agent/prompt-access.d.ts.map +1 -0
  311. package/lib/zhin-agent/prompt-access.js +7 -0
  312. package/lib/zhin-agent/prompt-access.js.map +1 -0
  313. package/lib/zhin-agent/prompt-builder.d.ts.map +1 -1
  314. package/lib/zhin-agent/prompt-builder.js +5 -0
  315. package/lib/zhin-agent/prompt-builder.js.map +1 -1
  316. package/lib/zhin-agent/prompt-controller.d.ts +53 -0
  317. package/lib/zhin-agent/prompt-controller.d.ts.map +1 -0
  318. package/lib/zhin-agent/prompt-controller.js +165 -0
  319. package/lib/zhin-agent/prompt-controller.js.map +1 -0
  320. package/lib/zhin-agent/prompt-input.d.ts +3 -0
  321. package/lib/zhin-agent/prompt-input.d.ts.map +1 -0
  322. package/lib/zhin-agent/prompt-input.js +8 -0
  323. package/lib/zhin-agent/prompt-input.js.map +1 -0
  324. package/lib/zhin-agent/prompt.d.ts.map +1 -1
  325. package/lib/zhin-agent/prompt.js +4 -0
  326. package/lib/zhin-agent/prompt.js.map +1 -1
  327. package/lib/zhin-agent/session-io.d.ts +28 -11
  328. package/lib/zhin-agent/session-io.d.ts.map +1 -1
  329. package/lib/zhin-agent/session-io.js +64 -28
  330. package/lib/zhin-agent/session-io.js.map +1 -1
  331. package/lib/zhin-agent/session-message-queue.d.ts +20 -0
  332. package/lib/zhin-agent/session-message-queue.d.ts.map +1 -0
  333. package/lib/zhin-agent/session-message-queue.js +52 -0
  334. package/lib/zhin-agent/session-message-queue.js.map +1 -0
  335. package/lib/zhin-agent/session-tree-commands.d.ts +5 -0
  336. package/lib/zhin-agent/session-tree-commands.d.ts.map +1 -0
  337. package/lib/zhin-agent/session-tree-commands.js +44 -0
  338. package/lib/zhin-agent/session-tree-commands.js.map +1 -0
  339. package/lib/zhin-agent/tool-calls-user-format.d.ts.map +1 -1
  340. package/lib/zhin-agent/tool-calls-user-format.js +3 -0
  341. package/lib/zhin-agent/tool-calls-user-format.js.map +1 -1
  342. package/lib/zhin-agent/tool-orchestration.d.ts.map +1 -1
  343. package/lib/zhin-agent/tool-orchestration.js +25 -6
  344. package/lib/zhin-agent/tool-orchestration.js.map +1 -1
  345. package/lib/zhin-agent/tool-runtime.d.ts +2 -2
  346. package/lib/zhin-agent/tool-runtime.d.ts.map +1 -1
  347. package/lib/zhin-agent/tool-runtime.js +4 -4
  348. package/lib/zhin-agent/tool-runtime.js.map +1 -1
  349. package/lib/zhin-agent/tool-search-orchestrator.d.ts.map +1 -1
  350. package/lib/zhin-agent/tool-search-orchestrator.js +13 -0
  351. package/lib/zhin-agent/tool-search-orchestrator.js.map +1 -1
  352. package/lib/zhin-agent/turn-context.d.ts +9 -0
  353. package/lib/zhin-agent/turn-context.d.ts.map +1 -0
  354. package/lib/zhin-agent/turn-context.js +12 -0
  355. package/lib/zhin-agent/turn-context.js.map +1 -0
  356. package/lib/zhin-agent/turn-pipeline.d.ts +7 -1
  357. package/lib/zhin-agent/turn-pipeline.d.ts.map +1 -1
  358. package/lib/zhin-agent/turn-pipeline.js +136 -450
  359. package/lib/zhin-agent/turn-pipeline.js.map +1 -1
  360. package/lib/zhin-agent/turn-user-message.d.ts +8 -0
  361. package/lib/zhin-agent/turn-user-message.d.ts.map +1 -0
  362. package/lib/zhin-agent/turn-user-message.js +10 -0
  363. package/lib/zhin-agent/turn-user-message.js.map +1 -0
  364. package/lib/zhin-agent/zhin-agent-private.d.ts +17 -4
  365. package/lib/zhin-agent/zhin-agent-private.d.ts.map +1 -1
  366. package/lib/zhin-agent/zhin-agent-private.js.map +1 -1
  367. package/package.json +4 -3
  368. package/lib/zhin-agent/llm-runner.d.ts +0 -18
  369. package/lib/zhin-agent/llm-runner.d.ts.map +0 -1
  370. package/lib/zhin-agent/llm-runner.js +0 -163
  371. package/lib/zhin-agent/llm-runner.js.map +0 -1
@@ -1,37 +1,33 @@
1
- import { getPlugin } from '@zhin.js/core';
2
- import { formatCompact, truncatePreview, Logger } from '@zhin.js/logger';
3
- import { createAgent } from '@zhin.js/ai';
1
+ import { formatCompact, Logger } from '@zhin.js/logger';
2
+ import { userMessagePlainText } from '@zhin.js/ai';
4
3
  import { resolveIMSessionIdFromToolContext } from '@zhin.js/ai';
5
4
  import { parseOutput } from '@zhin.js/ai';
6
5
  import { detectTone } from '@zhin.js/ai';
7
6
  import { ensureMcpConnectionsForBinding, getMcpToolsForBinding, } from '../orchestrator/mcp-lifecycle.js';
8
- import { applyExecPolicyToTools } from '../security/exec-policy.js';
9
- import { runWithBashToolContext } from '../security/bash-tool-context.js';
10
7
  import { triggerAIHook, createAIHookEvent } from '../hooks.js';
11
8
  import { resolveModelCandidates } from './model-resolver.js';
12
- import { streamChatWithHistory, streamChatWithVisionMedia } from './llm-runner.js';
13
- import { INBOUND_MEDIA_PARTS_EXTRA_KEY } from '../media/constants.js';
14
9
  import { mergeToolOutboundElements } from '../media/media-tool-bridge.js';
15
10
  import { providerSupportsVision } from '../media/vision-capability.js';
16
- import { buildSessionCreateInput, touchSession, buildHistoryMessages, formatUserContentForSession, resolveSessionIsNewBeforeCreate, } from './session-io.js';
11
+ import { touchSession, resolveSessionIsNewBeforeCreate, beginTurnSession as beginTurnSessionIO, } from './session-io.js';
12
+ import { buildTurnUserMessages } from './turn-user-message.js';
13
+ import { runAgentLoopTextTurn, runAgentLoopVisionTurn } from './agent-loop-turn.js';
17
14
  import { buildEnhancedPersona } from './prompt.js';
18
- import { collectRuntimeTools, planToolRun } from './tool-runtime.js';
19
- import { sanitizeAssistantReply, stripThinkBlocks } from './text-sanitize.js';
20
- import { pruneHistoryWithBudget } from './context-budget.js';
15
+ import { collectRuntimeTools } from './tool-runtime.js';
21
16
  import { buildMultimodalVisionSystemPrompt } from './prompt-assembly.js';
22
- import { formatToolCallsForUser } from './tool-calls-user-format.js';
23
- import { resolveModelHarness } from './model-harness.js';
24
- import { RESERVED_TOOL_NAMES, RESERVED_TOOL_NAME_PREFIXES } from '../reserved-tools.js';
25
- import { createOwnerOrchestratedToolResultTransform } from '../orchestrator/owner-confirm-orchestration.js';
26
- import { logPhase, usageLogFields } from './phase-trace.js';
27
17
  import { attachWebSearchLocale } from './web-search-locale-attach.js';
28
18
  import { EMPTY_USAGE } from './turn-metrics.js';
29
19
  import { resolveAgentToolsForTurn } from './tool-orchestration.js';
30
- import { buildAgentPathSystemPrompt, buildChatPathSystemPrompt, buildFastPathSystemPrompt, buildAgentUserMessage, } from './prompt-assembly.js';
20
+ import { logPhase } from './phase-trace.js';
21
+ import { buildVisionUserMessage, summarizeMultimodalParts } from './multimodal-message.js';
22
+ import { DEFAULT_MULTIMODAL_CONFIG } from '../media/media-types.js';
31
23
  const logger = new Logger(null, 'ZhinAgent');
32
24
  const now = () => performance.now();
33
25
  function sessionDeps(host) {
34
- return { chatHistory: host.chatHistory, imSessionStore: host.imSessionStore };
26
+ return {
27
+ imSessionStore: host.imSessionStore,
28
+ agentSessionStore: host.agentSessionStore,
29
+ contextRepository: host.contextRepository,
30
+ };
35
31
  }
36
32
  async function beginTurnSession(host, context) {
37
33
  const sessionKey = resolveIMSessionIdFromToolContext({
@@ -41,22 +37,27 @@ async function beginTurnSession(host, context) {
41
37
  sceneId: context.sceneId,
42
38
  senderId: context.senderId,
43
39
  });
44
- const imSession = await host.imSessionStore.getOrCreateActive(buildSessionCreateInput(sessionKey, context));
45
- return { sessionKey, sessionId: imSession.session_id };
40
+ return beginTurnSessionIO(sessionDeps(host), sessionKey, context);
46
41
  }
47
- export async function processTextTurn(host, content, context, externalTools = [], onChunk) {
42
+ export async function processTextTurn(host, content, context, externalTools = [], onChunk, extras) {
48
43
  const t0 = now();
49
- const { senderId, sceneId, platform, botId, messageId } = context;
50
- const sessionUserContent = formatUserContentForSession(context, content);
44
+ const { senderId, platform, botId } = context;
45
+ const turnUser = buildTurnUserMessages(context, content);
51
46
  const userId = senderId || 'unknown';
52
47
  const sessionKey = resolveIMSessionIdFromToolContext({
53
48
  platform,
54
49
  botId,
55
50
  scope: context.scope,
56
- sceneId,
51
+ sceneId: context.sceneId,
57
52
  senderId,
58
53
  });
59
- const isNewSession = await resolveSessionIsNewBeforeCreate(sessionDeps(host), sessionKey, context);
54
+ const isNewSession = await resolveSessionIsNewBeforeCreate(sessionDeps(host), sessionKey);
55
+ if (extras?.deferredAutoContinue) {
56
+ logPhase(host.phaseConfig, 'turn.deferred_auto_continue', sessionKey, {});
57
+ }
58
+ else {
59
+ host.resetDeferredAutoContinueDepth(sessionKey);
60
+ }
60
61
  await host.waitForMemoryPersistence();
61
62
  const { sessionId } = await beginTurnSession(host, context);
62
63
  await host.emitter.dispatch('ai.processing.start', host.emitter.createPayload(sessionId, context, 'text', {
@@ -66,25 +67,24 @@ export async function processTextTurn(host, content, context, externalTools = []
66
67
  mode: 'text',
67
68
  provider: host.getTurnProvider().name,
68
69
  });
69
- // 0. Rate limit
70
- const rateCheck = host.rateLimiter.check(userId);
71
- if (!rateCheck.allowed) {
72
- logPhase(host.phaseConfig, 'turn.rate_limited', sessionId, { userId });
73
- logger.debug(`[速率限制] 用户 ${userId} 被限制: ${rateCheck.message}`);
74
- await host.emitter.dispatch('ai.processing.finish', host.emitter.createPayload(sessionId, context, 'text', {
75
- path: 'rate_limited',
76
- reply: rateCheck.message || '请稍后再试',
77
- reason: 'rate_limited',
78
- }));
79
- await host.finalizeActiveTurn({ usage: EMPTY_USAGE, path: 'rate_limited' });
80
- return parseOutput(rateCheck.message || '请稍后再试');
70
+ if (!extras?.deferredAutoContinue) {
71
+ const rateCheck = host.rateLimiter.check(userId);
72
+ if (!rateCheck.allowed) {
73
+ logPhase(host.phaseConfig, 'turn.rate_limited', sessionId, { userId });
74
+ logger.debug(`[速率限制] 用户 ${userId} 被限制: ${rateCheck.message}`);
75
+ await host.emitter.dispatch('ai.processing.finish', host.emitter.createPayload(sessionId, context, 'text', {
76
+ path: 'rate_limited',
77
+ reply: rateCheck.message || '请稍后再试',
78
+ reason: 'rate_limited',
79
+ }));
80
+ await host.finalizeActiveTurn({ usage: EMPTY_USAGE, path: 'rate_limited' });
81
+ return parseOutput(rateCheck.message || '请稍后再试');
82
+ }
81
83
  }
82
- // 0.1 发射 typing 事件,由适配器插件自行决定如何响应
83
84
  host.emitter.emit('ai.typing.start', host.emitter.createPayload(sessionId, context, 'text', {
84
85
  reason: 'processing',
85
86
  }));
86
87
  host.beginActiveTurn();
87
- // 0.5 工具上下文:web_search 语言(档案 preferred_language / language,否则默认中文)
88
88
  const contextForTools = await attachWebSearchLocale(context, userId, host.userProfiles);
89
89
  triggerAIHook(createAIHookEvent('message', 'received', sessionId, {
90
90
  userId,
@@ -93,7 +93,6 @@ export async function processTextTurn(host, content, context, externalTools = []
93
93
  })).catch(() => { });
94
94
  const turnBinding = host.activeBinding;
95
95
  const mcpServerNames = turnBinding?.mcpServers ?? [];
96
- // 0.9 Lazy-connect MCP servers listed on active agent binding
97
96
  if (host.orchestrator && mcpServerNames.length > 0) {
98
97
  await ensureMcpConnectionsForBinding(host.orchestrator.mcps, mcpServerNames, (event) => {
99
98
  const payload = host.emitter.createPayload(sessionId, contextForTools, 'text', {
@@ -114,12 +113,11 @@ export async function processTextTurn(host, content, context, externalTools = []
114
113
  }
115
114
  });
116
115
  }
117
- // 1. Collect tools
118
116
  const tFilter = now();
119
117
  const mcpTools = host.orchestrator && mcpServerNames.length > 0
120
118
  ? getMcpToolsForBinding(host.orchestrator.mcps, mcpServerNames)
121
119
  : [];
122
- let allTools = collectRuntimeTools({
120
+ const allTools = collectRuntimeTools({
123
121
  content,
124
122
  context: contextForTools,
125
123
  externalTools,
@@ -128,7 +126,7 @@ export async function processTextTurn(host, content, context, externalTools = []
128
126
  externalRegistered: host.externalTools,
129
127
  sessionId,
130
128
  userId,
131
- chatHistory: host.chatHistory,
129
+ imTranscriptStore: host.imTranscriptStore,
132
130
  userProfiles: host.userProfiles,
133
131
  mcpTools,
134
132
  });
@@ -141,323 +139,91 @@ export async function processTextTurn(host, content, context, externalTools = []
141
139
  tool_search: true,
142
140
  names: resolvedTools.map(t => t.name).join(',') || '(none)',
143
141
  }));
144
- // 2. History + profile (parallel)
145
- const tMem = now();
146
- const [rawHistoryMessages, profileSummary] = await Promise.all([
147
- buildHistoryMessages(sessionDeps(host), sessionId, context, sessionUserContent),
148
- host.userProfiles.buildProfileSummary(userId),
149
- ]);
150
- const chatCandidates = resolveModelCandidates(host.getTurnProvider().models, host.modelRegistry, host.getTurnProvider().name, host.config, 'chat');
151
- const { messages: historyMessages, result: pruneResult, budget: contextBudget, } = pruneHistoryWithBudget({
152
- messages: rawHistoryMessages,
153
- config: host.config,
154
- provider: host.getTurnProvider(),
155
- modelRegistry: host.modelRegistry,
156
- model: chatCandidates[0],
157
- });
158
- if (pruneResult.droppedCount > 0) {
159
- logger.debug(`[上下文窗口] 丢弃 ${pruneResult.droppedCount} 条历史消息 (${pruneResult.droppedTokens} tokens)`);
160
- }
161
- const memMs = (now() - tMem).toFixed(0);
162
- logPhase(host.phaseConfig, 'context.ready', sessionId, { historyCount: historyMessages.length });
163
- // 2.5 Tone + persona
142
+ const profileSummary = await host.userProfiles.buildProfileSummary(userId);
164
143
  const toneHint = host.config.toneAwareness ? detectTone(content).hint : '';
165
144
  const personaEnhanced = buildEnhancedPersona(host.config, profileSummary, toneHint);
166
- // 3. No tools chat path (prefer per-session model, then lightweight model)
167
- if (allTools.length === 0) {
168
- logPhase(host.phaseConfig, 'path.chat', sessionId, { toolCount: 0 });
169
- const liteModel = host.config.chatLiteModel || undefined;
170
- const chatSystemPrompt = buildChatPathSystemPrompt(host, personaEnhanced, contextForTools);
171
- logger.debug(formatCompact({
172
- mode: 'chat',
173
- prompt_chars: chatSystemPrompt.length,
174
- model: liteModel || chatCandidates[0] || undefined,
175
- }));
176
- const tLLM = now();
177
- logPhase(host.phaseConfig, 'chat.llm.start', sessionId, { model: liteModel || chatCandidates[0] || '' });
178
- const inboundVision = contextForTools.extra?.[INBOUND_MEDIA_PARTS_EXTRA_KEY];
179
- const chatResult = inboundVision?.length
180
- ? await streamChatWithVisionMedia({ provider: host.getTurnProvider(), modelRegistry: host.modelRegistry, config: host.config }, sessionUserContent, inboundVision, chatSystemPrompt, historyMessages, onChunk, liteModel || host.config.visionModel)
181
- : await streamChatWithHistory({ provider: host.getTurnProvider(), modelRegistry: host.modelRegistry, config: host.config }, sessionUserContent, chatSystemPrompt, historyMessages, onChunk, liteModel);
182
- let reply = sanitizeAssistantReply(chatResult.content);
183
- await host.emitter.dispatch('ai.response', host.emitter.createPayload(sessionId, context, 'text', {
184
- path: 'chat',
185
- model: chatResult.model,
186
- reply,
187
- }));
188
- const llmMs = (now() - tLLM).toFixed(0);
189
- logPhase(host.phaseConfig, 'chat.llm.end', sessionId, {
190
- durationMs: Number(llmMs),
191
- ...usageLogFields(chatResult.usage ?? undefined),
192
- });
193
- logger.debug(formatCompact({
194
- mode: 'chat',
195
- filter_ms: filterMs,
196
- mem_ms: memMs,
197
- llm_ms: llmMs,
198
- total_ms: Math.round(now() - t0),
199
- }));
200
- await touchSession(sessionDeps(host), sessionId);
201
- if (isNewSession) {
202
- host.emitSessionNewEvent(sessionId, context, 'text', sessionUserContent, reply);
203
- }
204
- await host.finalizeActiveTurn({
205
- usage: chatResult.usage ?? EMPTY_USAGE,
206
- path: 'chat',
207
- model: chatResult.model,
208
- });
209
- await host.emitter.dispatch('ai.processing.finish', host.emitter.createPayload(sessionId, context, 'text', {
210
- path: 'chat',
211
- model: chatResult.model,
212
- reply,
213
- }));
214
- host.emitter.emit('ai.typing.stop', host.emitter.createPayload(sessionId, context, 'text', {
215
- reason: 'processing_complete',
216
- }));
217
- logPhase(host.phaseConfig, 'turn.end', sessionId, { path: 'chat' });
218
- return parseOutput(reply);
219
- }
220
- logger.debug(`[工具路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, ${allTools.length} 工具 (${allTools.map(t => t.name).join(', ')})`);
221
- // 4. Pre-executable tools
222
- const preExecCandidates = allTools.filter(tool => tool.preExecutable);
223
- const tPre = preExecCandidates.length > 0 ? now() : 0;
224
- if (preExecCandidates.length > 0) {
225
- logger.debug(`预执行: ${preExecCandidates.map(t => t.name).join(', ')}`);
226
- }
227
- const toolRun = await planToolRun(resolvedTools, host.config.preExecTimeout);
228
- logPhase(host.phaseConfig, 'preexec.done', sessionId, {
229
- mode: toolRun.mode,
230
- preExecutedTools: toolRun.preExecution.tools.length,
231
- });
232
- const preData = toolRun.preExecution.data;
233
- if (tPre > 0) {
234
- logger.debug(`预执行耗时: ${(now() - tPre).toFixed(0)}ms`);
235
- }
236
- // 6. Path selection
237
- let reply;
238
- let agentToolCalls = [];
239
- if (toolRun.mode === 'pre-exec-fast-path') {
240
- logPhase(host.phaseConfig, 'path.pre_exec_fast', sessionId, { toolCount: allTools.length });
241
- // Fast path
242
- const tLLM = now();
243
- const prompt = buildFastPathSystemPrompt(host, personaEnhanced, preData, contextForTools);
244
- logger.debug(formatCompact({ mode: 'fast', prompt_chars: prompt.length }));
245
- logPhase(host.phaseConfig, 'fast.llm.start', sessionId, { model: chatCandidates[0] || '' });
246
- const fastResult = await streamChatWithHistory({ provider: host.getTurnProvider(), modelRegistry: host.modelRegistry, config: host.config }, sessionUserContent, prompt, historyMessages, onChunk);
247
- reply = sanitizeAssistantReply(fastResult.content);
248
- logPhase(host.phaseConfig, 'fast.llm.end', sessionId, {
249
- durationMs: Math.round(now() - tLLM),
250
- ...usageLogFields(fastResult.usage ?? undefined),
251
- });
252
- logger.debug(`[快速路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, LLM=${(now() - tLLM).toFixed(0)}ms, 总=${(now() - t0).toFixed(0)}ms`);
253
- await host.finalizeActiveTurn({
254
- usage: fastResult.usage ?? EMPTY_USAGE,
255
- path: 'fast',
256
- model: fastResult.model,
257
- });
258
- }
259
- else {
260
- logPhase(host.phaseConfig, 'path.agent', sessionId, { toolCount: allTools.length });
261
- const tAgent = now();
262
- logger.debug(`Agent 路径: ${allTools.length} 个工具`);
263
- const systemPrompt = await buildAgentPathSystemPrompt(host, {
264
- content,
265
- context: contextForTools,
145
+ const chatCandidates = resolveModelCandidates(host.getTurnProvider().models, host.modelRegistry, host.getTurnProvider().name, host.config, 'chat');
146
+ logPhase(host.phaseConfig, 'path.agent_loop', sessionId, { toolCount: allTools.length });
147
+ const userMessages = extras?.prebuiltMessages?.length
148
+ ? extras.prebuiltMessages
149
+ : turnUser.promptMessages;
150
+ const loopResult = await host.promptController.schedule({
151
+ sessionKey,
152
+ sessionId,
153
+ userMessages,
154
+ context,
155
+ onChunk,
156
+ execute: (initialMessages, hooks, signal, _turnId) => runAgentLoopTextTurn({
157
+ host,
266
158
  sessionId,
159
+ userMessageExtra: turnUser.userMessageExtra,
160
+ rawContent: turnUser.rawContent,
161
+ context,
162
+ contextForTools,
163
+ allTools,
164
+ resolvedTools,
267
165
  personaEnhanced,
268
- preData,
166
+ modelId: chatCandidates[0] || host.getTurnProvider().models[0] || 'gpt-4o-mini',
167
+ modelCandidates: chatCandidates,
168
+ onChunk,
169
+ initialMessages,
170
+ promptHooks: hooks,
171
+ signal,
269
172
  deferredStats,
270
- });
271
- logger.debug(formatCompact({ mode: 'agent', prompt_chars: systemPrompt.length }));
272
- logger.debug(`[System Prompt Full]\n${systemPrompt}\n---END---`);
273
- const agentTools = applyExecPolicyToTools(host.config, resolvedTools, {
274
- approvalMode: host.config.execApprovalMode,
275
- });
276
- // Adaptive maxIterations: boost when skills are active (multi-step skill flows)
277
- const SKILL_ITERATION_BOOST = 3;
278
- const hasSkillActivation = agentTools.some(t => t.name === 'activate_skill' || t.name === 'install_skill');
279
- const harness = resolveModelHarness(host.getTurnProvider().name, chatCandidates[0] || '', host.config.modelHarness);
280
- const baseIterations = harness.maxIterations ?? host.config.maxIterations;
281
- const effectiveMaxIterations = hasSkillActivation
282
- ? baseIterations + SKILL_ITERATION_BOOST
283
- : baseIterations;
284
- logPhase(host.phaseConfig, 'harness.resolved', sessionId, {
285
- model: chatCandidates[0] || '',
286
- harnessMaxIterations: harness.maxIterations ?? null,
287
- effectiveMaxIterations,
288
- });
289
- let orchestrationPlugin = host.emitter.getHostPlugin() ?? undefined;
290
- if (!orchestrationPlugin) {
291
- try {
292
- orchestrationPlugin = getPlugin().root ?? getPlugin();
293
- }
294
- catch {
295
- logger.warn(formatCompact({ warn: 'no_host_plugin' }));
296
- }
297
- }
298
- const llmAgent = createAgent(host.getTurnProvider(), {
299
- model: chatCandidates[0],
300
- modelFallbacks: chatCandidates.slice(1),
301
- systemPrompt,
302
- tools: agentTools,
303
- maxIterations: effectiveMaxIterations,
304
- turnTimeout: host.config.timeout,
305
- contextWindow: contextBudget.contextWindow,
306
- reservedToolNames: RESERVED_TOOL_NAMES,
307
- reservedToolNamePrefixes: RESERVED_TOOL_NAME_PREFIXES,
308
- transformToolResult: createOwnerOrchestratedToolResultTransform({
309
- toolContext: contextForTools,
310
- disableHardOrchestration: false,
311
- plugin: orchestrationPlugin,
312
- }),
313
- policyDenialStopAfter: host.config.policyDenialStopAfter,
314
- });
315
- llmAgent.on('thinking', (message) => {
316
- host.emitter.emit('ai.thinking', host.emitter.createPayload(sessionId, contextForTools, 'text', {
317
- path: 'agent',
318
- thinking: message,
319
- }));
320
- });
321
- llmAgent.on('tool_call', (toolName, args) => {
322
- host.emitter.emit('ai.tool.call', host.emitter.createPayload(sessionId, contextForTools, 'text', {
323
- path: 'agent',
324
- toolName,
325
- args,
326
- }));
327
- });
328
- llmAgent.on('tool_result', (toolName, result) => {
329
- host.emitter.emit('ai.tool.result', host.emitter.createPayload(sessionId, contextForTools, 'text', {
330
- path: 'agent',
331
- toolName,
332
- result,
333
- }));
334
- });
335
- llmAgent.on('compaction', (info) => {
336
- host.emitSessionCompactEvent(sessionId, contextForTools, 'text', info);
337
- });
338
- const userMessageWithHistory = buildAgentUserMessage(historyMessages, sessionUserContent);
339
- let result;
340
- try {
341
- await host.emitter.dispatch('ai.agent.start', host.emitter.createPayload(sessionId, contextForTools, 'text', {
342
- path: 'agent',
343
- model: chatCandidates[0] || undefined,
344
- }));
345
- logPhase(host.phaseConfig, 'agent.run.start', sessionId, { model: chatCandidates[0] || '' });
346
- result = await runWithBashToolContext(contextForTools, () => llmAgent.run(userMessageWithHistory, []));
347
- logPhase(host.phaseConfig, 'agent.run.end', sessionId, {
348
- iterations: result.iterations,
349
- durationMs: Math.round(now() - tAgent),
350
- ...usageLogFields(result.usage),
351
- });
352
- await host.emitter.dispatch('ai.agent.finish', host.emitter.createPayload(sessionId, contextForTools, 'text', {
353
- path: 'agent',
354
- model: result.model ?? (chatCandidates[0] || undefined),
355
- iterations: result.iterations,
356
- }));
357
- }
358
- catch (error) {
359
- await host.emitter.dispatch('ai.processing.error', host.emitter.createPayload(sessionId, contextForTools, 'text', {
360
- path: 'agent',
361
- error: error instanceof Error ? error.message : String(error),
362
- }));
363
- throw error;
364
- }
365
- finally {
366
- llmAgent.dispose();
367
- }
368
- agentToolCalls = result.toolCalls;
369
- const spawnedSubagent = result.toolCalls.some(tc => tc.tool === 'spawn_task');
370
- if (spawnedSubagent) {
371
- await host.turnTracker.waitForPendingSubagents();
372
- }
373
- const delegatedOnly = spawnedSubagent
374
- && !result.toolCalls.some(tc => tc.tool === 'run_deferred_task')
375
- && !result.toolCalls.some(tc => tc.tool === 'generate_image'
376
- && tc.result
377
- && typeof tc.result === 'object'
378
- && typeof tc.result.image === 'string');
379
- if (delegatedOnly) {
380
- reply = '';
381
- }
382
- else {
383
- reply = sanitizeAssistantReply(result.content, {
384
- toolSummary: formatToolCallsForUser(result.toolCalls),
385
- });
386
- }
387
- await host.emitter.dispatch('ai.response', host.emitter.createPayload(sessionId, contextForTools, 'text', {
388
- path: 'agent',
389
- model: result.model ?? (chatCandidates[0] || undefined),
390
- iterations: result.iterations,
391
- reply,
392
- }));
393
- logger.debug(formatCompact({
394
- agent_answer: truncatePreview(reply, 480),
395
- tool_calls: result.toolCalls.length,
396
- ...(result.toolCalls.length
397
- ? { tools: result.toolCalls.map(tc => tc.tool).join(',') }
398
- : {}),
399
- }));
400
- for (const tc of result.toolCalls) {
401
- const preview = toolCallResultDebugPreview(tc);
402
- logger.debug(formatCompact({
403
- tool_result: tc.tool,
404
- preview: truncatePreview(preview, 480),
405
- }));
406
- }
407
- logger.debug(`[Agent 路径] 过滤=${filterMs}ms, 记忆=${memMs}ms, Agent=${(now() - tAgent).toFixed(0)}ms, 总=${(now() - t0).toFixed(0)}ms`);
408
- await host.finalizeActiveTurn({
409
- usage: result.usage,
410
- path: 'agent',
411
- iterations: result.iterations,
412
- model: result.model ?? (chatCandidates[0] || undefined),
413
- });
414
- }
173
+ }),
174
+ });
175
+ const reply = loopResult.reply;
176
+ await host.emitter.dispatch('ai.response', host.emitter.createPayload(sessionId, context, 'text', {
177
+ path: loopResult.path,
178
+ model: loopResult.model,
179
+ iterations: loopResult.iterations,
180
+ reply,
181
+ }));
415
182
  await touchSession(sessionDeps(host), sessionId);
416
183
  if (isNewSession) {
417
- host.emitSessionNewEvent(sessionId, context, 'text', sessionUserContent, reply);
184
+ host.emitSessionNewEvent(sessionId, context, 'text', turnUser.rawContent, reply);
418
185
  }
186
+ await host.finalizeActiveTurn({
187
+ usage: loopResult.usage,
188
+ path: loopResult.path,
189
+ iterations: loopResult.iterations,
190
+ model: loopResult.model,
191
+ });
419
192
  triggerAIHook(createAIHookEvent('message', 'sent', sessionId, {
420
193
  userId,
421
194
  content: reply,
422
195
  platform: platform || '',
423
196
  })).catch(() => { });
424
197
  await host.emitter.dispatch('ai.processing.finish', host.emitter.createPayload(sessionId, context, 'text', {
425
- path: toolRun.mode === 'pre-exec-fast-path' ? 'fast' : 'agent',
198
+ path: loopResult.path,
199
+ model: loopResult.model,
426
200
  reply,
427
201
  }));
428
- logPhase(host.phaseConfig, 'turn.end', sessionId, { path: toolRun.mode === 'pre-exec-fast-path' ? 'fast' : 'agent' });
429
202
  host.emitter.emit('ai.typing.stop', host.emitter.createPayload(sessionId, context, 'text', {
430
203
  reason: 'processing_complete',
431
204
  }));
432
- const outbound = mergeToolOutboundElements(parseOutput(reply), agentToolCalls);
205
+ logPhase(host.phaseConfig, 'turn.end', sessionId, {
206
+ path: loopResult.path,
207
+ filter_ms: filterMs,
208
+ total_ms: Math.round(now() - t0),
209
+ });
210
+ const outbound = mergeToolOutboundElements(parseOutput(reply), loopResult.toolCalls);
433
211
  if (!reply.trim() && outbound.length === 0)
434
212
  return [];
435
213
  return outbound;
436
214
  }
437
- function toolCallResultDebugPreview(tc) {
438
- if (tc.tool === 'generate_image' && tc.result && typeof tc.result === 'object' && !Array.isArray(tc.result)) {
439
- const image = tc.result.image;
440
- const len = typeof image === 'string' ? image.length : 0;
441
- return len > 0 ? `[image generated, ${len} b64 chars]` : '[generate_image: no image field]';
442
- }
443
- if (tc.tool === 'voice_tts' && tc.result && typeof tc.result === 'object' && !Array.isArray(tc.result)) {
444
- const audio = tc.result.audio;
445
- const len = typeof audio === 'string' ? audio.length : 0;
446
- return len > 0 ? `[audio generated, ${len} b64 chars]` : '[voice_tts: no audio field]';
447
- }
448
- return typeof tc.result === 'string' ? tc.result : JSON.stringify(tc.result);
449
- }
215
+ /** @deprecated 仅保留类型引用;多模态 turn 已统一 agentLoop */
450
216
  export async function processMultimodalTurn(host, parts, context, onChunk) {
451
- const { senderId, sceneId, platform, botId } = context;
217
+ const { senderId, platform, botId } = context;
452
218
  const userId = senderId || 'unknown';
453
219
  const sessionKey = resolveIMSessionIdFromToolContext({
454
220
  platform,
455
221
  botId,
456
222
  scope: context.scope,
457
- sceneId,
223
+ sceneId: context.sceneId,
458
224
  senderId,
459
225
  });
460
- const isNewSession = await resolveSessionIsNewBeforeCreate(sessionDeps(host), sessionKey, context);
226
+ const isNewSession = await resolveSessionIsNewBeforeCreate(sessionDeps(host), sessionKey);
461
227
  await host.waitForMemoryPersistence();
462
228
  const { sessionId } = await beginTurnSession(host, context);
463
229
  await host.emitter.dispatch('ai.processing.start', host.emitter.createPayload(sessionId, context, 'multimodal'));
@@ -475,54 +241,11 @@ export async function processMultimodalTurn(host, parts, context, onChunk) {
475
241
  reason: 'processing',
476
242
  }));
477
243
  host.beginActiveTurn();
478
- const textFragmentsEarly = [];
479
- for (const p of parts) {
480
- if (p.type === 'text')
481
- textFragmentsEarly.push(p.text);
482
- }
483
- const textContentEarly = textFragmentsEarly.join(' ') || '[多模态消息]';
484
- const sessionUserContentEarly = formatUserContentForSession(context, textContentEarly);
485
- const rawHistoryMessages = await buildHistoryMessages(sessionDeps(host), sessionId, context, sessionUserContentEarly);
244
+ const supportsVision = providerSupportsVision(host.getTurnProvider());
245
+ const textContent = summarizeMultimodalParts(parts, supportsVision);
246
+ const turnUser = buildTurnUserMessages(context, textContent);
486
247
  const profileSummary = await host.userProfiles.buildProfileSummary(userId);
487
248
  const personaEnhanced = host.buildDisciplinedPrompt(buildEnhancedPersona(host.config, profileSummary, ''));
488
- const textFragments = [];
489
- const llmParts = [];
490
- const supportsVision = providerSupportsVision(host.getTurnProvider());
491
- for (const p of parts) {
492
- switch (p.type) {
493
- case 'text':
494
- textFragments.push(p.text);
495
- llmParts.push(p);
496
- break;
497
- case 'image_url':
498
- textFragments.push('[图片]');
499
- if (supportsVision)
500
- llmParts.push(p);
501
- else
502
- llmParts.push({ type: 'text', text: '[用户发送了一张图片]' });
503
- break;
504
- case 'video_url':
505
- textFragments.push('[视频]');
506
- llmParts.push({ type: 'text', text: `[用户发送了一个视频: ${p.video_url.url}]` });
507
- break;
508
- case 'audio':
509
- textFragments.push('[音频]');
510
- if (supportsVision)
511
- llmParts.push(p);
512
- else
513
- llmParts.push({ type: 'text', text: '[用户发送了一段音频]' });
514
- break;
515
- case 'face':
516
- textFragments.push(p.face.text || `[表情:${p.face.id}]`);
517
- llmParts.push({
518
- type: 'text',
519
- text: p.face.text ? `[表情: ${p.face.text}]` : `[表情ID: ${p.face.id}]`,
520
- });
521
- break;
522
- }
523
- }
524
- const textContent = textFragments.join(' ') || '[多模态消息]';
525
- const sessionUserContent = formatUserContentForSession(context, textContent);
526
249
  const visionSystemPrompt = await buildMultimodalVisionSystemPrompt(host, {
527
250
  context,
528
251
  sessionId,
@@ -530,95 +253,58 @@ export async function processMultimodalTurn(host, parts, context, onChunk) {
530
253
  personaEnhanced,
531
254
  });
532
255
  const visionCandidates = resolveModelCandidates(host.getTurnProvider().models, host.modelRegistry, host.getTurnProvider().name, host.config, 'vision');
533
- const { messages: historyMessages, result: pruneResult } = pruneHistoryWithBudget({
534
- messages: rawHistoryMessages,
535
- config: host.config,
536
- provider: host.getTurnProvider(),
537
- modelRegistry: host.modelRegistry,
538
- model: visionCandidates[0],
539
- });
540
- if (pruneResult.droppedCount > 0) {
541
- logger.debug(`[多模态上下文窗口] 丢弃 ${pruneResult.droppedCount} 条历史消息 (${pruneResult.droppedTokens} tokens)`);
256
+ logPhase(host.phaseConfig, 'path.agent_loop', sessionId, { mode: 'multimodal' });
257
+ const userMessage = await buildVisionUserMessage(userMessagePlainText(turnUser.promptMessages[0]), parts, supportsVision, DEFAULT_MULTIMODAL_CONFIG.maxFileBytes);
258
+ let loopResult;
259
+ try {
260
+ loopResult = await host.promptController.schedule({
261
+ sessionKey,
262
+ sessionId,
263
+ userMessages: [userMessage],
264
+ context,
265
+ onChunk,
266
+ execute: (initialMessages, hooks, signal, _turnId) => runAgentLoopVisionTurn({
267
+ host,
268
+ sessionId,
269
+ context,
270
+ visionSystemPrompt,
271
+ userMessages: initialMessages,
272
+ modelCandidates: visionCandidates,
273
+ onChunk,
274
+ promptHooks: hooks,
275
+ signal,
276
+ }),
277
+ });
542
278
  }
543
- const messages = [
544
- { role: 'system', content: visionSystemPrompt },
545
- ...historyMessages,
546
- { role: 'user', content: llmParts },
547
- ];
548
- let reply = '';
549
- let lastUsage = null;
550
- let usedVisionModel = visionCandidates[0] || '';
551
- for (let i = 0; i < visionCandidates.length; i++) {
552
- const visionModel = visionCandidates[i];
553
- usedVisionModel = visionModel;
554
- try {
555
- reply = '';
556
- for await (const chunk of host.getTurnProvider().chatStream({ model: visionModel, messages })) {
557
- if (chunk.usage)
558
- lastUsage = chunk.usage;
559
- const delta = chunk.choices?.[0]?.delta;
560
- if (!delta)
561
- continue;
562
- const text = typeof delta.content === 'string' ? delta.content : '';
563
- if (text) {
564
- reply += text;
565
- if (onChunk)
566
- onChunk(text, reply);
567
- }
568
- }
569
- reply = stripThinkBlocks(reply);
570
- if (!reply) {
571
- logger.warn(formatCompact({ mode: 'multimodal', fallback: visionModel, reason: 'empty_stream' }));
572
- const response = await host.getTurnProvider().chat({ model: visionModel, messages });
573
- if (response.usage)
574
- lastUsage = response.usage;
575
- const msg = response.choices[0]?.message?.content;
576
- reply = stripThinkBlocks(typeof msg === 'string' ? msg : '');
577
- }
578
- if (reply)
579
- break;
580
- }
581
- catch (err) {
582
- const isLast = i === visionCandidates.length - 1;
583
- if (isLast) {
584
- try {
585
- const response = await host.getTurnProvider().chat({ model: visionModel, messages });
586
- if (response.usage)
587
- lastUsage = response.usage;
588
- const msg = response.choices[0]?.message?.content;
589
- reply = stripThinkBlocks(typeof msg === 'string' ? msg : '');
590
- }
591
- catch { /* all candidates exhausted */ }
592
- }
593
- else {
594
- logger.warn(formatCompact({
595
- mode: 'multimodal',
596
- fallback: `${visionModel}→${visionCandidates[i + 1]}`,
597
- error: truncatePreview(err.message),
598
- }));
599
- }
600
- }
279
+ catch {
280
+ loopResult = {
281
+ reply: '抱歉,我无法理解这条消息。',
282
+ usage: EMPTY_USAGE,
283
+ path: 'multimodal',
284
+ iterations: 0,
285
+ model: visionCandidates[0] || '',
286
+ toolCalls: [],
287
+ };
601
288
  }
602
- if (!reply)
603
- reply = '抱歉,我无法理解这条消息。';
604
- reply = sanitizeAssistantReply(reply);
289
+ const reply = loopResult.reply;
605
290
  await host.emitter.dispatch('ai.response', host.emitter.createPayload(sessionId, context, 'multimodal', {
606
291
  path: 'multimodal',
607
- model: usedVisionModel,
292
+ model: loopResult.model,
608
293
  reply,
609
294
  }));
610
295
  await touchSession(sessionDeps(host), sessionId);
611
296
  if (isNewSession) {
612
- host.emitSessionNewEvent(sessionId, context, 'multimodal', sessionUserContent, reply);
297
+ host.emitSessionNewEvent(sessionId, context, 'multimodal', turnUser.rawContent, reply);
613
298
  }
614
299
  await host.finalizeActiveTurn({
615
- usage: lastUsage ?? EMPTY_USAGE,
300
+ usage: loopResult.usage,
616
301
  path: 'multimodal',
617
- model: usedVisionModel,
302
+ model: loopResult.model,
303
+ iterations: loopResult.iterations,
618
304
  });
619
305
  await host.emitter.dispatch('ai.processing.finish', host.emitter.createPayload(sessionId, context, 'multimodal', {
620
306
  path: 'multimodal',
621
- model: usedVisionModel,
307
+ model: loopResult.model,
622
308
  reply,
623
309
  }));
624
310
  host.emitter.emit('ai.typing.stop', host.emitter.createPayload(sessionId, context, 'multimodal', {