@renxqoo/renx-code 0.0.8 → 0.0.10

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 (286) hide show
  1. package/README.md +114 -40
  2. package/bin/renx.cjs +79 -42
  3. package/bin/renx.exe +0 -0
  4. package/package.json +10 -28
  5. package/src/App.tsx +0 -297
  6. package/src/agent/runtime/event-format.ts +0 -258
  7. package/src/agent/runtime/model-types.ts +0 -13
  8. package/src/agent/runtime/runtime.context-usage.test.ts +0 -192
  9. package/src/agent/runtime/runtime.error-handling.test.ts +0 -235
  10. package/src/agent/runtime/runtime.simple.test.ts +0 -16
  11. package/src/agent/runtime/runtime.test.ts +0 -296
  12. package/src/agent/runtime/runtime.ts +0 -875
  13. package/src/agent/runtime/runtime.usage-forwarding.test.ts +0 -228
  14. package/src/agent/runtime/source-modules.test.ts +0 -38
  15. package/src/agent/runtime/source-modules.ts +0 -370
  16. package/src/agent/runtime/tool-call-buffer.test.ts +0 -65
  17. package/src/agent/runtime/tool-call-buffer.ts +0 -60
  18. package/src/agent/runtime/tool-confirmation.test.ts +0 -56
  19. package/src/agent/runtime/tool-confirmation.ts +0 -15
  20. package/src/agent/runtime/types.ts +0 -99
  21. package/src/commands/slash-commands.test.ts +0 -216
  22. package/src/commands/slash-commands.ts +0 -64
  23. package/src/components/chat/assistant-reply.test.tsx +0 -47
  24. package/src/components/chat/assistant-reply.tsx +0 -136
  25. package/src/components/chat/assistant-segment.test.ts +0 -99
  26. package/src/components/chat/assistant-segment.tsx +0 -125
  27. package/src/components/chat/assistant-tool-group.tsx +0 -900
  28. package/src/components/chat/code-block.test.tsx +0 -206
  29. package/src/components/chat/code-block.tsx +0 -313
  30. package/src/components/chat/prompt-card.tsx +0 -81
  31. package/src/components/chat/segment-groups.test.ts +0 -52
  32. package/src/components/chat/segment-groups.ts +0 -106
  33. package/src/components/chat/turn-item.tsx +0 -39
  34. package/src/components/conversation-panel.tsx +0 -43
  35. package/src/components/file-mention-menu.tsx +0 -77
  36. package/src/components/file-picker-dialog.tsx +0 -206
  37. package/src/components/footer-hints.tsx +0 -75
  38. package/src/components/model-picker-dialog.tsx +0 -248
  39. package/src/components/prompt.tsx +0 -233
  40. package/src/components/slash-command-menu.tsx +0 -65
  41. package/src/components/tool-confirm-dialog-content.test.ts +0 -103
  42. package/src/components/tool-confirm-dialog-content.ts +0 -186
  43. package/src/components/tool-confirm-dialog.tsx +0 -187
  44. package/src/components/tool-display-config.ts +0 -119
  45. package/src/context-usage-regressions.test.ts +0 -26
  46. package/src/files/attachment-capabilities.test.ts +0 -30
  47. package/src/files/attachment-capabilities.ts +0 -50
  48. package/src/files/attachment-content.ts +0 -153
  49. package/src/files/file-mention-query.test.ts +0 -34
  50. package/src/files/file-mention-query.ts +0 -32
  51. package/src/files/prompt-display.ts +0 -13
  52. package/src/files/types.ts +0 -5
  53. package/src/files/workspace-files.ts +0 -61
  54. package/src/hooks/agent-event-handlers.test.ts +0 -207
  55. package/src/hooks/agent-event-handlers.ts +0 -196
  56. package/src/hooks/chat-local-replies.fixed.test.ts +0 -119
  57. package/src/hooks/chat-local-replies.test.ts +0 -153
  58. package/src/hooks/chat-local-replies.ts +0 -63
  59. package/src/hooks/turn-updater.test.ts +0 -70
  60. package/src/hooks/turn-updater.ts +0 -166
  61. package/src/hooks/use-agent-chat.context.test.ts +0 -10
  62. package/src/hooks/use-agent-chat.status.test.ts +0 -14
  63. package/src/hooks/use-agent-chat.test.ts +0 -80
  64. package/src/hooks/use-agent-chat.ts +0 -621
  65. package/src/hooks/use-file-mention-menu.ts +0 -196
  66. package/src/hooks/use-file-picker.ts +0 -185
  67. package/src/hooks/use-model-picker.ts +0 -196
  68. package/src/hooks/use-slash-command-menu.ts +0 -154
  69. package/src/index.tsx +0 -55
  70. package/src/runtime/clipboard.test.ts +0 -43
  71. package/src/runtime/clipboard.ts +0 -89
  72. package/src/runtime/exit.test.ts +0 -177
  73. package/src/runtime/exit.ts +0 -98
  74. package/src/runtime/runtime-support.test.ts +0 -31
  75. package/src/runtime/terminal-theme.test.ts +0 -55
  76. package/src/runtime/terminal-theme.ts +0 -196
  77. package/src/types/chat.ts +0 -32
  78. package/src/types/message-content.ts +0 -48
  79. package/src/ui/open-code-theme.ts +0 -176
  80. package/src/ui/opencode-markdown.ts +0 -211
  81. package/src/ui/theme.simple.test.ts +0 -52
  82. package/src/ui/theme.test.ts +0 -151
  83. package/src/ui/theme.ts +0 -152
  84. package/src/utils/time.test.ts +0 -144
  85. package/src/utils/time.ts +0 -7
  86. package/tsconfig.json +0 -30
  87. package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +0 -95
  88. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +0 -1345
  89. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +0 -1353
  90. package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +0 -60
  91. package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +0 -278
  92. package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +0 -72
  93. package/vendor/agent-root/src/agent/__test__/types.test.ts +0 -137
  94. package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +0 -83
  95. package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +0 -34
  96. package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +0 -323
  97. package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +0 -290
  98. package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +0 -377
  99. package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +0 -212
  100. package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +0 -295
  101. package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +0 -3607
  102. package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +0 -35
  103. package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +0 -517
  104. package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +0 -97
  105. package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +0 -479
  106. package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +0 -80
  107. package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +0 -76
  108. package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +0 -173
  109. package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +0 -109
  110. package/vendor/agent-root/src/agent/agent/abort-runtime.ts +0 -71
  111. package/vendor/agent-root/src/agent/agent/callback-safety.ts +0 -33
  112. package/vendor/agent-root/src/agent/agent/compaction.ts +0 -291
  113. package/vendor/agent-root/src/agent/agent/concurrency.ts +0 -103
  114. package/vendor/agent-root/src/agent/agent/error-normalizer.ts +0 -190
  115. package/vendor/agent-root/src/agent/agent/error.ts +0 -198
  116. package/vendor/agent-root/src/agent/agent/index.ts +0 -1772
  117. package/vendor/agent-root/src/agent/agent/logger.ts +0 -65
  118. package/vendor/agent-root/src/agent/agent/message-utils.ts +0 -101
  119. package/vendor/agent-root/src/agent/agent/stream-events.ts +0 -61
  120. package/vendor/agent-root/src/agent/agent/telemetry.ts +0 -123
  121. package/vendor/agent-root/src/agent/agent/timeout-budget.ts +0 -227
  122. package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +0 -111
  123. package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +0 -164
  124. package/vendor/agent-root/src/agent/agent/write-buffer.ts +0 -188
  125. package/vendor/agent-root/src/agent/agent/write-file-session.ts +0 -238
  126. package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +0 -1053
  127. package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +0 -158
  128. package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +0 -437
  129. package/vendor/agent-root/src/agent/app/agent-app-service.ts +0 -748
  130. package/vendor/agent-root/src/agent/app/contracts.ts +0 -109
  131. package/vendor/agent-root/src/agent/app/index.ts +0 -5
  132. package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +0 -151
  133. package/vendor/agent-root/src/agent/app/ports.ts +0 -72
  134. package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +0 -1182
  135. package/vendor/agent-root/src/agent/app/sqlite-client.ts +0 -177
  136. package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +0 -36
  137. package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +0 -33
  138. package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +0 -40
  139. package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +0 -91
  140. package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +0 -116
  141. package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +0 -52
  142. package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +0 -53
  143. package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +0 -52
  144. package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +0 -40
  145. package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +0 -19
  146. package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +0 -28
  147. package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +0 -26
  148. package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +0 -30
  149. package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +0 -567
  150. package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +0 -583
  151. package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +0 -972
  152. package/vendor/agent-root/src/agent/error-contract.ts +0 -154
  153. package/vendor/agent-root/src/agent/prompts/system.ts +0 -246
  154. package/vendor/agent-root/src/agent/prompts/system1.ts +0 -208
  155. package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +0 -98
  156. package/vendor/agent-root/src/agent/storage/file-history-store.ts +0 -313
  157. package/vendor/agent-root/src/agent/storage/file-storage-config.ts +0 -94
  158. package/vendor/agent-root/src/agent/storage/file-system.ts +0 -31
  159. package/vendor/agent-root/src/agent/storage/file-write-service.ts +0 -21
  160. package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +0 -413
  161. package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +0 -356
  162. package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +0 -375
  163. package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +0 -372
  164. package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +0 -108
  165. package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +0 -258
  166. package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +0 -121
  167. package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +0 -210
  168. package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +0 -139
  169. package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +0 -456
  170. package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +0 -192
  171. package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +0 -300
  172. package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +0 -214
  173. package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +0 -336
  174. package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +0 -494
  175. package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +0 -543
  176. package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +0 -172
  177. package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +0 -116
  178. package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +0 -267
  179. package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +0 -519
  180. package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +0 -225
  181. package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +0 -223
  182. package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +0 -184
  183. package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +0 -287
  184. package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +0 -190
  185. package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +0 -352
  186. package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +0 -395
  187. package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +0 -391
  188. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +0 -176
  189. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +0 -68
  190. package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +0 -630
  191. package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +0 -732
  192. package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +0 -494
  193. package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +0 -175
  194. package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +0 -505
  195. package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +0 -55
  196. package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +0 -244
  197. package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +0 -290
  198. package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +0 -368
  199. package/vendor/agent-root/src/agent/tool/base-tool.ts +0 -345
  200. package/vendor/agent-root/src/agent/tool/bash-policy.ts +0 -636
  201. package/vendor/agent-root/src/agent/tool/bash.ts +0 -688
  202. package/vendor/agent-root/src/agent/tool/error.ts +0 -131
  203. package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +0 -264
  204. package/vendor/agent-root/src/agent/tool/file-history-list.ts +0 -103
  205. package/vendor/agent-root/src/agent/tool/file-history-restore.ts +0 -149
  206. package/vendor/agent-root/src/agent/tool/file-read-tool.ts +0 -211
  207. package/vendor/agent-root/src/agent/tool/glob.ts +0 -171
  208. package/vendor/agent-root/src/agent/tool/grep.ts +0 -496
  209. package/vendor/agent-root/src/agent/tool/lsp.ts +0 -481
  210. package/vendor/agent-root/src/agent/tool/path-security.ts +0 -117
  211. package/vendor/agent-root/src/agent/tool/search/common.ts +0 -153
  212. package/vendor/agent-root/src/agent/tool/skill/index.ts +0 -13
  213. package/vendor/agent-root/src/agent/tool/skill/loader.ts +0 -229
  214. package/vendor/agent-root/src/agent/tool/skill/parser.ts +0 -124
  215. package/vendor/agent-root/src/agent/tool/skill/types.ts +0 -27
  216. package/vendor/agent-root/src/agent/tool/skill-tool.ts +0 -143
  217. package/vendor/agent-root/src/agent/tool/task-create.ts +0 -186
  218. package/vendor/agent-root/src/agent/tool/task-errors.ts +0 -42
  219. package/vendor/agent-root/src/agent/tool/task-get.ts +0 -116
  220. package/vendor/agent-root/src/agent/tool/task-graph.ts +0 -78
  221. package/vendor/agent-root/src/agent/tool/task-list.ts +0 -141
  222. package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +0 -232
  223. package/vendor/agent-root/src/agent/tool/task-output.ts +0 -223
  224. package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +0 -115
  225. package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +0 -336
  226. package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +0 -55
  227. package/vendor/agent-root/src/agent/tool/task-stop.ts +0 -187
  228. package/vendor/agent-root/src/agent/tool/task-store.ts +0 -217
  229. package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +0 -149
  230. package/vendor/agent-root/src/agent/tool/task-types.ts +0 -264
  231. package/vendor/agent-root/src/agent/tool/task-update.ts +0 -315
  232. package/vendor/agent-root/src/agent/tool/task.ts +0 -209
  233. package/vendor/agent-root/src/agent/tool/tool-manager.ts +0 -361
  234. package/vendor/agent-root/src/agent/tool/tool-prompts.ts +0 -242
  235. package/vendor/agent-root/src/agent/tool/types.ts +0 -116
  236. package/vendor/agent-root/src/agent/tool/web-fetch.ts +0 -227
  237. package/vendor/agent-root/src/agent/tool/web-search.ts +0 -208
  238. package/vendor/agent-root/src/agent/tool/write-file.ts +0 -497
  239. package/vendor/agent-root/src/agent/types.ts +0 -232
  240. package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +0 -18
  241. package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +0 -610
  242. package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +0 -223
  243. package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +0 -42
  244. package/vendor/agent-root/src/agent/utils/index.ts +0 -16
  245. package/vendor/agent-root/src/agent/utils/message.ts +0 -171
  246. package/vendor/agent-root/src/agent/utils/token.ts +0 -28
  247. package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +0 -238
  248. package/vendor/agent-root/src/config/__tests__/loader.test.ts +0 -361
  249. package/vendor/agent-root/src/config/__tests__/runtime.test.ts +0 -88
  250. package/vendor/agent-root/src/config/index.ts +0 -55
  251. package/vendor/agent-root/src/config/loader.ts +0 -494
  252. package/vendor/agent-root/src/config/paths.ts +0 -30
  253. package/vendor/agent-root/src/config/runtime.ts +0 -163
  254. package/vendor/agent-root/src/config/types.ts +0 -96
  255. package/vendor/agent-root/src/logger/index.ts +0 -57
  256. package/vendor/agent-root/src/logger/logger.ts +0 -819
  257. package/vendor/agent-root/src/logger/types.ts +0 -150
  258. package/vendor/agent-root/src/providers/__tests__/errors.test.ts +0 -441
  259. package/vendor/agent-root/src/providers/__tests__/index.test.ts +0 -16
  260. package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +0 -318
  261. package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +0 -600
  262. package/vendor/agent-root/src/providers/__tests__/registry.test.ts +0 -523
  263. package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +0 -298
  264. package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +0 -354
  265. package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +0 -58
  266. package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +0 -261
  267. package/vendor/agent-root/src/providers/adapters/anthropic.ts +0 -572
  268. package/vendor/agent-root/src/providers/adapters/base.ts +0 -131
  269. package/vendor/agent-root/src/providers/adapters/kimi.ts +0 -48
  270. package/vendor/agent-root/src/providers/adapters/responses.ts +0 -732
  271. package/vendor/agent-root/src/providers/adapters/standard.ts +0 -120
  272. package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +0 -313
  273. package/vendor/agent-root/src/providers/http/client.ts +0 -289
  274. package/vendor/agent-root/src/providers/http/stream-parser.ts +0 -109
  275. package/vendor/agent-root/src/providers/index.ts +0 -76
  276. package/vendor/agent-root/src/providers/kimi-headers.ts +0 -177
  277. package/vendor/agent-root/src/providers/openai-compatible.ts +0 -387
  278. package/vendor/agent-root/src/providers/registry/model-config.ts +0 -477
  279. package/vendor/agent-root/src/providers/registry/provider-factory.ts +0 -127
  280. package/vendor/agent-root/src/providers/registry.ts +0 -135
  281. package/vendor/agent-root/src/providers/types/api.ts +0 -284
  282. package/vendor/agent-root/src/providers/types/config.ts +0 -58
  283. package/vendor/agent-root/src/providers/types/errors.ts +0 -323
  284. package/vendor/agent-root/src/providers/types/index.ts +0 -72
  285. package/vendor/agent-root/src/providers/types/provider.ts +0 -45
  286. package/vendor/agent-root/src/providers/types/registry.ts +0 -68
@@ -1,1345 +0,0 @@
1
- <!DOCTYPE html><html><head>
2
- <title>ENTERPRISE_REALTIME</title>
3
- <meta charset="utf-8">
4
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
-
6
- <link rel="stylesheet" href="file:///c:\Users\Administrator\.trae-cn\extensions\shd101wyy.markdown-preview-enhanced-0.8.20-universal\crossnote\dependencies\katex\katex.min.css">
7
-
8
-
9
-
10
-
11
-
12
- <style>
13
- code[class*=language-],pre[class*=language-]{color:#333;background:0 0;font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.4;-moz-tab-size:8;-o-tab-size:8;tab-size:8;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:.8em;overflow:auto;border-radius:3px;background:#f5f5f5}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal;background:#f5f5f5}.token.blockquote,.token.comment{color:#969896}.token.cdata{color:#183691}.token.doctype,.token.macro.property,.token.punctuation,.token.variable{color:#333}.token.builtin,.token.important,.token.keyword,.token.operator,.token.rule{color:#a71d5d}.token.attr-value,.token.regex,.token.string,.token.url{color:#183691}.token.atrule,.token.boolean,.token.code,.token.command,.token.constant,.token.entity,.token.number,.token.property,.token.symbol{color:#0086b3}.token.prolog,.token.selector,.token.tag{color:#63a35c}.token.attr-name,.token.class,.token.class-name,.token.function,.token.id,.token.namespace,.token.pseudo-class,.token.pseudo-element,.token.url-reference .token.variable{color:#795da3}.token.entity{cursor:help}.token.title,.token.title .token.punctuation{font-weight:700;color:#1d3e81}.token.list{color:#ed6a43}.token.inserted{background-color:#eaffea;color:#55a532}.token.deleted{background-color:#ffecec;color:#bd2c00}.token.bold{font-weight:700}.token.italic{font-style:italic}.language-json .token.property{color:#183691}.language-markup .token.tag .token.punctuation{color:#333}.language-css .token.function,code.language-css{color:#0086b3}.language-yaml .token.atrule{color:#63a35c}code.language-yaml{color:#183691}.language-ruby .token.function{color:#333}.language-markdown .token.url{color:#795da3}.language-makefile .token.symbol{color:#795da3}.language-makefile .token.variable{color:#183691}.language-makefile .token.builtin{color:#0086b3}.language-bash .token.keyword{color:#0086b3}pre[data-line]{position:relative;padding:1em 0 1em 3em}pre[data-line] .line-highlight-wrapper{position:absolute;top:0;left:0;background-color:transparent;display:block;width:100%}pre[data-line] .line-highlight{position:absolute;left:0;right:0;padding:inherit 0;margin-top:1em;background:hsla(24,20%,50%,.08);background:linear-gradient(to right,hsla(24,20%,50%,.1) 70%,hsla(24,20%,50%,0));pointer-events:none;line-height:inherit;white-space:pre}pre[data-line] .line-highlight:before,pre[data-line] .line-highlight[data-end]:after{content:attr(data-start);position:absolute;top:.4em;left:.6em;min-width:1em;padding:0 .5em;background-color:hsla(24,20%,50%,.4);color:#f4f1ef;font:bold 65%/1.5 sans-serif;text-align:center;vertical-align:.3em;border-radius:999px;text-shadow:none;box-shadow:0 1px #fff}pre[data-line] .line-highlight[data-end]:after{content:attr(data-end);top:auto;bottom:.4em}html body{font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif;font-size:16px;line-height:1.6;color:#333;background-color:#fff;overflow:initial;box-sizing:border-box;word-wrap:break-word}html body>:first-child{margin-top:0}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{line-height:1.2;margin-top:1em;margin-bottom:16px;color:#000}html body h1{font-size:2.25em;font-weight:300;padding-bottom:.3em}html body h2{font-size:1.75em;font-weight:400;padding-bottom:.3em}html body h3{font-size:1.5em;font-weight:500}html body h4{font-size:1.25em;font-weight:600}html body h5{font-size:1.1em;font-weight:600}html body h6{font-size:1em;font-weight:600}html body h1,html body h2,html body h3,html body h4,html body h5{font-weight:600}html body h5{font-size:1em}html body h6{color:#5c5c5c}html body strong{color:#000}html body del{color:#5c5c5c}html body a:not([href]){color:inherit;text-decoration:none}html body a{color:#08c;text-decoration:none}html body a:hover{color:#00a3f5;text-decoration:none}html body img{max-width:100%}html body>p{margin-top:0;margin-bottom:16px;word-wrap:break-word}html body>ol,html body>ul{margin-bottom:16px}html body ol,html body ul{padding-left:2em}html body ol.no-list,html body ul.no-list{padding:0;list-style-type:none}html body ol ol,html body ol ul,html body ul ol,html body ul ul{margin-top:0;margin-bottom:0}html body li{margin-bottom:0}html body li.task-list-item{list-style:none}html body li>p{margin-top:0;margin-bottom:0}html body .task-list-item-checkbox{margin:0 .2em .25em -1.8em;vertical-align:middle}html body .task-list-item-checkbox:hover{cursor:pointer}html body blockquote{margin:16px 0;font-size:inherit;padding:0 15px;color:#5c5c5c;background-color:#f0f0f0;border-left:4px solid #d6d6d6}html body blockquote>:first-child{margin-top:0}html body blockquote>:last-child{margin-bottom:0}html body hr{height:4px;margin:32px 0;background-color:#d6d6d6;border:0 none}html body table{margin:10px 0 15px 0;border-collapse:collapse;border-spacing:0;display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}html body table th{font-weight:700;color:#000}html body table td,html body table th{border:1px solid #d6d6d6;padding:6px 13px}html body dl{padding:0}html body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}html body dl dd{padding:0 16px;margin-bottom:16px}html body code{font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:.85em;color:#000;background-color:#f0f0f0;border-radius:3px;padding:.2em 0}html body code::after,html body code::before{letter-spacing:-.2em;content:'\00a0'}html body pre>code{padding:0;margin:0;word-break:normal;white-space:pre;background:0 0;border:0}html body .highlight{margin-bottom:16px}html body .highlight pre,html body pre{padding:1em;overflow:auto;line-height:1.45;border:#d6d6d6;border-radius:3px}html body .highlight pre{margin-bottom:0;word-break:normal}html body pre code,html body pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}html body pre code:after,html body pre code:before,html body pre tt:after,html body pre tt:before{content:normal}html body blockquote,html body dl,html body ol,html body p,html body pre,html body ul{margin-top:0;margin-bottom:16px}html body kbd{color:#000;border:1px solid #d6d6d6;border-bottom:2px solid #c7c7c7;padding:2px 4px;background-color:#f0f0f0;border-radius:3px}@media print{html body{background-color:#fff}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{color:#000;page-break-after:avoid}html body blockquote{color:#5c5c5c}html body pre{page-break-inside:avoid}html body table{display:table}html body img{display:block;max-width:100%;max-height:100%}html body code,html body pre{word-wrap:break-word;white-space:pre}}.markdown-preview{width:100%;height:100%;box-sizing:border-box}.markdown-preview ul{list-style:disc}.markdown-preview ul ul{list-style:circle}.markdown-preview ul ul ul{list-style:square}.markdown-preview ol{list-style:decimal}.markdown-preview ol ol,.markdown-preview ul ol{list-style-type:lower-roman}.markdown-preview ol ol ol,.markdown-preview ol ul ol,.markdown-preview ul ol ol,.markdown-preview ul ul ol{list-style-type:lower-alpha}.markdown-preview .newpage,.markdown-preview .pagebreak{page-break-before:always}.markdown-preview pre.line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}.markdown-preview pre.line-numbers>code{position:relative}.markdown-preview pre.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:1em;font-size:100%;left:0;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.markdown-preview pre.line-numbers .line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.markdown-preview pre.line-numbers .line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.markdown-preview .mathjax-exps .MathJax_Display{text-align:center!important}.markdown-preview:not([data-for=preview]) .code-chunk .code-chunk-btn-group{display:none}.markdown-preview:not([data-for=preview]) .code-chunk .status{display:none}.markdown-preview:not([data-for=preview]) .code-chunk .output-div{margin-bottom:16px}.markdown-preview .md-toc{padding:0}.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link{display:inline;padding:.25rem 0}.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link div,.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link p{display:inline}.markdown-preview .md-toc .md-toc-link-wrapper.highlighted .md-toc-link{font-weight:800}.scrollbar-style::-webkit-scrollbar{width:8px}.scrollbar-style::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}.scrollbar-style::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,.66);border:4px solid rgba(150,150,150,.66);background-clip:content-box}html body[for=html-export]:not([data-presentation-mode]){position:relative;width:100%;height:100%;top:0;left:0;margin:0;padding:0;overflow:auto}html body[for=html-export]:not([data-presentation-mode]) .markdown-preview{position:relative;top:0;min-height:100vh}@media screen and (min-width:914px){html body[for=html-export]:not([data-presentation-mode]) .markdown-preview{padding:2em calc(50% - 457px + 2em)}}@media screen and (max-width:914px){html body[for=html-export]:not([data-presentation-mode]) .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for=html-export]:not([data-presentation-mode]) .markdown-preview{font-size:14px!important;padding:1em}}@media print{html body[for=html-export]:not([data-presentation-mode]) #sidebar-toc-btn{display:none}}html body[for=html-export]:not([data-presentation-mode]) #sidebar-toc-btn{position:fixed;bottom:8px;left:8px;font-size:28px;cursor:pointer;color:inherit;z-index:99;width:32px;text-align:center;opacity:.4}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] #sidebar-toc-btn{opacity:1}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc{position:fixed;top:0;left:0;width:300px;height:100%;padding:32px 0 48px 0;font-size:14px;box-shadow:0 0 4px rgba(150,150,150,.33);box-sizing:border-box;overflow:auto;background-color:inherit}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar{width:8px}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,.66);border:4px solid rgba(150,150,150,.66);background-clip:content-box}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc a{text-decoration:none}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc{padding:0 16px}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link{display:inline;padding:.25rem 0}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link div,html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link p{display:inline}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper.highlighted .md-toc-link{font-weight:800}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{left:300px;width:calc(100% - 300px);padding:2em calc(50% - 457px - 300px / 2);margin:0;box-sizing:border-box}@media screen and (max-width:1274px){html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{width:100%}}html body[for=html-export]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .markdown-preview{left:50%;transform:translateX(-50%)}html body[for=html-export]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .md-sidebar-toc{display:none}
14
- /* Please visit the URL below for more information: */
15
- /* https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */
16
-
17
- </style>
18
- <!-- The content below will be included at the end of the <head> element. --><script type="text/javascript">
19
- document.addEventListener("DOMContentLoaded", function () {
20
- // your code here
21
- });
22
- </script></head><body for="html-export">
23
-
24
-
25
- <div class="crossnote markdown-preview ">
26
-
27
- <h1 id="企业级无状态-agent-实时存储方案">企业级无状态 Agent 实时存储方案 </h1>
28
- <h2 id="一-问题分析">一、问题分析 </h2>
29
- <pre data-role="codeBlock" data-info="" class="language-text"><code>当前设计的问题:
30
- ┌─────────────────────────────────────────────────────────────────┐
31
- │ │
32
- │ Agent 执行 (可能 10 分钟+) │
33
- │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
34
- │ │ Step 1 │→ │ Step 2 │→ │ Step 3 │→ │ Step N │ │
35
- │ │ │ │ │ │ │ │ │ │
36
- │ │ 消息在 │ │ 消息在 │ │ 消息在 │ │ 消息在 │ │
37
- │ │ 内存 │ │ 内存 │ │ 内存 │ │ 内存 │ │
38
- │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
39
- │ │ │
40
- │ ▼ │
41
- │ ❌ 只有完成时才存储 │
42
- │ │
43
- │ 问题: │
44
- │ - Agent 崩溃 = 所有消息丢失 │
45
- │ - 页面关闭 = 请求中断 │
46
- │ - 无法实时查看执行进度 │
47
- │ - 无法从中间步骤恢复 │
48
- └─────────────────────────────────────────────────────────────────┘
49
- </code></pre><hr>
50
- <h2 id="二-解决方案概述">二、解决方案概述 </h2>
51
- <pre data-role="codeBlock" data-info="" class="language-text"><code>核心思路: 实时存储 + 后台执行 + 检查点恢复
52
-
53
- ┌─────────────────────────────────────────────────────────────────┐
54
- │ │
55
- │ 1. 实时存储 │
56
- │ - 每条消息产生时立即存储 │
57
- │ - 每个 Step 完成时保存检查点 │
58
- │ │
59
- │ 2. 后台执行 (Fire and Forget) │
60
- │ - API 立即返回 executionId │
61
- │ - Worker 后台执行 │
62
- │ - 页面关闭不受影响 │
63
- │ │
64
- │ 3. 故障恢复 │
65
- │ - 检查点记录执行位置 │
66
- │ - 从 lastMessageId 恢复 │
67
- │ │
68
- └─────────────────────────────────────────────────────────────────┘
69
- </code></pre><hr>
70
- <h2 id="三-核心概念">三、核心概念 </h2>
71
- <table>
72
- <thead>
73
- <tr>
74
- <th>概念</th>
75
- <th>说明</th>
76
- </tr>
77
- </thead>
78
- <tbody>
79
- <tr>
80
- <td><strong>sessionId</strong></td>
81
- <td>整个对话(用户和 AI 之间的会话)</td>
82
- </tr>
83
- <tr>
84
- <td><strong>executionId</strong></td>
85
- <td>一次 agent.run()(用户的一次请求)</td>
86
- </tr>
87
- <tr>
88
- <td><strong>stepIndex</strong></td>
89
- <td>每次循环(内部步骤)</td>
90
- </tr>
91
- </tbody>
92
- </table>
93
- <pre data-role="codeBlock" data-info="" class="language-text"><code>Session: sess_001 (用户整个对话)
94
-
95
- └── Execution: exec_001 (用户第一次请求)
96
-
97
- ├── Step 1 (stepIndex=1)
98
- ├── Step 2 (stepIndex=2)
99
- └── Step 3 (stepIndex=3)
100
-
101
- └── 返回结果
102
- </code></pre><hr>
103
- <h2 id="四-实时存储架构">四、实时存储架构 </h2>
104
- <pre data-role="codeBlock" data-info="" class="language-text"><code>┌─────────────────────────────────────────────────────────────────┐
105
- │ 实时存储架构 │
106
- ├─────────────────────────────────────────────────────────────────┤
107
- │ │
108
- │ ┌───────────────────────────────────────────────────────────┐ │
109
- │ │ 回调驱动 │ │
110
- │ │ │ │
111
- │ │ onMessage: 每条消息产生时触发 │ │
112
- │ │ - Redis 实时写入 (&lt; 1ms) │ │
113
- │ │ - Kafka 异步持久化 │ │
114
- │ │ - SSE 推送客户端 │ │
115
- │ │ │ │
116
- │ │ onCheckpoint: 每个 Step 完成时触发 │ │
117
- │ │ - 保存执行位置 (stepIndex + lastMessageId) │ │
118
- │ │ - 用于故障恢复 │ │
119
- │ │ │ │
120
- │ └───────────────────────────────────────────────────────────┘ │
121
- │ │ │
122
- │ ▼ │
123
- │ ┌───────────────────────────────────────────────────────────┐ │
124
- │ │ 存储层 │ │
125
- │ │ │ │
126
- │ │ ┌─────────────┐ ┌─────────────┐ │ │
127
- │ │ │ Redis │ │ Kafka │ │ │
128
- │ │ │ (缓存/检查点)│ │ (持久化) │ │ │
129
- │ │ └─────────────┘ └─────────────┘ │ │
130
- │ │ │ │
131
- │ └───────────────────────────────────────────────────────────┘ │
132
- │ │
133
- └─────────────────────────────────────────────────────────────────┘
134
- </code></pre><hr>
135
- <h2 id="五-agent-回调机制设计">五、Agent 回调机制设计 </h2>
136
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token comment">// ============================================================</span>
137
- <span class="token comment">// 消息类型定义</span>
138
- <span class="token comment">// ============================================================</span>
139
-
140
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">Message</span> <span class="token punctuation">{</span>
141
- messageId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
142
- role<span class="token operator">:</span> <span class="token string">'system'</span> <span class="token operator">|</span> <span class="token string">'user'</span> <span class="token operator">|</span> <span class="token string">'assistant'</span> <span class="token operator">|</span> <span class="token string">'tool'</span><span class="token punctuation">;</span>
143
- content<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
144
- tool_call_id<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
145
- tool_calls<span class="token operator">?</span><span class="token operator">:</span> ToolCall<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
146
- timestamp<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
147
- metadata<span class="token operator">?</span><span class="token operator">:</span> Record<span class="token operator">&lt;</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">any</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
148
- <span class="token punctuation">}</span>
149
-
150
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">ToolCall</span> <span class="token punctuation">{</span>
151
- id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
152
- type<span class="token operator">:</span> <span class="token string">'function'</span><span class="token punctuation">;</span>
153
- name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
154
- arguments<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
155
- <span class="token punctuation">}</span>
156
-
157
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">Tool</span> <span class="token punctuation">{</span>
158
- name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
159
- description<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
160
- parameters<span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">;</span>
161
- <span class="token punctuation">}</span>
162
-
163
- <span class="token comment">// ============================================================</span>
164
- <span class="token comment">// Agent 输入输出接口</span>
165
- <span class="token comment">// ============================================================</span>
166
-
167
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">AgentInput</span> <span class="token punctuation">{</span>
168
- executionId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">// 任务 ID</span>
169
- conversationId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">// 会话 ID</span>
170
- messages<span class="token operator">:</span> Message<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Context 消息列表</span>
171
- systemPrompt<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">// 系统提示</span>
172
- tools<span class="token operator">?</span><span class="token operator">:</span> Tool<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 可用工具</span>
173
- config<span class="token operator">?</span><span class="token operator">:</span> LLMConfig<span class="token punctuation">;</span> <span class="token comment">// LLM 配置</span>
174
- maxSteps<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// 最大步数</span>
175
- startStep<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// 起始步骤 (用于恢复)</span>
176
- <span class="token punctuation">}</span>
177
-
178
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">AgentOutput</span> <span class="token punctuation">{</span>
179
- messages<span class="token operator">:</span> Message<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 包含新增消息</span>
180
- finishReason<span class="token operator">:</span> <span class="token string">'stop'</span> <span class="token operator">|</span> <span class="token string">'max_steps'</span> <span class="token operator">|</span> <span class="token string">'error'</span><span class="token punctuation">;</span>
181
- steps<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// 执行的步数</span>
182
- <span class="token punctuation">}</span>
183
-
184
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">LLMConfig</span> <span class="token punctuation">{</span>
185
- model<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
186
- temperature<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
187
- maxTokens<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
188
- topP<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
189
- <span class="token punctuation">}</span>
190
-
191
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">LLMResponse</span> <span class="token punctuation">{</span>
192
- message<span class="token operator">:</span> Message<span class="token punctuation">;</span>
193
- toolCalls<span class="token operator">?</span><span class="token operator">:</span> ToolCall<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
194
- usage<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">{</span>
195
- prompt_tokens<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
196
- completion_tokens<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
197
- total_tokens<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
198
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
199
- finishReason<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
200
- <span class="token punctuation">}</span>
201
-
202
- <span class="token comment">// ============================================================</span>
203
- <span class="token comment">// 回调接口</span>
204
- <span class="token comment">// ============================================================</span>
205
-
206
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">AgentCallbacks</span> <span class="token punctuation">{</span>
207
- <span class="token comment">// 每产生一条新消息时回调 (实时存储)</span>
208
- <span class="token function-variable function">onMessage</span><span class="token operator">:</span> <span class="token punctuation">(</span>message<span class="token operator">:</span> Message<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-void">void</span> <span class="token operator">|</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
209
-
210
- <span class="token comment">// 每个 Step 完成时回调 (检查点)</span>
211
- <span class="token function-variable function">onCheckpoint</span><span class="token operator">:</span> <span class="token punctuation">(</span>checkpoint<span class="token operator">:</span> ExecutionCheckpoint<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-void">void</span> <span class="token operator">|</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
212
-
213
- <span class="token comment">// 进度更新回调</span>
214
- onProgress<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">(</span>progress<span class="token operator">:</span> ExecutionProgress<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-void">void</span> <span class="token operator">|</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
215
-
216
- <span class="token comment">// 错误回调</span>
217
- onError<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">(</span>error<span class="token operator">:</span> Error<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-void">void</span> <span class="token operator">|</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
218
- <span class="token punctuation">}</span>
219
-
220
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">ExecutionCheckpoint</span> <span class="token punctuation">{</span>
221
- executionId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
222
- stepIndex<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// 当前步骤</span>
223
- lastMessageId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">// 最后一条消息 ID (用于恢复)</span>
224
- lastMessageTime<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// 时间戳</span>
225
- canResume<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span> <span class="token comment">// 是否可恢复</span>
226
- <span class="token punctuation">}</span>
227
-
228
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">ExecutionProgress</span> <span class="token punctuation">{</span>
229
- executionId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
230
- stepIndex<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
231
- currentAction<span class="token operator">:</span> <span class="token string">'llm'</span> <span class="token operator">|</span> <span class="token string">'tool'</span> <span class="token operator">|</span> <span class="token string">'waiting'</span><span class="token punctuation">;</span>
232
- messageCount<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
233
- <span class="token punctuation">}</span>
234
-
235
- <span class="token comment">// ============================================================</span>
236
- <span class="token comment">// LLM Provider 接口</span>
237
- <span class="token comment">// ============================================================</span>
238
-
239
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">LLMProvider</span> <span class="token punctuation">{</span>
240
- <span class="token comment">// 生成响应 (非流式)</span>
241
- <span class="token function">generate</span><span class="token punctuation">(</span>messages<span class="token operator">:</span> Message<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> config<span class="token operator">?</span><span class="token operator">:</span> LLMConfig<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>LLMResponse<span class="token operator">&gt;</span><span class="token punctuation">;</span>
242
-
243
- <span class="token comment">// 生成响应 (流式)</span>
244
- <span class="token function">generateStream</span><span class="token punctuation">(</span>
245
- messages<span class="token operator">:</span> Message<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
246
- config<span class="token operator">?</span><span class="token operator">:</span> LLMConfig
247
- <span class="token punctuation">)</span><span class="token operator">:</span> AsyncGenerator<span class="token operator">&lt;</span>Chunk<span class="token operator">&gt;</span><span class="token punctuation">;</span>
248
- <span class="token punctuation">}</span>
249
-
250
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">Chunk</span> <span class="token punctuation">{</span>
251
- id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
252
- choices<span class="token operator">:</span> <span class="token builtin">Array</span><span class="token operator">&lt;</span><span class="token punctuation">{</span>
253
- index<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
254
- delta<span class="token operator">:</span> <span class="token punctuation">{</span>
255
- content<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
256
- tool_calls<span class="token operator">?</span><span class="token operator">:</span> ToolCall<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
257
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
258
- finish_reason<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
259
- <span class="token punctuation">}</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
260
- <span class="token punctuation">}</span>
261
-
262
- <span class="token comment">// ============================================================</span>
263
- <span class="token comment">// Tool Executor 接口</span>
264
- <span class="token comment">// ============================================================</span>
265
-
266
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">ToolExecutor</span> <span class="token punctuation">{</span>
267
- <span class="token function">execute</span><span class="token punctuation">(</span>toolCall<span class="token operator">:</span> ToolCall<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>Message<span class="token operator">&gt;</span><span class="token punctuation">;</span>
268
- <span class="token function">registerTool</span><span class="token punctuation">(</span>tool<span class="token operator">:</span> Tool<span class="token punctuation">,</span> handler<span class="token operator">:</span> <span class="token builtin">Function</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword keyword-void">void</span><span class="token punctuation">;</span>
269
- <span class="token punctuation">}</span>
270
-
271
- <span class="token comment">// ============================================================</span>
272
- <span class="token comment">// 无状态 Agent 完整实现</span>
273
- <span class="token comment">// ============================================================</span>
274
-
275
- <span class="token keyword keyword-class">class</span> <span class="token class-name">StatelessAgent</span> <span class="token punctuation">{</span>
276
- <span class="token keyword keyword-private">private</span> llmProvider<span class="token operator">:</span> LLMProvider<span class="token punctuation">;</span>
277
- <span class="token keyword keyword-private">private</span> toolExecutor<span class="token operator">:</span> ToolExecutor<span class="token punctuation">;</span>
278
-
279
- <span class="token function">constructor</span><span class="token punctuation">(</span>llmProvider<span class="token operator">:</span> LLMProvider<span class="token punctuation">,</span> toolExecutor<span class="token operator">:</span> ToolExecutor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
280
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>llmProvider <span class="token operator">=</span> llmProvider<span class="token punctuation">;</span>
281
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>toolExecutor <span class="token operator">=</span> toolExecutor<span class="token punctuation">;</span>
282
- <span class="token punctuation">}</span>
283
-
284
- <span class="token keyword keyword-async">async</span> <span class="token function">run</span><span class="token punctuation">(</span>input<span class="token operator">:</span> AgentInput<span class="token punctuation">,</span> callbacks<span class="token operator">?</span><span class="token operator">:</span> AgentCallbacks<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>AgentOutput<span class="token operator">&gt;</span> <span class="token punctuation">{</span>
285
- <span class="token keyword keyword-let">let</span> <span class="token punctuation">{</span>
286
- messages<span class="token punctuation">,</span>
287
- maxSteps <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">,</span>
288
- startStep <span class="token operator">=</span> <span class="token number">1</span>
289
- <span class="token punctuation">}</span> <span class="token operator">=</span> input<span class="token punctuation">;</span>
290
-
291
- <span class="token keyword keyword-let">let</span> stepIndex <span class="token operator">=</span> startStep <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
292
- <span class="token keyword keyword-let">let</span> finishReason<span class="token operator">:</span> <span class="token string">'stop'</span> <span class="token operator">|</span> <span class="token string">'max_steps'</span> <span class="token operator">|</span> <span class="token string">'error'</span> <span class="token operator">=</span> <span class="token string">'stop'</span><span class="token punctuation">;</span>
293
-
294
- <span class="token comment">// 主循环</span>
295
- <span class="token keyword keyword-while">while</span> <span class="token punctuation">(</span>stepIndex <span class="token operator">&lt;</span> maxSteps<span class="token punctuation">)</span> <span class="token punctuation">{</span>
296
- stepIndex<span class="token operator">++</span><span class="token punctuation">;</span>
297
-
298
- <span class="token keyword keyword-try">try</span> <span class="token punctuation">{</span>
299
- <span class="token comment">// 回调: 进度</span>
300
- callbacks<span class="token operator">?.</span>onProgress<span class="token operator">?.</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
301
- executionId<span class="token operator">:</span> input<span class="token punctuation">.</span>executionId<span class="token punctuation">,</span>
302
- stepIndex<span class="token punctuation">,</span>
303
- currentAction<span class="token operator">:</span> <span class="token string">'llm'</span><span class="token punctuation">,</span>
304
- messageCount<span class="token operator">:</span> messages<span class="token punctuation">.</span>length
305
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
306
-
307
- <span class="token comment">// 1. 调用 LLM</span>
308
- <span class="token keyword keyword-const">const</span> response <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>llmProvider<span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span>messages<span class="token punctuation">,</span> input<span class="token punctuation">.</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
309
-
310
- <span class="token comment">// 2. 添加助手消息</span>
311
- <span class="token keyword keyword-const">const</span> assistantMessage <span class="token operator">=</span> response<span class="token punctuation">.</span>message<span class="token punctuation">;</span>
312
- messages<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>assistantMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
313
-
314
- <span class="token comment">// 回调: 新消息 (实时存储)</span>
315
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">safeCallback</span><span class="token punctuation">(</span>callbacks<span class="token operator">?.</span>onMessage<span class="token punctuation">,</span> assistantMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
316
-
317
- <span class="token comment">// 3. 检查工具调用</span>
318
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>toolCalls <span class="token operator">&amp;&amp;</span> response<span class="token punctuation">.</span>toolCalls<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
319
- <span class="token comment">// 回调: 进度</span>
320
- callbacks<span class="token operator">?.</span>onProgress<span class="token operator">?.</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
321
- executionId<span class="token operator">:</span> input<span class="token punctuation">.</span>executionId<span class="token punctuation">,</span>
322
- stepIndex<span class="token punctuation">,</span>
323
- currentAction<span class="token operator">:</span> <span class="token string">'tool'</span><span class="token punctuation">,</span>
324
- messageCount<span class="token operator">:</span> messages<span class="token punctuation">.</span>length
325
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
326
-
327
- <span class="token comment">// 4. 执行工具调用</span>
328
- <span class="token keyword keyword-for">for</span> <span class="token punctuation">(</span><span class="token keyword keyword-const">const</span> toolCall <span class="token keyword keyword-of">of</span> response<span class="token punctuation">.</span>toolCalls<span class="token punctuation">)</span> <span class="token punctuation">{</span>
329
- <span class="token keyword keyword-const">const</span> toolResult <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>toolExecutor<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span>toolCall<span class="token punctuation">)</span><span class="token punctuation">;</span>
330
- messages<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>toolResult<span class="token punctuation">)</span><span class="token punctuation">;</span>
331
-
332
- <span class="token comment">// 回调: 工具结果 (实时存储)</span>
333
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">safeCallback</span><span class="token punctuation">(</span>callbacks<span class="token operator">?.</span>onMessage<span class="token punctuation">,</span> toolResult<span class="token punctuation">)</span><span class="token punctuation">;</span>
334
- <span class="token punctuation">}</span>
335
-
336
- <span class="token comment">// 回调: 检查点 (每个 Step 完成)</span>
337
- <span class="token keyword keyword-const">const</span> lastMessage <span class="token operator">=</span> messages<span class="token punctuation">[</span>messages<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
338
- <span class="token keyword keyword-const">const</span> checkpoint<span class="token operator">:</span> ExecutionCheckpoint <span class="token operator">=</span> <span class="token punctuation">{</span>
339
- executionId<span class="token operator">:</span> input<span class="token punctuation">.</span>executionId<span class="token punctuation">,</span>
340
- stepIndex<span class="token punctuation">,</span>
341
- lastMessageId<span class="token operator">:</span> lastMessage<span class="token operator">?.</span>messageId <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
342
- lastMessageTime<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
343
- canResume<span class="token operator">:</span> <span class="token boolean">true</span>
344
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
345
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">safeCallback</span><span class="token punctuation">(</span>callbacks<span class="token operator">?.</span>onCheckpoint<span class="token punctuation">,</span> checkpoint<span class="token punctuation">)</span><span class="token punctuation">;</span>
346
-
347
- <span class="token comment">// 继续下一轮</span>
348
- <span class="token keyword keyword-continue">continue</span><span class="token punctuation">;</span>
349
- <span class="token punctuation">}</span>
350
-
351
- <span class="token comment">// 5. 无工具调用,完成</span>
352
- finishReason <span class="token operator">=</span> <span class="token string">'stop'</span><span class="token punctuation">;</span>
353
- <span class="token keyword keyword-break">break</span><span class="token punctuation">;</span>
354
-
355
- <span class="token punctuation">}</span> <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
356
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Agent] Step </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>stepIndex<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> error:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
357
-
358
- <span class="token comment">// 回调: 错误</span>
359
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">safeCallback</span><span class="token punctuation">(</span>callbacks<span class="token operator">?.</span>onError<span class="token punctuation">,</span> error <span class="token keyword keyword-as">as</span> Error<span class="token punctuation">)</span><span class="token punctuation">;</span>
360
-
361
- <span class="token comment">// 检查是否是可恢复错误</span>
362
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">isRetryableError</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
363
- <span class="token comment">// 可以重试,继续循环</span>
364
- <span class="token keyword keyword-continue">continue</span><span class="token punctuation">;</span>
365
- <span class="token punctuation">}</span>
366
-
367
- finishReason <span class="token operator">=</span> <span class="token string">'error'</span><span class="token punctuation">;</span>
368
- <span class="token keyword keyword-break">break</span><span class="token punctuation">;</span>
369
- <span class="token punctuation">}</span>
370
- <span class="token punctuation">}</span>
371
-
372
- <span class="token comment">// 检查是否是达到最大步数</span>
373
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>stepIndex <span class="token operator">&gt;=</span> maxSteps<span class="token punctuation">)</span> <span class="token punctuation">{</span>
374
- finishReason <span class="token operator">=</span> <span class="token string">'max_steps'</span><span class="token punctuation">;</span>
375
- <span class="token punctuation">}</span>
376
-
377
- <span class="token keyword keyword-return">return</span> <span class="token punctuation">{</span>
378
- messages<span class="token punctuation">,</span>
379
- finishReason<span class="token punctuation">,</span>
380
- steps<span class="token operator">:</span> stepIndex <span class="token operator">-</span> startStep <span class="token operator">+</span> <span class="token number">1</span>
381
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
382
- <span class="token punctuation">}</span>
383
-
384
- <span class="token comment">// 安全执行回调 (防止回调抛出异常)</span>
385
- <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-async">async</span> <span class="token generic-function"><span class="token function">safeCallback</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>
386
- callback<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>arg<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-void">void</span> <span class="token operator">|</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token keyword keyword-undefined">undefined</span><span class="token punctuation">,</span>
387
- arg<span class="token operator">:</span> <span class="token constant">T</span>
388
- <span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
389
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>callback<span class="token punctuation">)</span> <span class="token keyword keyword-return">return</span><span class="token punctuation">;</span>
390
-
391
- <span class="token keyword keyword-try">try</span> <span class="token punctuation">{</span>
392
- <span class="token keyword keyword-await">await</span> <span class="token function">callback</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span><span class="token punctuation">;</span>
393
- <span class="token punctuation">}</span> <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
394
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'[Agent] Callback error:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
395
- <span class="token punctuation">}</span>
396
- <span class="token punctuation">}</span>
397
-
398
- <span class="token comment">// 判断是否可重试</span>
399
- <span class="token keyword keyword-private">private</span> <span class="token function">isRetryableError</span><span class="token punctuation">(</span>error<span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">boolean</span> <span class="token punctuation">{</span>
400
- <span class="token keyword keyword-const">const</span> retryableCodes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'RATE_LIMIT'</span><span class="token punctuation">,</span> <span class="token string">'TIMEOUT'</span><span class="token punctuation">,</span> <span class="token string">'NETWORK_ERROR'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
401
- <span class="token keyword keyword-return">return</span> error<span class="token operator">?.</span>code <span class="token operator">&amp;&amp;</span> retryableCodes<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>code<span class="token punctuation">)</span><span class="token punctuation">;</span>
402
- <span class="token punctuation">}</span>
403
-
404
- <span class="token comment">// ============================================================</span>
405
- <span class="token comment">// 流式版本: runStream</span>
406
- <span class="token comment">// 适用于需要实时显示每个 chunk 的场景</span>
407
- <span class="token comment">// ============================================================</span>
408
-
409
- async <span class="token operator">*</span><span class="token function">runStream</span><span class="token punctuation">(</span>
410
- input<span class="token operator">:</span> AgentInput<span class="token punctuation">,</span>
411
- callbacks<span class="token operator">?</span><span class="token operator">:</span> AgentCallbacks
412
- <span class="token punctuation">)</span><span class="token operator">:</span> AsyncGenerator<span class="token operator">&lt;</span>StreamEvent<span class="token punctuation">,</span> <span class="token builtin">any</span><span class="token punctuation">,</span> <span class="token builtin">unknown</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
413
- <span class="token keyword keyword-let">let</span> <span class="token punctuation">{</span>
414
- messages<span class="token punctuation">,</span>
415
- maxSteps <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">,</span>
416
- startStep <span class="token operator">=</span> <span class="token number">1</span>
417
- <span class="token punctuation">}</span> <span class="token operator">=</span> input<span class="token punctuation">;</span>
418
-
419
- <span class="token keyword keyword-let">let</span> stepIndex <span class="token operator">=</span> startStep <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
420
-
421
- <span class="token keyword keyword-while">while</span> <span class="token punctuation">(</span>stepIndex <span class="token operator">&lt;</span> maxSteps<span class="token punctuation">)</span> <span class="token punctuation">{</span>
422
- stepIndex<span class="token operator">++</span><span class="token punctuation">;</span>
423
-
424
- <span class="token keyword keyword-try">try</span> <span class="token punctuation">{</span>
425
- <span class="token comment">// 回调: 进度</span>
426
- <span class="token keyword keyword-yield">yield</span> <span class="token punctuation">{</span>
427
- type<span class="token operator">:</span> <span class="token string">'progress'</span><span class="token punctuation">,</span>
428
- data<span class="token operator">:</span> <span class="token punctuation">{</span>
429
- executionId<span class="token operator">:</span> input<span class="token punctuation">.</span>executionId<span class="token punctuation">,</span>
430
- stepIndex<span class="token punctuation">,</span>
431
- currentAction<span class="token operator">:</span> <span class="token string">'llm'</span><span class="token punctuation">,</span>
432
- messageCount<span class="token operator">:</span> messages<span class="token punctuation">.</span>length
433
- <span class="token punctuation">}</span>
434
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
435
-
436
- <span class="token comment">// 1. 流式调用 LLM</span>
437
- <span class="token keyword keyword-const">const</span> stream <span class="token operator">=</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>llmProvider<span class="token punctuation">.</span><span class="token function">generateStream</span><span class="token punctuation">(</span>messages<span class="token punctuation">,</span> input<span class="token punctuation">.</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
438
-
439
- <span class="token comment">// 构建助手消息</span>
440
- <span class="token keyword keyword-const">const</span> assistantMessage<span class="token operator">:</span> Message <span class="token operator">=</span> <span class="token punctuation">{</span>
441
- messageId<span class="token operator">:</span> <span class="token function">generateId</span><span class="token punctuation">(</span><span class="token string">'msg_'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
442
- role<span class="token operator">:</span> <span class="token string">'assistant'</span><span class="token punctuation">,</span>
443
- content<span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
444
- timestamp<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
445
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
446
-
447
- <span class="token keyword keyword-let">let</span> toolCalls<span class="token operator">:</span> ToolCall<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
448
-
449
- <span class="token comment">// 2. 处理流式响应</span>
450
- <span class="token keyword keyword-for">for</span> <span class="token keyword keyword-await">await</span> <span class="token punctuation">(</span><span class="token keyword keyword-const">const</span> chunk <span class="token keyword keyword-of">of</span> stream<span class="token punctuation">)</span> <span class="token punctuation">{</span>
451
- <span class="token keyword keyword-const">const</span> delta <span class="token operator">=</span> chunk<span class="token punctuation">.</span>choices<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>delta<span class="token punctuation">;</span>
452
-
453
- <span class="token comment">// 更新 content</span>
454
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>delta<span class="token operator">?.</span>content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
455
- assistantMessage<span class="token punctuation">.</span>content <span class="token operator">+=</span> delta<span class="token punctuation">.</span>content<span class="token punctuation">;</span>
456
-
457
- <span class="token comment">// 回调: 内容更新</span>
458
- <span class="token keyword keyword-yield">yield</span> <span class="token punctuation">{</span>
459
- type<span class="token operator">:</span> <span class="token string">'chunk'</span><span class="token punctuation">,</span>
460
- data<span class="token operator">:</span> <span class="token punctuation">{</span>
461
- messageId<span class="token operator">:</span> assistantMessage<span class="token punctuation">.</span>messageId<span class="token punctuation">,</span>
462
- content<span class="token operator">:</span> delta<span class="token punctuation">.</span>content<span class="token punctuation">,</span>
463
- delta<span class="token operator">:</span> <span class="token boolean">true</span>
464
- <span class="token punctuation">}</span>
465
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
466
- <span class="token punctuation">}</span>
467
-
468
- <span class="token comment">// 更新 tool_calls</span>
469
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>delta<span class="token operator">?.</span>tool_calls<span class="token punctuation">)</span> <span class="token punctuation">{</span>
470
- toolCalls <span class="token operator">=</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">mergeToolCalls</span><span class="token punctuation">(</span>toolCalls<span class="token punctuation">,</span> delta<span class="token punctuation">.</span>tool_calls<span class="token punctuation">)</span><span class="token punctuation">;</span>
471
-
472
- <span class="token comment">// 回调: 工具调用</span>
473
- <span class="token keyword keyword-yield">yield</span> <span class="token punctuation">{</span>
474
- type<span class="token operator">:</span> <span class="token string">'tool_call'</span><span class="token punctuation">,</span>
475
- data<span class="token operator">:</span> <span class="token punctuation">{</span>
476
- messageId<span class="token operator">:</span> assistantMessage<span class="token punctuation">.</span>messageId<span class="token punctuation">,</span>
477
- toolCalls
478
- <span class="token punctuation">}</span>
479
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
480
- <span class="token punctuation">}</span>
481
-
482
- <span class="token comment">// 检查完成</span>
483
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>chunk<span class="token punctuation">.</span>choices<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>finish_reason<span class="token punctuation">)</span> <span class="token punctuation">{</span>
484
- <span class="token keyword keyword-break">break</span><span class="token punctuation">;</span>
485
- <span class="token punctuation">}</span>
486
- <span class="token punctuation">}</span>
487
-
488
- <span class="token comment">// 3. 完成消息构建</span>
489
- assistantMessage<span class="token punctuation">.</span>tool_calls <span class="token operator">=</span> toolCalls<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">?</span> toolCalls <span class="token operator">:</span> <span class="token keyword keyword-undefined">undefined</span><span class="token punctuation">;</span>
490
- messages<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>assistantMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
491
-
492
- <span class="token comment">// 回调: 新消息</span>
493
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">safeCallback</span><span class="token punctuation">(</span>callbacks<span class="token operator">?.</span>onMessage<span class="token punctuation">,</span> assistantMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
494
-
495
- <span class="token comment">// 4. 处理工具调用</span>
496
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>toolCalls<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
497
- <span class="token keyword keyword-for">for</span> <span class="token punctuation">(</span><span class="token keyword keyword-const">const</span> toolCall <span class="token keyword keyword-of">of</span> toolCalls<span class="token punctuation">)</span> <span class="token punctuation">{</span>
498
- <span class="token keyword keyword-yield">yield</span> <span class="token punctuation">{</span>
499
- type<span class="token operator">:</span> <span class="token string">'progress'</span><span class="token punctuation">,</span>
500
- data<span class="token operator">:</span> <span class="token punctuation">{</span>
501
- stepIndex<span class="token punctuation">,</span>
502
- currentAction<span class="token operator">:</span> <span class="token string">'tool'</span><span class="token punctuation">,</span>
503
- messageCount<span class="token operator">:</span> messages<span class="token punctuation">.</span>length
504
- <span class="token punctuation">}</span>
505
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
506
-
507
- <span class="token comment">// 执行工具</span>
508
- <span class="token keyword keyword-const">const</span> toolResult <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>toolExecutor<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span>toolCall<span class="token punctuation">)</span><span class="token punctuation">;</span>
509
- messages<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>toolResult<span class="token punctuation">)</span><span class="token punctuation">;</span>
510
-
511
- <span class="token comment">// 回调: 工具结果</span>
512
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">safeCallback</span><span class="token punctuation">(</span>callbacks<span class="token operator">?.</span>onMessage<span class="token punctuation">,</span> toolResult<span class="token punctuation">)</span><span class="token punctuation">;</span>
513
-
514
- <span class="token comment">// 推送工具结果</span>
515
- <span class="token keyword keyword-yield">yield</span> <span class="token punctuation">{</span>
516
- type<span class="token operator">:</span> <span class="token string">'tool_result'</span><span class="token punctuation">,</span>
517
- data<span class="token operator">:</span> toolResult
518
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
519
- <span class="token punctuation">}</span>
520
-
521
- <span class="token comment">// 回调: 检查点</span>
522
- <span class="token keyword keyword-const">const</span> lastMessage <span class="token operator">=</span> messages<span class="token punctuation">[</span>messages<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
523
- <span class="token keyword keyword-const">const</span> checkpoint<span class="token operator">:</span> ExecutionCheckpoint <span class="token operator">=</span> <span class="token punctuation">{</span>
524
- executionId<span class="token operator">:</span> input<span class="token punctuation">.</span>executionId<span class="token punctuation">,</span>
525
- stepIndex<span class="token punctuation">,</span>
526
- lastMessageId<span class="token operator">:</span> lastMessage<span class="token operator">?.</span>messageId <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
527
- lastMessageTime<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
528
- canResume<span class="token operator">:</span> <span class="token boolean">true</span>
529
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
530
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">safeCallback</span><span class="token punctuation">(</span>callbacks<span class="token operator">?.</span>onCheckpoint<span class="token punctuation">,</span> checkpoint<span class="token punctuation">)</span><span class="token punctuation">;</span>
531
-
532
- <span class="token comment">// 推送检查点</span>
533
- <span class="token keyword keyword-yield">yield</span> <span class="token punctuation">{</span>
534
- type<span class="token operator">:</span> <span class="token string">'checkpoint'</span><span class="token punctuation">,</span>
535
- data<span class="token operator">:</span> checkpoint
536
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
537
-
538
- <span class="token keyword keyword-continue">continue</span><span class="token punctuation">;</span>
539
- <span class="token punctuation">}</span>
540
-
541
- <span class="token comment">// 5. 无工具调用,完成</span>
542
- <span class="token keyword keyword-yield">yield</span> <span class="token punctuation">{</span>
543
- type<span class="token operator">:</span> <span class="token string">'done'</span><span class="token punctuation">,</span>
544
- data<span class="token operator">:</span> <span class="token punctuation">{</span>
545
- finishReason<span class="token operator">:</span> <span class="token string">'stop'</span><span class="token punctuation">,</span>
546
- steps<span class="token operator">:</span> stepIndex <span class="token operator">-</span> startStep <span class="token operator">+</span> <span class="token number">1</span>
547
- <span class="token punctuation">}</span>
548
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
549
-
550
- <span class="token keyword keyword-break">break</span><span class="token punctuation">;</span>
551
-
552
- <span class="token punctuation">}</span> <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
553
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Agent] Step </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>stepIndex<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> error:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
554
-
555
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">safeCallback</span><span class="token punctuation">(</span>callbacks<span class="token operator">?.</span>onError<span class="token punctuation">,</span> error <span class="token keyword keyword-as">as</span> Error<span class="token punctuation">)</span><span class="token punctuation">;</span>
556
-
557
- <span class="token keyword keyword-yield">yield</span> <span class="token punctuation">{</span>
558
- type<span class="token operator">:</span> <span class="token string">'error'</span><span class="token punctuation">,</span>
559
- data<span class="token operator">:</span> <span class="token punctuation">{</span> message<span class="token operator">:</span> <span class="token punctuation">(</span>error <span class="token keyword keyword-as">as</span> Error<span class="token punctuation">)</span><span class="token punctuation">.</span>message <span class="token punctuation">}</span>
560
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
561
-
562
- <span class="token keyword keyword-break">break</span><span class="token punctuation">;</span>
563
- <span class="token punctuation">}</span>
564
- <span class="token punctuation">}</span>
565
- <span class="token punctuation">}</span>
566
-
567
- <span class="token comment">// 合并工具调用</span>
568
- <span class="token keyword keyword-private">private</span> <span class="token function">mergeToolCalls</span><span class="token punctuation">(</span>
569
- existing<span class="token operator">:</span> ToolCall<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
570
- newCalls<span class="token operator">:</span> ToolCall<span class="token punctuation">[</span><span class="token punctuation">]</span>
571
- <span class="token punctuation">)</span><span class="token operator">:</span> ToolCall<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
572
- <span class="token keyword keyword-for">for</span> <span class="token punctuation">(</span><span class="token keyword keyword-const">const</span> newCall <span class="token keyword keyword-of">of</span> newCalls<span class="token punctuation">)</span> <span class="token punctuation">{</span>
573
- <span class="token keyword keyword-const">const</span> existingCall <span class="token operator">=</span> existing<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span>c <span class="token operator">=&gt;</span> c<span class="token punctuation">.</span>id <span class="token operator">===</span> newCall<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
574
-
575
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>existingCall<span class="token punctuation">)</span> <span class="token punctuation">{</span>
576
- existingCall<span class="token punctuation">.</span>arguments <span class="token operator">+=</span> newCall<span class="token punctuation">.</span>arguments<span class="token punctuation">;</span>
577
- <span class="token punctuation">}</span> <span class="token keyword keyword-else">else</span> <span class="token punctuation">{</span>
578
- existing<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span>newCall <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
579
- <span class="token punctuation">}</span>
580
- <span class="token punctuation">}</span>
581
- <span class="token keyword keyword-return">return</span> existing<span class="token punctuation">;</span>
582
- <span class="token punctuation">}</span>
583
- <span class="token punctuation">}</span>
584
-
585
- <span class="token keyword keyword-interface">interface</span> <span class="token class-name">StreamEvent</span> <span class="token punctuation">{</span>
586
- type<span class="token operator">:</span> <span class="token string">'chunk'</span> <span class="token operator">|</span> <span class="token string">'tool_call'</span> <span class="token operator">|</span> <span class="token string">'tool_result'</span> <span class="token operator">|</span> <span class="token string">'progress'</span> <span class="token operator">|</span> <span class="token string">'checkpoint'</span> <span class="token operator">|</span> <span class="token string">'done'</span> <span class="token operator">|</span> <span class="token string">'error'</span><span class="token punctuation">;</span>
587
- data<span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">;</span>
588
- <span class="token punctuation">}</span>
589
- </code></pre><h2 id="六-实时存储实现">六、实时存储实现 </h2>
590
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token keyword keyword-class">class</span> <span class="token class-name">RealTimeStorage</span> <span class="token punctuation">{</span>
591
- <span class="token comment">// 保存消息到 Redis (毫秒级延迟)</span>
592
- <span class="token keyword keyword-async">async</span> <span class="token function">saveMessage</span><span class="token punctuation">(</span>conversationId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> message<span class="token operator">:</span> Message<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
593
- <span class="token keyword keyword-const">const</span> key <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">conversation:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conversationId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:messages</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
594
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">rpush</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
595
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">expire</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token number">1800</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 30 分钟过期</span>
596
- <span class="token punctuation">}</span>
597
-
598
- <span class="token comment">// 保存检查点 (只存位置,不重复存储消息)</span>
599
- <span class="token keyword keyword-async">async</span> <span class="token function">saveCheckpoint</span><span class="token punctuation">(</span>checkpoint<span class="token operator">:</span> ExecutionCheckpoint<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
600
- <span class="token keyword keyword-const">const</span> key <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">execution:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>checkpoint<span class="token punctuation">.</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:checkpoint</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
601
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">hset</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token punctuation">{</span>
602
- stepIndex<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>stepIndex<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
603
- lastMessageId<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>lastMessageId<span class="token punctuation">,</span>
604
- lastMessageTime<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>lastMessageTime<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
605
- canResume<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>canResume <span class="token operator">?</span> <span class="token string">'1'</span> <span class="token operator">:</span> <span class="token string">'0'</span>
606
- <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token constant">EX</span><span class="token operator">:</span> <span class="token number">86400</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
607
- <span class="token punctuation">}</span>
608
-
609
- <span class="token comment">// 获取检查点</span>
610
- <span class="token keyword keyword-async">async</span> <span class="token function">getLatestCheckpoint</span><span class="token punctuation">(</span>executionId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>ExecutionCheckpoint <span class="token operator">|</span> <span class="token keyword keyword-null">null</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
611
- <span class="token keyword keyword-const">const</span> key <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">execution:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:checkpoint</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
612
- <span class="token keyword keyword-const">const</span> data <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">hgetall</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
613
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>data<span class="token punctuation">)</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">;</span>
614
-
615
- <span class="token keyword keyword-return">return</span> <span class="token punctuation">{</span>
616
- executionId<span class="token punctuation">,</span>
617
- stepIndex<span class="token operator">:</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>stepIndex<span class="token punctuation">)</span><span class="token punctuation">,</span>
618
- lastMessageId<span class="token operator">:</span> data<span class="token punctuation">.</span>lastMessageId<span class="token punctuation">,</span>
619
- lastMessageTime<span class="token operator">:</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>lastMessageTime<span class="token punctuation">)</span><span class="token punctuation">,</span>
620
- canResume<span class="token operator">:</span> data<span class="token punctuation">.</span>canResume <span class="token operator">===</span> <span class="token string">'1'</span>
621
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
622
- <span class="token punctuation">}</span>
623
-
624
- <span class="token comment">// 获取检查点后的消息 (用于恢复)</span>
625
- <span class="token keyword keyword-async">async</span> <span class="token function">getMessagesAfterCheckpoint</span><span class="token punctuation">(</span>
626
- conversationId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span>
627
- lastMessageId<span class="token operator">:</span> <span class="token builtin">string</span>
628
- <span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>Message<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
629
- <span class="token keyword keyword-const">const</span> allMessages <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">lrange</span><span class="token punctuation">(</span>
630
- <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">conversation:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conversationId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:messages</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span>
631
- <span class="token punctuation">)</span><span class="token punctuation">;</span>
632
-
633
- <span class="token keyword keyword-const">const</span> messages<span class="token operator">:</span> Message<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
634
- <span class="token keyword keyword-let">let</span> found <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
635
-
636
- <span class="token keyword keyword-for">for</span> <span class="token punctuation">(</span><span class="token keyword keyword-const">const</span> msgStr <span class="token keyword keyword-of">of</span> allMessages<span class="token punctuation">)</span> <span class="token punctuation">{</span>
637
- <span class="token keyword keyword-const">const</span> msg <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>msgStr<span class="token punctuation">)</span><span class="token punctuation">;</span>
638
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>msg<span class="token punctuation">.</span>messageId <span class="token operator">===</span> lastMessageId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
639
- found <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
640
- <span class="token keyword keyword-continue">continue</span><span class="token punctuation">;</span>
641
- <span class="token punctuation">}</span>
642
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>found<span class="token punctuation">)</span> <span class="token punctuation">{</span>
643
- messages<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>msg<span class="token punctuation">)</span><span class="token punctuation">;</span>
644
- <span class="token punctuation">}</span>
645
- <span class="token punctuation">}</span>
646
-
647
- <span class="token keyword keyword-return">return</span> messages<span class="token punctuation">;</span>
648
- <span class="token punctuation">}</span>
649
- <span class="token punctuation">}</span>
650
- </code></pre><hr>
651
- <h2 id="七-后台执行机制">七、后台执行机制 </h2>
652
- <h3 id="问题">问题 </h3>
653
- <pre data-role="codeBlock" data-info="" class="language-text"><code>传统模式 (阻塞):
654
- 用户 ──▶ API ──▶ Agent 执行 ──▶ 等待完成 ──▶ 返回结果
655
-
656
- └─ 页面关闭 = 请求中断 ❌
657
-
658
- 后台模式 (非阻塞):
659
- 用户 ──▶ API ──▶ 创建 Task ──▶ 返回 Task ID ──▶ 立即返回 ✓
660
-
661
-
662
- ┌─────────┐
663
- │ Task │ 后台执行
664
- │ Queue │◀── 页面关闭不受影响
665
- └─────────┘
666
-
667
-
668
- 存储结果 ── 用户可查询
669
- </code></pre><h3 id="执行流程">执行流程 </h3>
670
- <pre data-role="codeBlock" data-info="" class="language-text"><code>1. 用户发起请求
671
- POST /api/v1/executions
672
- { conversationId, message: "帮我写排序算法" }
673
-
674
- Response: { executionId: "exec_001", status: "CREATED" } ← 立即返回!
675
-
676
- 2. 创建任务并放入队列
677
- TaskQueue.push({ executionId, message, createdAt })
678
- 更新状态: CREATED → QUEUED
679
-
680
- 3. Worker 消费任务
681
- - 更新状态: QUEUED → RUNNING
682
- - 执行 Agent
683
- - onMessage: 实时存储 + SSE 推送
684
- - onCheckpoint: 保存检查点
685
-
686
- 4. 执行完成
687
- 更新状态: RUNNING → COMPLETED
688
- 保存最终结果
689
-
690
- 5. 用户查询结果
691
- GET /api/v1/executions/exec_001
692
- { status: "COMPLETED", messages: [...] }
693
- </code></pre><h3 id="api-设计">API 设计 </h3>
694
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token comment">// 创建执行 (立即返回)</span>
695
- <span class="token constant">POST</span> <span class="token operator">/</span>api<span class="token operator">/</span>v1<span class="token operator">/</span>executions
696
- Body<span class="token operator">:</span> <span class="token punctuation">{</span> conversationId<span class="token punctuation">,</span> message <span class="token punctuation">}</span>
697
- Response<span class="token operator">:</span> <span class="token punctuation">{</span> executionId<span class="token punctuation">,</span> status<span class="token operator">:</span> <span class="token string">'CREATED'</span> <span class="token punctuation">}</span>
698
-
699
- <span class="token comment">// 查询执行状态和结果</span>
700
- <span class="token constant">GET</span> <span class="token operator">/</span>api<span class="token operator">/</span>v1<span class="token operator">/</span>executions<span class="token operator">/</span><span class="token punctuation">{</span>executionId<span class="token punctuation">}</span>
701
- Response<span class="token operator">:</span> <span class="token punctuation">{</span>
702
- executionId<span class="token punctuation">,</span> conversationId<span class="token punctuation">,</span>
703
- status<span class="token operator">:</span> <span class="token string">'CREATED'</span> <span class="token operator">|</span> <span class="token string">'QUEUED'</span> <span class="token operator">|</span> <span class="token string">'RUNNING'</span> <span class="token operator">|</span> <span class="token string">'COMPLETED'</span> <span class="token operator">|</span> <span class="token string">'FAILED'</span><span class="token punctuation">,</span>
704
- stepIndex<span class="token operator">?</span><span class="token punctuation">,</span> result<span class="token operator">?</span><span class="token punctuation">,</span> messages<span class="token operator">?</span><span class="token punctuation">,</span> error<span class="token operator">?</span>
705
- <span class="token punctuation">}</span>
706
-
707
- <span class="token comment">// 实时消息流 (SSE)</span>
708
- <span class="token constant">GET</span> <span class="token operator">/</span>api<span class="token operator">/</span>v1<span class="token operator">/</span>executions<span class="token operator">/</span><span class="token punctuation">{</span>executionId<span class="token punctuation">}</span><span class="token operator">/</span>stream
709
-
710
- <span class="token comment">// 恢复执行 (崩溃后)</span>
711
- <span class="token constant">POST</span> <span class="token operator">/</span>api<span class="token operator">/</span>v1<span class="token operator">/</span>executions<span class="token operator">/</span><span class="token punctuation">{</span>executionId<span class="token punctuation">}</span><span class="token operator">/</span>resume
712
- </code></pre><h3 id="worker-实现">Worker 实现 </h3>
713
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token comment">// ============================================================</span>
714
- <span class="token comment">// 1. 依赖注入配置</span>
715
- <span class="token comment">// ============================================================</span>
716
-
717
- <span class="token comment">// 创建依赖容器</span>
718
- <span class="token keyword keyword-class">class</span> <span class="token class-name">DIContainer</span> <span class="token punctuation">{</span>
719
- <span class="token operator">:</span> <span class="token keyword keyword-private">private</span> services Map<span class="token operator">&lt;</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">any</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
720
-
721
- <span class="token comment">// 注册服务</span>
722
- <span class="token generic-function"><span class="token function">register</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> instance<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword keyword-void">void</span> <span class="token punctuation">{</span>
723
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>services<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> instance<span class="token punctuation">)</span><span class="token punctuation">;</span>
724
- <span class="token punctuation">}</span>
725
-
726
- <span class="token comment">// 获取服务</span>
727
- <span class="token generic-function"><span class="token function">get</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token constant">T</span> <span class="token punctuation">{</span>
728
- <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>services<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
729
- <span class="token punctuation">}</span>
730
- <span class="token punctuation">}</span>
731
-
732
- <span class="token comment">// 初始化容器</span>
733
- <span class="token keyword keyword-const">const</span> container <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">DIContainer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
734
-
735
- <span class="token comment">// 注册 Redis 客户端</span>
736
- <span class="token keyword keyword-const">const</span> redis <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">Redis</span><span class="token punctuation">(</span><span class="token punctuation">{</span> host<span class="token operator">:</span> <span class="token string">'localhost'</span><span class="token punctuation">,</span> port<span class="token operator">:</span> <span class="token number">6379</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
737
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'redis'</span><span class="token punctuation">,</span> redis<span class="token punctuation">)</span><span class="token punctuation">;</span>
738
-
739
- <span class="token comment">// 注册消息队列</span>
740
- <span class="token keyword keyword-const">const</span> taskQueue <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">TaskQueue</span><span class="token punctuation">(</span>redis<span class="token punctuation">)</span><span class="token punctuation">;</span>
741
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'taskQueue'</span><span class="token punctuation">,</span> taskQueue<span class="token punctuation">)</span><span class="token punctuation">;</span>
742
-
743
- <span class="token comment">// 注册存储服务</span>
744
- <span class="token keyword keyword-const">const</span> messageStorage <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">MessageStorage</span><span class="token punctuation">(</span>redis<span class="token punctuation">,</span> kafka<span class="token punctuation">)</span><span class="token punctuation">;</span>
745
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'messageStorage'</span><span class="token punctuation">,</span> messageStorage<span class="token punctuation">)</span><span class="token punctuation">;</span>
746
-
747
- <span class="token keyword keyword-const">const</span> checkpointService <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">CheckpointService</span><span class="token punctuation">(</span>redis<span class="token punctuation">)</span><span class="token punctuation">;</span>
748
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'checkpointService'</span><span class="token punctuation">,</span> checkpointService<span class="token punctuation">)</span><span class="token punctuation">;</span>
749
-
750
- <span class="token keyword keyword-const">const</span> executionService <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">ExecutionService</span><span class="token punctuation">(</span>redis<span class="token punctuation">)</span><span class="token punctuation">;</span>
751
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'executionService'</span><span class="token punctuation">,</span> executionService<span class="token punctuation">)</span><span class="token punctuation">;</span>
752
-
753
- <span class="token comment">// 注册 Context 服务</span>
754
- <span class="token keyword keyword-const">const</span> contextService <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">ContextService</span><span class="token punctuation">(</span>redis<span class="token punctuation">,</span> clickhouse<span class="token punctuation">)</span><span class="token punctuation">;</span>
755
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'contextService'</span><span class="token punctuation">,</span> contextService<span class="token punctuation">)</span><span class="token punctuation">;</span>
756
-
757
- <span class="token comment">// 注册 SSE 发布器</span>
758
- <span class="token keyword keyword-const">const</span> ssePublisher <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">SSEPublisher</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
759
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'ssePublisher'</span><span class="token punctuation">,</span> ssePublisher<span class="token punctuation">)</span><span class="token punctuation">;</span>
760
-
761
- <span class="token comment">// 注册 LLM 提供商</span>
762
- <span class="token keyword keyword-const">const</span> llmProvider <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">OpenAIProvider</span><span class="token punctuation">(</span><span class="token punctuation">{</span> apiKey<span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">OPENAI_KEY</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
763
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'llmProvider'</span><span class="token punctuation">,</span> llmProvider<span class="token punctuation">)</span><span class="token punctuation">;</span>
764
-
765
- <span class="token comment">// 注册工具执行器</span>
766
- <span class="token keyword keyword-const">const</span> toolExecutor <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">ToolExecutor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
767
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'toolExecutor'</span><span class="token punctuation">,</span> toolExecutor<span class="token punctuation">)</span><span class="token punctuation">;</span>
768
-
769
- <span class="token comment">// 创建无状态 Agent</span>
770
- <span class="token keyword keyword-const">const</span> agent <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">StatelessAgent</span><span class="token punctuation">(</span>llmProvider<span class="token punctuation">,</span> toolExecutor<span class="token punctuation">)</span><span class="token punctuation">;</span>
771
- container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">'agent'</span><span class="token punctuation">,</span> agent<span class="token punctuation">)</span><span class="token punctuation">;</span>
772
-
773
- <span class="token comment">// ============================================================</span>
774
- <span class="token comment">// 2. ExecutionWorker 完整实现</span>
775
- <span class="token comment">// ============================================================</span>
776
-
777
- <span class="token keyword keyword-class">class</span> <span class="token class-name">ExecutionWorker</span> <span class="token punctuation">{</span>
778
- <span class="token keyword keyword-private">private</span> queue<span class="token operator">:</span> TaskQueue<span class="token punctuation">;</span>
779
- <span class="token keyword keyword-private">private</span> agent<span class="token operator">:</span> StatelessAgent<span class="token punctuation">;</span>
780
- <span class="token keyword keyword-private">private</span> executionService<span class="token operator">:</span> ExecutionService<span class="token punctuation">;</span>
781
- <span class="token keyword keyword-private">private</span> messageStorage<span class="token operator">:</span> MessageStorage<span class="token punctuation">;</span>
782
- <span class="token keyword keyword-private">private</span> checkpointService<span class="token operator">:</span> CheckpointService<span class="token punctuation">;</span>
783
- <span class="token keyword keyword-private">private</span> contextService<span class="token operator">:</span> ContextService<span class="token punctuation">;</span>
784
- <span class="token keyword keyword-private">private</span> ssePublisher<span class="token operator">:</span> SSEPublisher<span class="token punctuation">;</span>
785
-
786
- <span class="token comment">// 构造函数注入依赖</span>
787
- <span class="token function">constructor</span><span class="token punctuation">(</span>
788
- queue<span class="token operator">:</span> TaskQueue<span class="token punctuation">,</span>
789
- agent<span class="token operator">:</span> StatelessAgent<span class="token punctuation">,</span>
790
- executionService<span class="token operator">:</span> ExecutionService<span class="token punctuation">,</span>
791
- messageStorage<span class="token operator">:</span> MessageStorage<span class="token punctuation">,</span>
792
- checkpointService<span class="token operator">:</span> CheckpointService<span class="token punctuation">,</span>
793
- contextService<span class="token operator">:</span> ContextService<span class="token punctuation">,</span>
794
- ssePublisher<span class="token operator">:</span> SSEPublisher
795
- <span class="token punctuation">)</span> <span class="token punctuation">{</span>
796
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>queue <span class="token operator">=</span> queue<span class="token punctuation">;</span>
797
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>agent <span class="token operator">=</span> agent<span class="token punctuation">;</span>
798
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService <span class="token operator">=</span> executionService<span class="token punctuation">;</span>
799
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>messageStorage <span class="token operator">=</span> messageStorage<span class="token punctuation">;</span>
800
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>checkpointService <span class="token operator">=</span> checkpointService<span class="token punctuation">;</span>
801
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>contextService <span class="token operator">=</span> contextService<span class="token punctuation">;</span>
802
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>ssePublisher <span class="token operator">=</span> ssePublisher<span class="token punctuation">;</span>
803
- <span class="token punctuation">}</span>
804
-
805
- <span class="token comment">// 启动 Worker</span>
806
- <span class="token keyword keyword-async">async</span> <span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
807
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'[Worker] Starting...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
808
-
809
- <span class="token keyword keyword-while">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
810
- <span class="token keyword keyword-try">try</span> <span class="token punctuation">{</span>
811
- <span class="token comment">// 从队列获取任务 (阻塞等待)</span>
812
- <span class="token comment">// key: 队列名称, timeout: 超时时间(0=无限等待)</span>
813
- <span class="token keyword keyword-const">const</span> task <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">brpop</span><span class="token punctuation">(</span><span class="token string">'task_queue'</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
814
-
815
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>task<span class="token punctuation">)</span> <span class="token punctuation">{</span>
816
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Received task: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>task<span class="token punctuation">.</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
817
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">processTask</span><span class="token punctuation">(</span>task<span class="token punctuation">)</span><span class="token punctuation">;</span>
818
- <span class="token punctuation">}</span>
819
- <span class="token punctuation">}</span> <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
820
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'[Worker] Error:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
821
- <span class="token comment">// 短暂等待后继续</span>
822
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
823
- <span class="token punctuation">}</span>
824
- <span class="token punctuation">}</span>
825
- <span class="token punctuation">}</span>
826
-
827
- <span class="token comment">// 处理单个任务</span>
828
- <span class="token keyword keyword-async">async</span> <span class="token function">processTask</span><span class="token punctuation">(</span>task<span class="token operator">:</span> Task<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
829
- <span class="token keyword keyword-const">const</span> <span class="token punctuation">{</span> executionId<span class="token punctuation">,</span> conversationId<span class="token punctuation">,</span> message <span class="token punctuation">}</span> <span class="token operator">=</span> task<span class="token punctuation">;</span>
830
-
831
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Processing task: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
832
-
833
- <span class="token comment">// 1. 尝试获取锁 (防止重复执行)</span>
834
- <span class="token keyword keyword-const">const</span> lockAcquired <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService<span class="token punctuation">.</span><span class="token function">acquireLock</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token string">'worker-1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
835
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>lockAcquired<span class="token punctuation">)</span> <span class="token punctuation">{</span>
836
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Task </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is being processed by another worker</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
837
- <span class="token keyword keyword-return">return</span><span class="token punctuation">;</span>
838
- <span class="token punctuation">}</span>
839
-
840
- <span class="token keyword keyword-try">try</span> <span class="token punctuation">{</span>
841
- <span class="token comment">// 2. 更新状态为 RUNNING</span>
842
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService<span class="token punctuation">.</span><span class="token function">updateStatus</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token string">'RUNNING'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
843
-
844
- <span class="token comment">// 3. 检查是否有未完成的检查点</span>
845
- <span class="token keyword keyword-const">const</span> checkpoint <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>checkpointService<span class="token punctuation">.</span><span class="token function">getLatestCheckpoint</span><span class="token punctuation">(</span>executionId<span class="token punctuation">)</span><span class="token punctuation">;</span>
846
-
847
- <span class="token keyword keyword-let">let</span> messages<span class="token operator">:</span> Message<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
848
- <span class="token keyword keyword-let">let</span> startStep <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
849
-
850
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>checkpoint <span class="token operator">&amp;&amp;</span> checkpoint<span class="token punctuation">.</span>canResume<span class="token punctuation">)</span> <span class="token punctuation">{</span>
851
- <span class="token comment">// 4a. 恢复执行</span>
852
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Resuming from checkpoint: step </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>checkpoint<span class="token punctuation">.</span>stepIndex<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
853
-
854
- <span class="token comment">// 加载上下文</span>
855
- <span class="token keyword keyword-const">const</span> context <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>contextService<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>conversationId<span class="token punctuation">)</span><span class="token punctuation">;</span>
856
-
857
- <span class="token comment">// 获取检查点后的消息</span>
858
- <span class="token keyword keyword-const">const</span> newMessages <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>messageStorage<span class="token punctuation">.</span><span class="token function">getMessagesAfterCheckpoint</span><span class="token punctuation">(</span>
859
- conversationId<span class="token punctuation">,</span>
860
- checkpoint<span class="token punctuation">.</span>lastMessageId
861
- <span class="token punctuation">)</span><span class="token punctuation">;</span>
862
-
863
- messages <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>context<span class="token punctuation">.</span>messages<span class="token punctuation">,</span> <span class="token operator">...</span>newMessages<span class="token punctuation">]</span><span class="token punctuation">;</span>
864
- startStep <span class="token operator">=</span> checkpoint<span class="token punctuation">.</span>stepIndex <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
865
-
866
- <span class="token punctuation">}</span> <span class="token keyword keyword-else">else</span> <span class="token punctuation">{</span>
867
- <span class="token comment">// 4b. 全新执行</span>
868
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Starting new execution</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
869
-
870
- <span class="token comment">// 加载上下文</span>
871
- <span class="token keyword keyword-const">const</span> context <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>contextService<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>conversationId<span class="token punctuation">)</span><span class="token punctuation">;</span>
872
-
873
- <span class="token comment">// 添加用户消息</span>
874
- <span class="token keyword keyword-const">const</span> userMessage<span class="token operator">:</span> Message <span class="token operator">=</span> <span class="token punctuation">{</span>
875
- messageId<span class="token operator">:</span> <span class="token function">generateId</span><span class="token punctuation">(</span><span class="token string">'msg_'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
876
- role<span class="token operator">:</span> <span class="token string">'user'</span><span class="token punctuation">,</span>
877
- content<span class="token operator">:</span> message<span class="token punctuation">.</span>content<span class="token punctuation">,</span>
878
- timestamp<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
879
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
880
-
881
- messages <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>context<span class="token punctuation">.</span>messages<span class="token punctuation">,</span> userMessage<span class="token punctuation">]</span><span class="token punctuation">;</span>
882
-
883
- <span class="token comment">// 实时存储用户消息</span>
884
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>messageStorage<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>conversationId<span class="token punctuation">,</span> userMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
885
- <span class="token punctuation">}</span>
886
-
887
- <span class="token comment">// 5. 获取系统提示和工具配置</span>
888
- <span class="token keyword keyword-const">const</span> context <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>contextService<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>conversationId<span class="token punctuation">)</span><span class="token punctuation">;</span>
889
-
890
- <span class="token comment">// 6. 构造 Agent 输入</span>
891
- <span class="token keyword keyword-const">const</span> input<span class="token operator">:</span> AgentInput <span class="token operator">=</span> <span class="token punctuation">{</span>
892
- executionId<span class="token punctuation">,</span>
893
- conversationId<span class="token punctuation">,</span>
894
- messages<span class="token punctuation">,</span>
895
- systemPrompt<span class="token operator">:</span> context<span class="token punctuation">.</span>systemPrompt<span class="token punctuation">,</span>
896
- tools<span class="token operator">:</span> context<span class="token punctuation">.</span>tools<span class="token punctuation">,</span>
897
- startStep<span class="token punctuation">,</span> <span class="token comment">// 从指定步骤开始</span>
898
- callbacks<span class="token operator">:</span> <span class="token punctuation">{</span>
899
- <span class="token comment">// 实时消息回调</span>
900
- <span class="token function-variable function">onMessage</span><span class="token operator">:</span> <span class="token keyword keyword-async">async</span> <span class="token punctuation">(</span>msg<span class="token operator">:</span> Message<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
901
- <span class="token comment">// 存储消息到 Redis + Kafka</span>
902
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>messageStorage<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>conversationId<span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">;</span>
903
-
904
- <span class="token comment">// SSE 推送给在线用户</span>
905
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>ssePublisher<span class="token punctuation">.</span><span class="token function">publish</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token punctuation">{</span>
906
- type<span class="token operator">:</span> <span class="token string">'message'</span><span class="token punctuation">,</span>
907
- data<span class="token operator">:</span> msg
908
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
909
-
910
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Message saved: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>msg<span class="token punctuation">.</span>messageId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
911
- <span class="token punctuation">}</span><span class="token punctuation">,</span>
912
-
913
- <span class="token comment">// 检查点回调</span>
914
- <span class="token function-variable function">onCheckpoint</span><span class="token operator">:</span> <span class="token keyword keyword-async">async</span> <span class="token punctuation">(</span>checkpoint<span class="token operator">:</span> ExecutionCheckpoint<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
915
- <span class="token comment">// 保存检查点</span>
916
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>checkpointService<span class="token punctuation">.</span><span class="token function">saveCheckpoint</span><span class="token punctuation">(</span>checkpoint<span class="token punctuation">)</span><span class="token punctuation">;</span>
917
-
918
- <span class="token comment">// 更新执行进度</span>
919
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService<span class="token punctuation">.</span><span class="token function">updateProgress</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token punctuation">{</span>
920
- stepIndex<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>stepIndex<span class="token punctuation">,</span>
921
- lastMessageId<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>lastMessageId
922
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
923
-
924
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Checkpoint saved: step </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>checkpoint<span class="token punctuation">.</span>stepIndex<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
925
- <span class="token punctuation">}</span><span class="token punctuation">,</span>
926
-
927
- <span class="token comment">// 进度回调</span>
928
- <span class="token function-variable function">onProgress</span><span class="token operator">:</span> <span class="token keyword keyword-async">async</span> <span class="token punctuation">(</span>progress<span class="token operator">:</span> ExecutionProgress<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
929
- <span class="token comment">// 更新进度</span>
930
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService<span class="token punctuation">.</span><span class="token function">updateProgress</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token punctuation">{</span>
931
- currentAction<span class="token operator">:</span> progress<span class="token punctuation">.</span>currentAction<span class="token punctuation">,</span>
932
- stepIndex<span class="token operator">:</span> progress<span class="token punctuation">.</span>stepIndex<span class="token punctuation">,</span>
933
- messageCount<span class="token operator">:</span> progress<span class="token punctuation">.</span>messageCount
934
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
935
-
936
- <span class="token comment">// SSE 推送进度</span>
937
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>ssePublisher<span class="token punctuation">.</span><span class="token function">publish</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token punctuation">{</span>
938
- type<span class="token operator">:</span> <span class="token string">'progress'</span><span class="token punctuation">,</span>
939
- data<span class="token operator">:</span> progress
940
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
941
- <span class="token punctuation">}</span><span class="token punctuation">,</span>
942
-
943
- <span class="token comment">// 错误回调</span>
944
- <span class="token function-variable function">onError</span><span class="token operator">:</span> <span class="token keyword keyword-async">async</span> <span class="token punctuation">(</span>error<span class="token operator">:</span> Error<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
945
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Error:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
946
-
947
- <span class="token comment">// 保存错误检查点</span>
948
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>checkpointService<span class="token punctuation">.</span><span class="token function">saveCheckpoint</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
949
- executionId<span class="token punctuation">,</span>
950
- stepIndex<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
951
- lastMessageId<span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
952
- lastMessageTime<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
953
- canResume<span class="token operator">:</span> <span class="token boolean">false</span>
954
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
955
-
956
- <span class="token comment">// 更新状态为失败</span>
957
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService<span class="token punctuation">.</span><span class="token function">updateStatus</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token string">'FAILED'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
958
- error<span class="token operator">:</span> error<span class="token punctuation">.</span>message
959
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
960
-
961
- <span class="token comment">// SSE 推送错误</span>
962
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>ssePublisher<span class="token punctuation">.</span><span class="token function">publish</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token punctuation">{</span>
963
- type<span class="token operator">:</span> <span class="token string">'error'</span><span class="token punctuation">,</span>
964
- data<span class="token operator">:</span> <span class="token punctuation">{</span> message<span class="token operator">:</span> error<span class="token punctuation">.</span>message <span class="token punctuation">}</span>
965
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
966
- <span class="token punctuation">}</span>
967
- <span class="token punctuation">}</span>
968
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
969
-
970
- <span class="token comment">// 7. 执行 Agent</span>
971
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Starting agent execution from step </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>startStep<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
972
- <span class="token keyword keyword-const">const</span> result <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>agent<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">;</span>
973
-
974
- <span class="token comment">// 8. 执行完成</span>
975
- <span class="token keyword keyword-const">const</span> finalMessage <span class="token operator">=</span> result<span class="token punctuation">.</span>messages<span class="token punctuation">[</span>result<span class="token punctuation">.</span>messages<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
976
-
977
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService<span class="token punctuation">.</span><span class="token function">updateStatus</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token string">'COMPLETED'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
978
- result<span class="token operator">:</span> finalMessage<span class="token operator">?.</span>content<span class="token punctuation">,</span>
979
- steps<span class="token operator">:</span> result<span class="token punctuation">.</span>steps<span class="token punctuation">,</span>
980
- finishReason<span class="token operator">:</span> result<span class="token punctuation">.</span>finishReason
981
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
982
-
983
- <span class="token comment">// SSE 推送完成</span>
984
- <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>ssePublisher<span class="token punctuation">.</span><span class="token function">publish</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token punctuation">{</span>
985
- type<span class="token operator">:</span> <span class="token string">'done'</span><span class="token punctuation">,</span>
986
- data<span class="token operator">:</span> <span class="token punctuation">{</span>
987
- result<span class="token operator">:</span> finalMessage<span class="token operator">?.</span>content<span class="token punctuation">,</span>
988
- steps<span class="token operator">:</span> result<span class="token punctuation">.</span>steps
989
- <span class="token punctuation">}</span>
990
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
991
-
992
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Task completed: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
993
-
994
- <span class="token punctuation">}</span> <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
995
- <span class="token comment">// 执行失败</span>
996
- <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">[Worker] Task failed: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
997
-
998
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService<span class="token punctuation">.</span><span class="token function">updateStatus</span><span class="token punctuation">(</span>executionId<span class="token punctuation">,</span> <span class="token string">'FAILED'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
999
- error<span class="token operator">:</span> <span class="token punctuation">(</span>error <span class="token keyword keyword-as">as</span> Error<span class="token punctuation">)</span><span class="token punctuation">.</span>message
1000
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1001
-
1002
- <span class="token punctuation">}</span> <span class="token keyword keyword-finally">finally</span> <span class="token punctuation">{</span>
1003
- <span class="token comment">// 释放锁</span>
1004
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>executionService<span class="token punctuation">.</span><span class="token function">releaseLock</span><span class="token punctuation">(</span>executionId<span class="token punctuation">)</span><span class="token punctuation">;</span>
1005
- <span class="token punctuation">}</span>
1006
- <span class="token punctuation">}</span>
1007
-
1008
- <span class="token comment">// 辅助方法: 睡眠</span>
1009
- <span class="token keyword keyword-private">private</span> <span class="token function">sleep</span><span class="token punctuation">(</span>ms<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1010
- <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-new">new</span> <span class="token class-name"><span class="token builtin">Promise</span></span><span class="token punctuation">(</span>resolve <span class="token operator">=&gt;</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> ms<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1011
- <span class="token punctuation">}</span>
1012
- <span class="token punctuation">}</span>
1013
-
1014
- <span class="token comment">// ============================================================</span>
1015
- <span class="token comment">// 3. 启动 Worker</span>
1016
- <span class="token comment">// ============================================================</span>
1017
-
1018
- <span class="token keyword keyword-async">async</span> <span class="token keyword keyword-function">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
1019
- <span class="token comment">// 从容器获取依赖</span>
1020
- <span class="token keyword keyword-const">const</span> queue <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token generic-function"><span class="token function">get</span><span class="token generic class-name"><span class="token operator">&lt;</span>TaskQueue<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token string">'taskQueue'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1021
- <span class="token keyword keyword-const">const</span> agent <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token generic-function"><span class="token function">get</span><span class="token generic class-name"><span class="token operator">&lt;</span>StatelessAgent<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token string">'agent'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1022
- <span class="token keyword keyword-const">const</span> executionService <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token generic-function"><span class="token function">get</span><span class="token generic class-name"><span class="token operator">&lt;</span>ExecutionService<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token string">'executionService'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1023
- <span class="token keyword keyword-const">const</span> messageStorage <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token generic-function"><span class="token function">get</span><span class="token generic class-name"><span class="token operator">&lt;</span>MessageStorage<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token string">'messageStorage'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1024
- <span class="token keyword keyword-const">const</span> checkpointService <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token generic-function"><span class="token function">get</span><span class="token generic class-name"><span class="token operator">&lt;</span>CheckpointService<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token string">'checkpointService'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1025
- <span class="token keyword keyword-const">const</span> contextService <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token generic-function"><span class="token function">get</span><span class="token generic class-name"><span class="token operator">&lt;</span>ContextService<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token string">'contextService'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1026
- <span class="token keyword keyword-const">const</span> ssePublisher <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token generic-function"><span class="token function">get</span><span class="token generic class-name"><span class="token operator">&lt;</span>SSEPublisher<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token string">'ssePublisher'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1027
-
1028
- <span class="token comment">// 创建 Worker 实例</span>
1029
- <span class="token keyword keyword-const">const</span> worker <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">ExecutionWorker</span><span class="token punctuation">(</span>
1030
- queue<span class="token punctuation">,</span>
1031
- agent<span class="token punctuation">,</span>
1032
- executionService<span class="token punctuation">,</span>
1033
- messageStorage<span class="token punctuation">,</span>
1034
- checkpointService<span class="token punctuation">,</span>
1035
- contextService<span class="token punctuation">,</span>
1036
- ssePublisher
1037
- <span class="token punctuation">)</span><span class="token punctuation">;</span>
1038
-
1039
- <span class="token comment">// 启动</span>
1040
- <span class="token keyword keyword-await">await</span> worker<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1041
- <span class="token punctuation">}</span>
1042
-
1043
- <span class="token comment">// 运行</span>
1044
- <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token builtin">console</span><span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
1045
- </code></pre><hr>
1046
- <h3 id="依赖服务详细说明">依赖服务详细说明 </h3>
1047
- <h4 id="1-taskqueue-任务队列">1. TaskQueue (任务队列) </h4>
1048
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token keyword keyword-class">class</span> <span class="token class-name">TaskQueue</span> <span class="token punctuation">{</span>
1049
- <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword keyword-private">private</span> redis<span class="token operator">:</span> Redis<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
1050
-
1051
- <span class="token comment">// 放入任务 (LPUSH)</span>
1052
- <span class="token keyword keyword-async">async</span> <span class="token function">push</span><span class="token punctuation">(</span>task<span class="token operator">:</span> Task<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1053
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">lpush</span><span class="token punctuation">(</span><span class="token string">'task_queue'</span><span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>task<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1054
- <span class="token punctuation">}</span>
1055
-
1056
- <span class="token comment">// 阻塞取出任务 (BRPOP)</span>
1057
- <span class="token keyword keyword-async">async</span> <span class="token function">brpop</span><span class="token punctuation">(</span>timeout<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>Task <span class="token operator">|</span> <span class="token keyword keyword-null">null</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1058
- <span class="token keyword keyword-const">const</span> result <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">brpop</span><span class="token punctuation">(</span><span class="token string">'task_queue'</span><span class="token punctuation">,</span> timeout<span class="token punctuation">)</span><span class="token punctuation">;</span>
1059
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>result<span class="token punctuation">)</span> <span class="token punctuation">{</span>
1060
- <span class="token keyword keyword-return">return</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>result<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1061
- <span class="token punctuation">}</span>
1062
- <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">;</span>
1063
- <span class="token punctuation">}</span>
1064
- <span class="token punctuation">}</span>
1065
- </code></pre><h4 id="2-executionservice-执行状态管理">2. ExecutionService (执行状态管理) </h4>
1066
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token keyword keyword-class">class</span> <span class="token class-name">ExecutionService</span> <span class="token punctuation">{</span>
1067
- <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword keyword-private">private</span> redis<span class="token operator">:</span> Redis<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
1068
-
1069
- <span class="token comment">// 更新状态</span>
1070
- <span class="token keyword keyword-async">async</span> <span class="token function">updateStatus</span><span class="token punctuation">(</span>executionId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> status<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> extra<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1071
- <span class="token keyword keyword-const">const</span> key <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">execution:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
1072
- <span class="token keyword keyword-const">const</span> update<span class="token operator">:</span> <span class="token builtin">any</span> <span class="token operator">=</span> <span class="token punctuation">{</span> status<span class="token punctuation">,</span> updatedAt<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token operator">...</span>extra <span class="token punctuation">}</span><span class="token punctuation">;</span>
1073
-
1074
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>status <span class="token operator">===</span> <span class="token string">'COMPLETED'</span> <span class="token operator">||</span> status <span class="token operator">===</span> <span class="token string">'FAILED'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
1075
- update<span class="token punctuation">.</span>completedAt <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1076
- <span class="token punctuation">}</span>
1077
-
1078
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">hset</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> update<span class="token punctuation">)</span><span class="token punctuation">;</span>
1079
- <span class="token punctuation">}</span>
1080
-
1081
- <span class="token comment">// 获取锁 (防止重复执行)</span>
1082
- <span class="token keyword keyword-async">async</span> <span class="token function">acquireLock</span><span class="token punctuation">(</span>executionId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> workerId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token builtin">boolean</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1083
- <span class="token keyword keyword-const">const</span> key <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">lock:execution:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
1084
- <span class="token keyword keyword-const">const</span> result <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> workerId<span class="token punctuation">,</span> <span class="token punctuation">{</span>
1085
- <span class="token constant">NX</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 只有不存在时设置</span>
1086
- <span class="token constant">EX</span><span class="token operator">:</span> <span class="token number">300</span> <span class="token comment">// 5分钟超时</span>
1087
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1088
- <span class="token keyword keyword-return">return</span> result <span class="token operator">===</span> <span class="token string">'OK'</span><span class="token punctuation">;</span>
1089
- <span class="token punctuation">}</span>
1090
-
1091
- <span class="token comment">// 释放锁</span>
1092
- <span class="token keyword keyword-async">async</span> <span class="token function">releaseLock</span><span class="token punctuation">(</span>executionId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1093
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">del</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">lock:execution:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1094
- <span class="token punctuation">}</span>
1095
- <span class="token punctuation">}</span>
1096
- </code></pre><h4 id="3-messagestorage-消息存储">3. MessageStorage (消息存储) </h4>
1097
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token keyword keyword-class">class</span> <span class="token class-name">MessageStorage</span> <span class="token punctuation">{</span>
1098
- <span class="token function">constructor</span><span class="token punctuation">(</span>
1099
- <span class="token keyword keyword-private">private</span> redis<span class="token operator">:</span> Redis<span class="token punctuation">,</span>
1100
- <span class="token keyword keyword-private">private</span> kafka<span class="token operator">:</span> Kafka
1101
- <span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
1102
-
1103
- <span class="token comment">// 保存消息</span>
1104
- <span class="token keyword keyword-async">async</span> <span class="token function">save</span><span class="token punctuation">(</span>conversationId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> message<span class="token operator">:</span> Message<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1105
- <span class="token keyword keyword-const">const</span> key <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">conversation:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conversationId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:messages</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
1106
-
1107
- <span class="token comment">// 1. 实时写入 Redis</span>
1108
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">rpush</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1109
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">expire</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token number">1800</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 30分钟过期</span>
1110
-
1111
- <span class="token comment">// 2. 发送到 Kafka (异步)</span>
1112
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>kafka<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
1113
- topic<span class="token operator">:</span> <span class="token string">'messages'</span><span class="token punctuation">,</span>
1114
- messages<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>
1115
- key<span class="token operator">:</span> conversationId<span class="token punctuation">,</span>
1116
- value<span class="token operator">:</span> <span class="token punctuation">{</span> event<span class="token operator">:</span> <span class="token string">'message_created'</span><span class="token punctuation">,</span> conversationId<span class="token punctuation">,</span> message <span class="token punctuation">}</span>
1117
- <span class="token punctuation">}</span><span class="token punctuation">]</span>
1118
- <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1119
- <span class="token punctuation">}</span>
1120
- <span class="token punctuation">}</span>
1121
- </code></pre><h4 id="4-checkpointservice-检查点服务">4. CheckpointService (检查点服务) </h4>
1122
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token keyword keyword-class">class</span> <span class="token class-name">CheckpointService</span> <span class="token punctuation">{</span>
1123
- <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword keyword-private">private</span> redis<span class="token operator">:</span> Redis<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
1124
-
1125
- <span class="token comment">// 保存检查点</span>
1126
- <span class="token keyword keyword-async">async</span> <span class="token function">saveCheckpoint</span><span class="token punctuation">(</span>checkpoint<span class="token operator">:</span> ExecutionCheckpoint<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span><span class="token keyword keyword-void">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1127
- <span class="token keyword keyword-const">const</span> key <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">execution:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>checkpoint<span class="token punctuation">.</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:checkpoint</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
1128
-
1129
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">hset</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token punctuation">{</span>
1130
- stepIndex<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>stepIndex<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
1131
- lastMessageId<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>lastMessageId<span class="token punctuation">,</span>
1132
- lastMessageTime<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>lastMessageTime<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
1133
- canResume<span class="token operator">:</span> checkpoint<span class="token punctuation">.</span>canResume <span class="token operator">?</span> <span class="token string">'1'</span> <span class="token operator">:</span> <span class="token string">'0'</span>
1134
- <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token constant">EX</span><span class="token operator">:</span> <span class="token number">86400</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1135
- <span class="token punctuation">}</span>
1136
-
1137
- <span class="token comment">// 获取检查点</span>
1138
- <span class="token keyword keyword-async">async</span> <span class="token function">getLatestCheckpoint</span><span class="token punctuation">(</span>executionId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>ExecutionCheckpoint <span class="token operator">|</span> <span class="token keyword keyword-null">null</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1139
- <span class="token keyword keyword-const">const</span> key <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">execution:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>executionId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:checkpoint</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
1140
- <span class="token keyword keyword-const">const</span> data <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">hgetall</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
1141
-
1142
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>data <span class="token operator">||</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
1143
- <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">;</span>
1144
- <span class="token punctuation">}</span>
1145
-
1146
- <span class="token keyword keyword-return">return</span> <span class="token punctuation">{</span>
1147
- executionId<span class="token punctuation">,</span>
1148
- stepIndex<span class="token operator">:</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>stepIndex<span class="token punctuation">)</span><span class="token punctuation">,</span>
1149
- lastMessageId<span class="token operator">:</span> data<span class="token punctuation">.</span>lastMessageId<span class="token punctuation">,</span>
1150
- lastMessageTime<span class="token operator">:</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>lastMessageTime<span class="token punctuation">)</span><span class="token punctuation">,</span>
1151
- canResume<span class="token operator">:</span> data<span class="token punctuation">.</span>canResume <span class="token operator">===</span> <span class="token string">'1'</span>
1152
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
1153
- <span class="token punctuation">}</span>
1154
- <span class="token punctuation">}</span>
1155
- </code></pre><h4 id="5-contextservice-上下文服务">5. ContextService (上下文服务) </h4>
1156
- <pre data-role="codeBlock" data-info="typescript" class="language-typescript typescript"><code><span class="token keyword keyword-class">class</span> <span class="token class-name">ContextService</span> <span class="token punctuation">{</span>
1157
- <span class="token function">constructor</span><span class="token punctuation">(</span>
1158
- <span class="token keyword keyword-private">private</span> redis<span class="token operator">:</span> Redis<span class="token punctuation">,</span>
1159
- <span class="token keyword keyword-private">private</span> clickhouse<span class="token operator">:</span> ClickHouse
1160
- <span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
1161
-
1162
- <span class="token comment">// 加载上下文</span>
1163
- <span class="token keyword keyword-async">async</span> <span class="token function">load</span><span class="token punctuation">(</span>conversationId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>ConversationContext<span class="token operator">&gt;</span> <span class="token punctuation">{</span>
1164
- <span class="token keyword keyword-const">const</span> cacheKey <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">conversation:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conversationId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:context</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
1165
-
1166
- <span class="token comment">// 1. 先从 Redis 缓存获取</span>
1167
- <span class="token keyword keyword-const">const</span> cached <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
1168
- <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>cached<span class="token punctuation">)</span> <span class="token punctuation">{</span>
1169
- <span class="token keyword keyword-return">return</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>cached<span class="token punctuation">)</span><span class="token punctuation">;</span>
1170
- <span class="token punctuation">}</span>
1171
-
1172
- <span class="token comment">// 2. 缓存不存在,从 ClickHouse 加载</span>
1173
- <span class="token keyword keyword-const">const</span> messages <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>clickhouse<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
1174
- SELECT * FROM messages
1175
- WHERE conversation_id = '</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conversationId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">'
1176
- ORDER BY timestamp ASC
1177
- LIMIT 1000
1178
- </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1179
-
1180
- <span class="token comment">// 3. 加载系统提示和工具配置</span>
1181
- <span class="token keyword keyword-const">const</span> conversation <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>clickhouse<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
1182
- SELECT * FROM conversations
1183
- WHERE id = '</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conversationId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">'
1184
- </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1185
-
1186
- <span class="token keyword keyword-const">const</span> context<span class="token operator">:</span> ConversationContext <span class="token operator">=</span> <span class="token punctuation">{</span>
1187
- messages<span class="token punctuation">,</span>
1188
- systemPrompt<span class="token operator">:</span> conversation<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>system_prompt<span class="token punctuation">,</span>
1189
- tools<span class="token operator">:</span> conversation<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>tools
1190
- <span class="token punctuation">}</span><span class="token punctuation">;</span>
1191
-
1192
- <span class="token comment">// 4. 写入缓存</span>
1193
- <span class="token keyword keyword-await">await</span> <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>redis<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token constant">EX</span><span class="token operator">:</span> <span class="token number">300</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
1194
-
1195
- <span class="token keyword keyword-return">return</span> context<span class="token punctuation">;</span>
1196
- <span class="token punctuation">}</span>
1197
- <span class="token punctuation">}</span>
1198
- </code></pre><hr>
1199
- <h2 id="八-故障恢复机制">八、故障恢复机制 </h2>
1200
- <h3 id="场景-1-agent-进程崩溃">场景 1: Agent 进程崩溃 </h3>
1201
- <pre data-role="codeBlock" data-info="" class="language-text"><code>发生时间: Step 3 ~ Step 4 之间
1202
-
1203
- 已存储:
1204
- ✅ Step 1 消息 (Redis + Kafka)
1205
- ✅ Step 2 消息 (Redis + Kafka)
1206
- ✅ Step 3 消息 (Redis + Kafka)
1207
- ✅ Step 4 消息 (部分)
1208
- ✅ 检查点: stepIndex=3, lastMessageId=msg_3
1209
-
1210
- 丢失: Step 4 未完成的工具调用结果
1211
-
1212
- 恢复:
1213
- 1. 从检查点获取 lastMessageId=msg_3
1214
- 2. 查询 msg_3 之后的消息
1215
- 3. 从 Step 4 继续执行
1216
- </code></pre><h3 id="场景-2-redis-崩溃">场景 2: Redis 崩溃 </h3>
1217
- <pre data-role="codeBlock" data-info="" class="language-text"><code>已存储:
1218
- ✅ Kafka 保留所有消息 (7 天)
1219
-
1220
- 恢复:
1221
- 1. 从 Kafka 重放消息
1222
- 2. 重建 Redis 缓存
1223
- </code></pre><h3 id="场景-3-整个节点崩溃">场景 3: 整个节点崩溃 </h3>
1224
- <pre data-role="codeBlock" data-info="" class="language-text"><code>恢复:
1225
- 1. Task Manager 检测到超时
1226
- 2. 从检查点恢复
1227
- 3. 调度到新节点继续执行
1228
- </code></pre><hr>
1229
- <h2 id="九-完整数据流">九、完整数据流 </h2>
1230
- <pre data-role="codeBlock" data-info="" class="language-text"><code>┌─────────────────────────────────────────────────────────────────┐
1231
- │ 完整数据流 │
1232
- ├─────────────────────────────────────────────────────────────────┤
1233
- │ │
1234
- │ 用户请求 │
1235
- │ │ │
1236
- │ ▼ │
1237
- │ API Gateway (鉴权/限流) │
1238
- │ │ │
1239
- │ ▼ │
1240
- │ Controller (创建 Task) │
1241
- │ │ │
1242
- │ │ 立即返回 executionId │
1243
- │ ▼ │
1244
- │ Task Queue (Redis) │
1245
- │ │ │
1246
- │ ▼ │
1247
- │ Worker (执行 Agent) ────────────────────────────────────── │
1248
- │ │ │
1249
- │ ├─ onMessage ──▶ Redis + Kafka + SSE │
1250
- │ │ │
1251
- │ ├─ onCheckpoint ──▶ Redis │
1252
- │ │ │
1253
- │ ▼ │
1254
- │ 执行完成 │
1255
- │ │ │
1256
- │ ▼ │
1257
- │ 用户查询结果 (REST API / SSE) │
1258
- │ │
1259
- └─────────────────────────────────────────────────────────────────┘
1260
- </code></pre><hr>
1261
- <h2 id="十-技术选型">十、技术选型 </h2>
1262
- <table>
1263
- <thead>
1264
- <tr>
1265
- <th>层级</th>
1266
- <th>组件</th>
1267
- <th>用途</th>
1268
- </tr>
1269
- </thead>
1270
- <tbody>
1271
- <tr>
1272
- <td>API</td>
1273
- <td>Express/Spring Boot</td>
1274
- <td>REST API + SSE</td>
1275
- </tr>
1276
- <tr>
1277
- <td>任务队列</td>
1278
- <td>Redis List</td>
1279
- <td>任务缓冲</td>
1280
- </tr>
1281
- <tr>
1282
- <td>缓存</td>
1283
- <td>Redis</td>
1284
- <td>消息 + 检查点</td>
1285
- </tr>
1286
- <tr>
1287
- <td>消息队列</td>
1288
- <td>Kafka</td>
1289
- <td>异步持久化</td>
1290
- </tr>
1291
- <tr>
1292
- <td>主存储</td>
1293
- <td>ClickHouse</td>
1294
- <td>消息历史</td>
1295
- </tr>
1296
- <tr>
1297
- <td>搜索</td>
1298
- <td>Elasticsearch</td>
1299
- <td>全文搜索</td>
1300
- </tr>
1301
- </tbody>
1302
- </table>
1303
- <hr>
1304
- <h2 id="十一-总结">十一、总结 </h2>
1305
- <pre data-role="codeBlock" data-info="" class="language-text"><code>┌─────────────────────────────────────────────────────────────────┐
1306
- │ 方案总结 │
1307
- ├─────────────────────────────────────────────────────────────────┤
1308
- │ │
1309
- │ 1. 无状态 Agent │
1310
- │ - 输入: sessionId + messages + callbacks │
1311
- │ - 输出: new_messages + finishReason │
1312
- │ - 内部通过回调实时存储 │
1313
- │ │
1314
- │ 2. 实时存储 │
1315
- │ - onMessage: 每条消息实时存储 (Redis + Kafka) │
1316
- │ - onCheckpoint: 记录位置 (stepIndex + lastMessageId) │
1317
- │ │
1318
- │ 3. 后台执行 │
1319
- │ - API 立即返回 executionId │
1320
- │ - Task Queue 缓冲任务 │
1321
- │ - Worker 后台消费 │
1322
- │ │
1323
- │ 4. 用户交互 │
1324
- │ - SSE 实时推送 (在线用户) │
1325
- │ - REST API 查询 (离线用户) │
1326
- │ - 支持页面关闭后继续执行 │
1327
- │ │
1328
- │ 5. 故障恢复 │
1329
- │ - 检查点恢复: 从 lastMessageId 继续 │
1330
- │ - Worker 挂了: Task Queue 重试 │
1331
- │ - Redis 挂了: Kafka 重放 │
1332
- │ │
1333
- └─────────────────────────────────────────────────────────────────┘
1334
- </code></pre>
1335
- </div>
1336
-
1337
-
1338
-
1339
-
1340
-
1341
-
1342
-
1343
-
1344
-
1345
- </body></html>