@gt-fe/eap-runtime 0.0.8

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 (326) hide show
  1. package/README.md +323 -0
  2. package/dist/api/handlers/index.d.ts +3 -0
  3. package/dist/api/handlers/index.js +4 -0
  4. package/dist/api/handlers/invoke.handler.d.ts +77 -0
  5. package/dist/api/handlers/invoke.handler.js +411 -0
  6. package/dist/api/handlers/messages.handler.d.ts +53 -0
  7. package/dist/api/handlers/messages.handler.js +80 -0
  8. package/dist/api/handlers/stream.handler.d.ts +92 -0
  9. package/dist/api/handlers/stream.handler.js +432 -0
  10. package/dist/api/index.d.ts +3 -0
  11. package/dist/api/index.js +4 -0
  12. package/dist/api/middleware/auth.middleware.d.ts +96 -0
  13. package/dist/api/middleware/auth.middleware.js +158 -0
  14. package/dist/api/middleware/index.d.ts +1 -0
  15. package/dist/api/middleware/index.js +2 -0
  16. package/dist/api/routes/agent.routes.d.ts +44 -0
  17. package/dist/api/routes/agent.routes.js +204 -0
  18. package/dist/api/routes/index.d.ts +3 -0
  19. package/dist/api/routes/index.js +4 -0
  20. package/dist/api/routes/session.routes.d.ts +82 -0
  21. package/dist/api/routes/session.routes.js +169 -0
  22. package/dist/api/routes/task.routes.d.ts +75 -0
  23. package/dist/api/routes/task.routes.js +108 -0
  24. package/dist/checkpoint/checkpoint-serializer.d.ts +58 -0
  25. package/dist/checkpoint/checkpoint-serializer.js +81 -0
  26. package/dist/checkpoint/composite-checkpoint-saver.d.ts +42 -0
  27. package/dist/checkpoint/composite-checkpoint-saver.js +118 -0
  28. package/dist/checkpoint/contracts/checkpoint-saver.contract.d.ts +65 -0
  29. package/dist/checkpoint/contracts/checkpoint-saver.contract.js +12 -0
  30. package/dist/checkpoint/contracts/index.d.ts +1 -0
  31. package/dist/checkpoint/contracts/index.js +1 -0
  32. package/dist/checkpoint/file-checkpoint-saver.d.ts +19 -0
  33. package/dist/checkpoint/file-checkpoint-saver.js +98 -0
  34. package/dist/checkpoint/hybrid-checkpoint-saver.d.ts +130 -0
  35. package/dist/checkpoint/hybrid-checkpoint-saver.js +211 -0
  36. package/dist/checkpoint/in-memory-checkpoint-saver.d.ts +14 -0
  37. package/dist/checkpoint/in-memory-checkpoint-saver.js +46 -0
  38. package/dist/checkpoint/index.d.ts +16 -0
  39. package/dist/checkpoint/index.js +13 -0
  40. package/dist/checkpoint/mongo-checkpoint-saver.d.ts +38 -0
  41. package/dist/checkpoint/mongo-checkpoint-saver.js +56 -0
  42. package/dist/checkpoint/pg-checkpoint-saver.d.ts +59 -0
  43. package/dist/checkpoint/pg-checkpoint-saver.js +140 -0
  44. package/dist/checkpoint/redis-checkpoint-saver.d.ts +68 -0
  45. package/dist/checkpoint/redis-checkpoint-saver.js +173 -0
  46. package/dist/checkpoint/restore-checkpoint.d.ts +33 -0
  47. package/dist/checkpoint/restore-checkpoint.js +33 -0
  48. package/dist/common/agent-code.d.ts +10 -0
  49. package/dist/common/agent-code.js +12 -0
  50. package/dist/common/concurrency.d.ts +79 -0
  51. package/dist/common/concurrency.js +121 -0
  52. package/dist/common/health.d.ts +40 -0
  53. package/dist/common/health.js +37 -0
  54. package/dist/common/index.d.ts +5 -0
  55. package/dist/common/index.js +5 -0
  56. package/dist/common/logger.d.ts +34 -0
  57. package/dist/common/logger.js +38 -0
  58. package/dist/common/queue-consumer.d.ts +125 -0
  59. package/dist/common/queue-consumer.js +159 -0
  60. package/dist/common/trace-id.d.ts +2 -0
  61. package/dist/common/trace-id.js +8 -0
  62. package/dist/common/types.d.ts +104 -0
  63. package/dist/common/types.js +14 -0
  64. package/dist/contracts/index.d.ts +11 -0
  65. package/dist/contracts/index.js +10 -0
  66. package/dist/contracts/permission-checker.d.ts +10 -0
  67. package/dist/contracts/permission-checker.js +4 -0
  68. package/dist/contracts/trace-collector.d.ts +211 -0
  69. package/dist/contracts/trace-collector.js +13 -0
  70. package/dist/governance/governance-client.d.ts +38 -0
  71. package/dist/governance/governance-client.js +95 -0
  72. package/dist/governance/index.d.ts +7 -0
  73. package/dist/governance/index.js +5 -0
  74. package/dist/governance/permission-guard.d.ts +19 -0
  75. package/dist/governance/permission-guard.js +59 -0
  76. package/dist/graph/adapters/index.d.ts +3 -0
  77. package/dist/graph/adapters/index.js +3 -0
  78. package/dist/graph/adapters/langgraph-checkpointer.d.ts +40 -0
  79. package/dist/graph/adapters/langgraph-checkpointer.js +211 -0
  80. package/dist/graph/adapters/langgraph.adapter.d.ts +190 -0
  81. package/dist/graph/adapters/langgraph.adapter.js +1303 -0
  82. package/dist/graph/adapters/subgraph-compiler.d.ts +39 -0
  83. package/dist/graph/adapters/subgraph-compiler.js +248 -0
  84. package/dist/graph/condition-evaluator.d.ts +57 -0
  85. package/dist/graph/condition-evaluator.js +162 -0
  86. package/dist/graph/contracts/executable-graph.d.ts +340 -0
  87. package/dist/graph/contracts/executable-graph.js +10 -0
  88. package/dist/graph/contracts/index.d.ts +2 -0
  89. package/dist/graph/contracts/index.js +2 -0
  90. package/dist/graph/contracts/state-graph.contract.d.ts +76 -0
  91. package/dist/graph/contracts/state-graph.contract.js +11 -0
  92. package/dist/graph/hitl/hitl-handler.d.ts +199 -0
  93. package/dist/graph/hitl/hitl-handler.js +480 -0
  94. package/dist/graph/hitl/index.d.ts +1 -0
  95. package/dist/graph/hitl/index.js +1 -0
  96. package/dist/graph/index.d.ts +7 -0
  97. package/dist/graph/index.js +7 -0
  98. package/dist/graph/nodes/index.d.ts +2 -0
  99. package/dist/graph/nodes/index.js +2 -0
  100. package/dist/graph/nodes/llm-node.d.ts +182 -0
  101. package/dist/graph/nodes/llm-node.js +281 -0
  102. package/dist/graph/nodes/skill-bind-node.d.ts +32 -0
  103. package/dist/graph/nodes/skill-bind-node.js +116 -0
  104. package/dist/graph/nodes/tool-node.d.ts +75 -0
  105. package/dist/graph/nodes/tool-node.js +324 -0
  106. package/dist/graph/resolve-graph-prompt.d.ts +5 -0
  107. package/dist/graph/resolve-graph-prompt.js +75 -0
  108. package/dist/graph/retry/budget-aware-retry.d.ts +91 -0
  109. package/dist/graph/retry/budget-aware-retry.js +126 -0
  110. package/dist/graph/retry/index.d.ts +9 -0
  111. package/dist/graph/retry/index.js +8 -0
  112. package/dist/graph/retry/node-retry.d.ts +123 -0
  113. package/dist/graph/retry/node-retry.js +235 -0
  114. package/dist/graph/skill-audit-recorder.d.ts +126 -0
  115. package/dist/graph/skill-audit-recorder.js +114 -0
  116. package/dist/index.d.ts +21 -0
  117. package/dist/index.js +32 -0
  118. package/dist/memory/compression/compression-stats.d.ts +109 -0
  119. package/dist/memory/compression/compression-stats.js +144 -0
  120. package/dist/memory/compression/compression.repository.d.ts +62 -0
  121. package/dist/memory/compression/compression.repository.js +71 -0
  122. package/dist/memory/compression/index.d.ts +10 -0
  123. package/dist/memory/compression/index.js +15 -0
  124. package/dist/memory/compression/llm-summarize.d.ts +58 -0
  125. package/dist/memory/compression/llm-summarize.js +192 -0
  126. package/dist/memory/compression/sliding-window.compression.d.ts +60 -0
  127. package/dist/memory/compression/sliding-window.compression.js +175 -0
  128. package/dist/memory/index.d.ts +4 -0
  129. package/dist/memory/index.js +7 -0
  130. package/dist/memory/long-term-memory.service.d.ts +94 -0
  131. package/dist/memory/long-term-memory.service.js +120 -0
  132. package/dist/memory/message-compression.service.d.ts +128 -0
  133. package/dist/memory/message-compression.service.js +69 -0
  134. package/dist/memory/pg-memory.repository.d.ts +44 -0
  135. package/dist/memory/pg-memory.repository.js +108 -0
  136. package/dist/memory/semantic-retrieval.service.d.ts +148 -0
  137. package/dist/memory/semantic-retrieval.service.js +238 -0
  138. package/dist/providers/echo-llm-provider.d.ts +10 -0
  139. package/dist/providers/echo-llm-provider.js +87 -0
  140. package/dist/providers/http-llm-provider.d.ts +35 -0
  141. package/dist/providers/http-llm-provider.js +404 -0
  142. package/dist/providers/index.d.ts +7 -0
  143. package/dist/providers/index.js +5 -0
  144. package/dist/providers/local-llm-provider.d.ts +27 -0
  145. package/dist/providers/local-llm-provider.js +105 -0
  146. package/dist/providers/resolve-llm-model.d.ts +13 -0
  147. package/dist/providers/resolve-llm-model.js +30 -0
  148. package/dist/providers/routing-llm-provider.d.ts +28 -0
  149. package/dist/providers/routing-llm-provider.js +79 -0
  150. package/dist/registry/agent-models.d.ts +1 -0
  151. package/dist/registry/agent-models.js +1 -0
  152. package/dist/registry/agent-registry-client.d.ts +56 -0
  153. package/dist/registry/agent-registry-client.js +36 -0
  154. package/dist/registry/definition-cache.d.ts +37 -0
  155. package/dist/registry/definition-cache.js +82 -0
  156. package/dist/registry/deployment-snapshot.d.ts +99 -0
  157. package/dist/registry/deployment-snapshot.js +542 -0
  158. package/dist/registry/graph-loader.d.ts +134 -0
  159. package/dist/registry/graph-loader.js +985 -0
  160. package/dist/registry/index.d.ts +9 -0
  161. package/dist/registry/index.js +9 -0
  162. package/dist/registry/preload-errors.d.ts +13 -0
  163. package/dist/registry/preload-errors.js +35 -0
  164. package/dist/registry/preload-flags.d.ts +22 -0
  165. package/dist/registry/preload-flags.js +44 -0
  166. package/dist/registry/skill-io-guard.d.ts +25 -0
  167. package/dist/registry/skill-io-guard.js +98 -0
  168. package/dist/registry/skill-tree.d.ts +27 -0
  169. package/dist/registry/skill-tree.js +183 -0
  170. package/dist/runtime/agent-runtime.d.ts +106 -0
  171. package/dist/runtime/agent-runtime.js +777 -0
  172. package/dist/runtime/dev-runtime.d.ts +69 -0
  173. package/dist/runtime/dev-runtime.js +199 -0
  174. package/dist/runtime/index.d.ts +4 -0
  175. package/dist/runtime/index.js +3 -0
  176. package/dist/runtime/storage-profile.d.ts +50 -0
  177. package/dist/runtime/storage-profile.js +138 -0
  178. package/dist/runtime/types.d.ts +120 -0
  179. package/dist/runtime/types.js +9 -0
  180. package/dist/server.d.ts +12 -0
  181. package/dist/server.js +161 -0
  182. package/dist/session/compression-middleware.d.ts +126 -0
  183. package/dist/session/compression-middleware.js +230 -0
  184. package/dist/session/file-message.repository.d.ts +25 -0
  185. package/dist/session/file-message.repository.js +78 -0
  186. package/dist/session/file-session.repository.d.ts +72 -0
  187. package/dist/session/file-session.repository.js +212 -0
  188. package/dist/session/index.d.ts +13 -0
  189. package/dist/session/index.js +12 -0
  190. package/dist/session/message.service.d.ts +80 -0
  191. package/dist/session/message.service.js +128 -0
  192. package/dist/session/persist-turn-messages.d.ts +145 -0
  193. package/dist/session/persist-turn-messages.js +325 -0
  194. package/dist/session/pg-message.repository.d.ts +49 -0
  195. package/dist/session/pg-message.repository.js +149 -0
  196. package/dist/session/pg-session.repository.d.ts +46 -0
  197. package/dist/session/pg-session.repository.js +117 -0
  198. package/dist/session/session-context.service.d.ts +49 -0
  199. package/dist/session/session-context.service.js +66 -0
  200. package/dist/session/session.service.d.ts +194 -0
  201. package/dist/session/session.service.js +166 -0
  202. package/dist/sse/connection-event-logger.d.ts +21 -0
  203. package/dist/sse/connection-event-logger.js +33 -0
  204. package/dist/sse/contracts/index.d.ts +1 -0
  205. package/dist/sse/contracts/index.js +1 -0
  206. package/dist/sse/contracts/sse-emitter.contract.d.ts +74 -0
  207. package/dist/sse/contracts/sse-emitter.contract.js +11 -0
  208. package/dist/sse/event-buffer.d.ts +20 -0
  209. package/dist/sse/event-buffer.js +45 -0
  210. package/dist/sse/events/code-events.d.ts +19 -0
  211. package/dist/sse/events/code-events.js +9 -0
  212. package/dist/sse/events/collaboration-events.d.ts +37 -0
  213. package/dist/sse/events/collaboration-events.js +11 -0
  214. package/dist/sse/events/connection-events.d.ts +13 -0
  215. package/dist/sse/events/connection-events.js +9 -0
  216. package/dist/sse/events/file-events.d.ts +29 -0
  217. package/dist/sse/events/file-events.js +10 -0
  218. package/dist/sse/events/hitl-events.d.ts +33 -0
  219. package/dist/sse/events/hitl-events.js +10 -0
  220. package/dist/sse/events/index.d.ts +107 -0
  221. package/dist/sse/events/index.js +96 -0
  222. package/dist/sse/events/plan-events.d.ts +38 -0
  223. package/dist/sse/events/plan-events.js +11 -0
  224. package/dist/sse/events/reasoning-events.d.ts +35 -0
  225. package/dist/sse/events/reasoning-events.js +13 -0
  226. package/dist/sse/events/response-events.d.ts +25 -0
  227. package/dist/sse/events/response-events.js +12 -0
  228. package/dist/sse/events/session-events.d.ts +43 -0
  229. package/dist/sse/events/session-events.js +12 -0
  230. package/dist/sse/events/skill-events.d.ts +48 -0
  231. package/dist/sse/events/skill-events.js +11 -0
  232. package/dist/sse/events/stats-events.d.ts +44 -0
  233. package/dist/sse/events/stats-events.js +12 -0
  234. package/dist/sse/events/tool-events.d.ts +68 -0
  235. package/dist/sse/events/tool-events.js +14 -0
  236. package/dist/sse/index.d.ts +8 -0
  237. package/dist/sse/index.js +8 -0
  238. package/dist/sse/sse-connection-manager.d.ts +116 -0
  239. package/dist/sse/sse-connection-manager.js +185 -0
  240. package/dist/sse/sse-emitter.d.ts +108 -0
  241. package/dist/sse/sse-emitter.js +210 -0
  242. package/dist/sse/sse-heartbeat.d.ts +58 -0
  243. package/dist/sse/sse-heartbeat.js +76 -0
  244. package/dist/sse/trace-collector.d.ts +60 -0
  245. package/dist/sse/trace-collector.js +107 -0
  246. package/dist/task/contracts/index.d.ts +2 -0
  247. package/dist/task/contracts/index.js +1 -0
  248. package/dist/task/contracts/task-manager.contract.d.ts +160 -0
  249. package/dist/task/contracts/task-manager.contract.js +10 -0
  250. package/dist/task/index.d.ts +7 -0
  251. package/dist/task/index.js +5 -0
  252. package/dist/task/pg-task.repository.d.ts +47 -0
  253. package/dist/task/pg-task.repository.js +131 -0
  254. package/dist/task/task-progress-tracker.d.ts +67 -0
  255. package/dist/task/task-progress-tracker.js +80 -0
  256. package/dist/task/task-timeout.d.ts +70 -0
  257. package/dist/task/task-timeout.js +116 -0
  258. package/dist/task/task.service.d.ts +84 -0
  259. package/dist/task/task.service.js +233 -0
  260. package/dist/token/compression-budget-integration.d.ts +145 -0
  261. package/dist/token/compression-budget-integration.js +185 -0
  262. package/dist/token/context-window-budget.d.ts +113 -0
  263. package/dist/token/context-window-budget.js +134 -0
  264. package/dist/token/contracts/index.d.ts +1 -0
  265. package/dist/token/contracts/index.js +1 -0
  266. package/dist/token/contracts/token-budget.contract.d.ts +77 -0
  267. package/dist/token/contracts/token-budget.contract.js +11 -0
  268. package/dist/token/index.d.ts +12 -0
  269. package/dist/token/index.js +10 -0
  270. package/dist/token/pg-token-budget.repository.d.ts +39 -0
  271. package/dist/token/pg-token-budget.repository.js +116 -0
  272. package/dist/token/session-budget-checker.d.ts +54 -0
  273. package/dist/token/session-budget-checker.js +72 -0
  274. package/dist/token/token-budget-guard.d.ts +66 -0
  275. package/dist/token/token-budget-guard.js +97 -0
  276. package/dist/token/token-budget.service.d.ts +86 -0
  277. package/dist/token/token-budget.service.js +130 -0
  278. package/dist/token/token-detail-mode.d.ts +73 -0
  279. package/dist/token/token-detail-mode.js +107 -0
  280. package/dist/token/token-estimator.d.ts +80 -0
  281. package/dist/token/token-estimator.js +134 -0
  282. package/dist/token/token-stats.service.d.ts +88 -0
  283. package/dist/token/token-stats.service.js +94 -0
  284. package/dist/tool/create-tool-executor.d.ts +33 -0
  285. package/dist/tool/create-tool-executor.js +60 -0
  286. package/dist/tool/dev-http-executor.d.ts +18 -0
  287. package/dist/tool/dev-http-executor.js +96 -0
  288. package/dist/tool/dev-mcp-executor.d.ts +29 -0
  289. package/dist/tool/dev-mcp-executor.js +84 -0
  290. package/dist/tool/dev-tool-executor.d.ts +23 -0
  291. package/dist/tool/dev-tool-executor.js +55 -0
  292. package/dist/tool/file-artifact.d.ts +11 -0
  293. package/dist/tool/file-artifact.js +90 -0
  294. package/dist/tool/http-tool-executor.d.ts +17 -0
  295. package/dist/tool/http-tool-executor.js +158 -0
  296. package/dist/tool/index.d.ts +18 -0
  297. package/dist/tool/index.js +17 -0
  298. package/dist/tool/loaded-tool-definition.d.ts +35 -0
  299. package/dist/tool/loaded-tool-definition.js +9 -0
  300. package/dist/tool/local-mcp-client.d.ts +23 -0
  301. package/dist/tool/local-mcp-client.js +225 -0
  302. package/dist/tool/local-tool-executor.d.ts +37 -0
  303. package/dist/tool/local-tool-executor.js +249 -0
  304. package/dist/tool/mcp-tool-executor.d.ts +23 -0
  305. package/dist/tool/mcp-tool-executor.js +160 -0
  306. package/dist/tool/mock-tool-executor.d.ts +28 -0
  307. package/dist/tool/mock-tool-executor.js +65 -0
  308. package/dist/tool/system-prompt-builder.d.ts +114 -0
  309. package/dist/tool/system-prompt-builder.js +213 -0
  310. package/dist/tool/tool-confirmation.d.ts +29 -0
  311. package/dist/tool/tool-confirmation.js +81 -0
  312. package/dist/tool/tool-event-emitter.d.ts +58 -0
  313. package/dist/tool/tool-event-emitter.js +154 -0
  314. package/dist/tool/tool-execution-router.d.ts +25 -0
  315. package/dist/tool/tool-execution-router.js +50 -0
  316. package/dist/tool/tool-executor.interface.d.ts +85 -0
  317. package/dist/tool/tool-executor.interface.js +7 -0
  318. package/dist/tool/tool-orchestrator.d.ts +22 -0
  319. package/dist/tool/tool-orchestrator.js +104 -0
  320. package/dist/tool/tool-result-injector.d.ts +64 -0
  321. package/dist/tool/tool-result-injector.js +65 -0
  322. package/dist/utils/format-error.d.ts +4 -0
  323. package/dist/utils/format-error.js +4 -0
  324. package/dist/utils/http-error.d.ts +11 -0
  325. package/dist/utils/http-error.js +24 -0
  326. package/package.json +56 -0
@@ -0,0 +1,325 @@
1
+ /**
2
+ * 多轮对话 Message 写回辅助
3
+ *
4
+ * invoke / stream 主路径在执行前后调用,保证 Session 短期记忆可被下一轮加载。
5
+ */
6
+ export async function persistUserTurnMessage(messageService, params) {
7
+ if (!messageService || !params.content)
8
+ return;
9
+ await messageService.addMessage({
10
+ sessionId: params.sessionId,
11
+ taskId: params.taskId,
12
+ correlationId: params.correlationId,
13
+ role: 'user',
14
+ content: params.content,
15
+ tokenCount: 0,
16
+ });
17
+ }
18
+ export async function persistAssistantTurnMessage(messageService, params) {
19
+ if (!messageService)
20
+ return;
21
+ const content = params.content?.trim() ?? '';
22
+ if (!content && !(params.toolCalls && params.toolCalls.length > 0))
23
+ return;
24
+ await messageService.addMessage({
25
+ sessionId: params.sessionId,
26
+ taskId: params.taskId,
27
+ correlationId: params.correlationId,
28
+ role: 'assistant',
29
+ content: content || '(tool_calls)',
30
+ toolCalls: params.toolCalls,
31
+ tokenCount: params.tokenCount ?? 0,
32
+ reasoning: params.reasoningContent
33
+ ? { reasoningContent: params.reasoningContent }
34
+ : null,
35
+ });
36
+ }
37
+ /**
38
+ * HITL 等待态占位消息:避免早退时本轮只有 user、历史偏薄
39
+ *
40
+ * 以 assistant 写入确认问题;metadata.hitlWaiting=true 供后续过滤/展示。
41
+ */
42
+ export async function persistHitlWaitingPlaceholder(messageService, params) {
43
+ if (!messageService)
44
+ return;
45
+ const question = params.question?.trim() || '等待人工确认';
46
+ await messageService.addMessage({
47
+ sessionId: params.sessionId,
48
+ taskId: params.taskId,
49
+ correlationId: params.correlationId,
50
+ role: 'assistant',
51
+ content: question,
52
+ tokenCount: 0,
53
+ metadata: {
54
+ hitlWaiting: true,
55
+ hitlOptions: params.options,
56
+ hitlThreadId: params.threadId,
57
+ },
58
+ });
59
+ }
60
+ export async function persistToolTurnMessage(messageService, params) {
61
+ if (!messageService)
62
+ return;
63
+ const content = typeof params.content === 'string'
64
+ ? params.content
65
+ : JSON.stringify(params.content ?? null);
66
+ await messageService.addMessage({
67
+ sessionId: params.sessionId,
68
+ taskId: params.taskId,
69
+ correlationId: params.correlationId,
70
+ role: 'tool',
71
+ content,
72
+ toolCalls: [
73
+ {
74
+ id: params.toolCallId,
75
+ name: params.toolName,
76
+ success: params.success,
77
+ },
78
+ ],
79
+ tokenCount: 0,
80
+ });
81
+ }
82
+ /** 从流式 RuntimeEvent payload 抽取文本增量 */
83
+ export function extractStreamTextDelta(eventType, payload) {
84
+ if (eventType !== 'response.chunk' &&
85
+ eventType !== 'response.delta' &&
86
+ eventType !== 'response.final') {
87
+ return '';
88
+ }
89
+ if (!payload || typeof payload !== 'object')
90
+ return '';
91
+ const p = payload;
92
+ const text = p.chunk ?? p.delta ?? p.content;
93
+ return typeof text === 'string' ? text : '';
94
+ }
95
+ /**
96
+ * 从流式事件抽取 assistant reasoning。
97
+ * 子图在 skill.completed 上回传(父图不再为 subgraph 节点发空 response.chunk)。
98
+ */
99
+ export function extractStreamReasoning(eventType, payload) {
100
+ if (eventType !== 'response.chunk' &&
101
+ eventType !== 'response.delta' &&
102
+ eventType !== 'response.final' &&
103
+ eventType !== 'skill.completed') {
104
+ return undefined;
105
+ }
106
+ if (!payload || typeof payload !== 'object')
107
+ return undefined;
108
+ const value = payload.reasoningContent;
109
+ return typeof value === 'string' && value ? value : undefined;
110
+ }
111
+ /** 历史 MessageRecord → GraphMessage(保留 tool 元数据与 reasoning) */
112
+ export function messageRecordsToGraphMessages(records) {
113
+ return records.map((m) => {
114
+ const base = {
115
+ role: m.role,
116
+ content: m.content,
117
+ };
118
+ if (m.toolCalls && m.toolCalls.length > 0) {
119
+ base.toolCalls = m.toolCalls;
120
+ const first = m.toolCalls[0];
121
+ if (m.role === 'tool') {
122
+ if (first?.id)
123
+ base.toolCallId = first.id;
124
+ if (first?.name)
125
+ base.toolName = first.name;
126
+ if (typeof first?.success === 'boolean')
127
+ base.success = first.success;
128
+ }
129
+ }
130
+ const reasoningContent = extractReasoningContent(m.reasoning);
131
+ if (reasoningContent)
132
+ base.reasoningContent = reasoningContent;
133
+ return base;
134
+ });
135
+ }
136
+ function extractReasoningContent(reasoning) {
137
+ if (typeof reasoning === 'string' && reasoning) {
138
+ const trimmed = reasoning.trim();
139
+ if (trimmed.startsWith('{')) {
140
+ try {
141
+ const parsed = JSON.parse(trimmed);
142
+ if (typeof parsed.reasoningContent === 'string' && parsed.reasoningContent) {
143
+ return parsed.reasoningContent;
144
+ }
145
+ if (typeof parsed.content === 'string' && parsed.content) {
146
+ return parsed.content;
147
+ }
148
+ }
149
+ catch {
150
+ // 非 JSON 字符串,按原文回传
151
+ }
152
+ }
153
+ return reasoning;
154
+ }
155
+ if (!reasoning || typeof reasoning !== 'object')
156
+ return undefined;
157
+ const r = reasoning;
158
+ if (typeof r.reasoningContent === 'string' && r.reasoningContent)
159
+ return r.reasoningContent;
160
+ if (typeof r.content === 'string' && r.content)
161
+ return r.content;
162
+ return undefined;
163
+ }
164
+ /**
165
+ * 组装本轮送入 Graph 的 messages。
166
+ *
167
+ * 契约:
168
+ * - Session 消息是产品侧短期记忆(展示/落库)
169
+ * - Session 级 Checkpoint 持有图内 messages(含 reasoning)
170
+ * - 当 Checkpoint 已有历史时,只追加本轮 user,避免双重 append
171
+ * - Checkpoint 缺失/无 messages 时,回退 Session 全量历史
172
+ */
173
+ export async function buildTurnGraphMessages(params) {
174
+ const newUser = { role: 'user', content: params.input };
175
+ const history = params.history;
176
+ if (!params.checkpointSaver || !params.threadId || history.length === 0) {
177
+ return [...history, newUser];
178
+ }
179
+ const cp = await params.checkpointSaver.load(params.threadId);
180
+ if (checkpointHasMessages(cp)) {
181
+ return [newUser];
182
+ }
183
+ return [...history, newUser];
184
+ }
185
+ function checkpointHasMessages(cp) {
186
+ if (!cp)
187
+ return false;
188
+ if (Array.isArray(cp.state?.messages) && cp.state.messages.length > 0)
189
+ return true;
190
+ const channelValues = cp.engineSnapshot?.['channel_values'];
191
+ if (channelValues && typeof channelValues === 'object') {
192
+ const messages = channelValues['messages'];
193
+ if (Array.isArray(messages) && messages.length > 0)
194
+ return true;
195
+ }
196
+ return false;
197
+ }
198
+ export function buildHitlWaitingTaskOutput(params) {
199
+ return {
200
+ hitlWaiting: true,
201
+ hitlThreadId: params.threadId,
202
+ question: params.question?.trim() || '等待人工确认',
203
+ options: params.options,
204
+ };
205
+ }
206
+ /** 从 Task.output 解析 Checkpoint thread_id(含嵌套 hitl.threadId) */
207
+ export function extractHitlThreadId(output) {
208
+ if (!output || typeof output !== 'object')
209
+ return undefined;
210
+ const o = output;
211
+ if (typeof o.hitlThreadId === 'string' && o.hitlThreadId.trim()) {
212
+ return o.hitlThreadId.trim();
213
+ }
214
+ const hitl = o.hitl;
215
+ if (hitl && typeof hitl === 'object') {
216
+ const threadId = hitl.threadId;
217
+ if (typeof threadId === 'string' && threadId.trim())
218
+ return threadId.trim();
219
+ }
220
+ return undefined;
221
+ }
222
+ /**
223
+ * Checkpoint thread_id 契约:HITL/多轮优先且应唯一等于 sessionId;
224
+ * 无 session 时退到 `task-${taskId}`。勿用 correlationId 作为 Checkpoint key。
225
+ *
226
+ * 注意:session 级 thread + 全量 Session 历史同时注入会导致 messages 双重 append。
227
+ * 组装本轮 Graph 输入请用 {@link buildTurnGraphMessages}(有 Checkpoint 历史则只追加 user)。
228
+ */
229
+ export function resolveCheckpointThreadId(params) {
230
+ if (params.sessionId)
231
+ return params.sessionId;
232
+ if (params.taskId)
233
+ return `task-${params.taskId}`;
234
+ if (params.graphId)
235
+ return `thread-${params.graphId}`;
236
+ return `thread-${Date.now()}`;
237
+ }
238
+ /**
239
+ * 将 stream 侧累加的 tool 事件规范为与 invoke GraphState 增量同序的 messages:
240
+ * assistant(tool_calls) → tool* → assistant(text)
241
+ */
242
+ export function buildTurnTranscriptFromStreamEvents(params) {
243
+ const out = [];
244
+ const pending = params.pendingToolCalls ?? [];
245
+ const results = params.toolResults ?? [];
246
+ const text = params.assistantText ?? '';
247
+ if (pending.length > 0) {
248
+ out.push({
249
+ role: 'assistant',
250
+ content: '',
251
+ toolCalls: pending.map((tc) => ({
252
+ id: tc.id,
253
+ name: tc.name,
254
+ arguments: tc.arguments,
255
+ })),
256
+ ...(params.toolCallReasoningContent
257
+ ? { reasoningContent: params.toolCallReasoningContent }
258
+ : {}),
259
+ });
260
+ }
261
+ for (const tr of results) {
262
+ out.push({
263
+ role: 'tool',
264
+ content: typeof tr.content === 'string' ? tr.content : JSON.stringify(tr.content ?? null),
265
+ toolCallId: tr.toolCallId,
266
+ toolName: tr.toolName,
267
+ success: tr.success,
268
+ });
269
+ }
270
+ if (text.trim() || (params.persistEmptyAssistant && out.length === 0)) {
271
+ out.push({
272
+ role: 'assistant',
273
+ content: text,
274
+ ...(params.assistantReasoningContent
275
+ ? { reasoningContent: params.assistantReasoningContent }
276
+ : {}),
277
+ });
278
+ }
279
+ return out;
280
+ }
281
+ /**
282
+ * 统一落库本轮 transcript(invoke / stream / AgentRuntime.stream 共用)
283
+ */
284
+ export async function persistTurnTranscript(messageService, params) {
285
+ if (!messageService)
286
+ return;
287
+ let hasAssistantText = false;
288
+ for (const m of params.messages) {
289
+ if (m.role === 'assistant') {
290
+ const isToolCallOnly = Boolean(m.toolCalls?.length) && !(m.content?.trim());
291
+ if (!isToolCallOnly && (m.content?.trim() ?? '')) {
292
+ hasAssistantText = true;
293
+ }
294
+ await persistAssistantTurnMessage(messageService, {
295
+ sessionId: params.sessionId,
296
+ taskId: params.taskId,
297
+ correlationId: params.correlationId,
298
+ content: m.content ?? '',
299
+ toolCalls: m.toolCalls,
300
+ tokenCount: isToolCallOnly ? 0 : params.assistantTokenCount,
301
+ reasoningContent: m.reasoningContent,
302
+ });
303
+ }
304
+ else if (m.role === 'tool') {
305
+ await persistToolTurnMessage(messageService, {
306
+ sessionId: params.sessionId,
307
+ taskId: params.taskId,
308
+ correlationId: params.correlationId,
309
+ toolCallId: m.toolCallId ?? 'unknown',
310
+ toolName: m.toolName ?? 'unknown',
311
+ content: m.content,
312
+ success: m.success !== false,
313
+ });
314
+ }
315
+ }
316
+ if (!hasAssistantText && params.fallbackAssistantContent != null) {
317
+ await persistAssistantTurnMessage(messageService, {
318
+ sessionId: params.sessionId,
319
+ taskId: params.taskId,
320
+ correlationId: params.correlationId,
321
+ content: params.fallbackAssistantContent,
322
+ tokenCount: params.assistantTokenCount,
323
+ });
324
+ }
325
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * PostgresMessageRepository — Message 持久化 PostgreSQL 实现
3
+ *
4
+ * 基于 pg 连接池实现 IFullMessageRepository 接口。
5
+ * JSON 字段(tool_calls / reasoning / metadata)使用 JSONB 类型存储。
6
+ *
7
+ * @see design.md §1.3 数据模型 — messages 表
8
+ * @see message.service.ts IFullMessageRepository 接口定义
9
+ */
10
+ import type { MessageRecord } from './session.service.js';
11
+ import type { IFullMessageRepository } from './message.service.js';
12
+ /** pg Pool 抽象接口 */
13
+ export interface IPgPool {
14
+ query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<{
15
+ rows: T[];
16
+ }>;
17
+ }
18
+ export declare class PostgresMessageRepository implements IFullMessageRepository {
19
+ private readonly pool;
20
+ constructor(pool: IPgPool);
21
+ /**
22
+ * INSERT message record with audit fields
23
+ */
24
+ save(message: MessageRecord): Promise<void>;
25
+ /**
26
+ * SELECT messages by session_id, ORDER BY created_at ASC, 支持分页
27
+ * Excludes soft-deleted records
28
+ */
29
+ findBySessionId(sessionId: string, limit?: number, offset?: number): Promise<MessageRecord[]>;
30
+ /**
31
+ * SELECT messages by task_id, ORDER BY created_at ASC
32
+ * Excludes soft-deleted records
33
+ */
34
+ findByTaskId(taskId: string): Promise<MessageRecord[]>;
35
+ /**
36
+ * Soft delete message
37
+ */
38
+ saveMany(messages: MessageRecord[]): Promise<void>;
39
+ markAsCompressed(messageIds: string[], compressedBy: string, compressedAt: string): Promise<void>;
40
+ softDelete(id: string, deletedBy: string): Promise<void>;
41
+ /**
42
+ * 将 PostgreSQL 行数据转换为 MessageRecord
43
+ */
44
+ private rowToRecord;
45
+ /**
46
+ * 解析 JSON 字段 — pg 可能已自动解析 JSONB 列,也可能返回字符串
47
+ */
48
+ private parseJson;
49
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * PostgresMessageRepository — Message 持久化 PostgreSQL 实现
3
+ *
4
+ * 基于 pg 连接池实现 IFullMessageRepository 接口。
5
+ * JSON 字段(tool_calls / reasoning / metadata)使用 JSONB 类型存储。
6
+ *
7
+ * @see design.md §1.3 数据模型 — messages 表
8
+ * @see message.service.ts IFullMessageRepository 接口定义
9
+ */
10
+ // ─────────────────────────────────────────────
11
+ // PostgresMessageRepository
12
+ // ─────────────────────────────────────────────
13
+ export class PostgresMessageRepository {
14
+ pool;
15
+ constructor(pool) {
16
+ this.pool = pool;
17
+ }
18
+ /**
19
+ * INSERT message record with audit fields
20
+ */
21
+ async save(message) {
22
+ const sql = `
23
+ INSERT INTO messages (
24
+ id, session_id, task_id, correlation_id, role, content, tool_calls,
25
+ reasoning, metadata, token_count, duration_ms,
26
+ created_by, created_at, updated_by, updated_at
27
+ )
28
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
29
+ `;
30
+ await this.pool.query(sql, [
31
+ message.id,
32
+ message.sessionId,
33
+ message.taskId,
34
+ message.correlationId,
35
+ message.role,
36
+ message.content,
37
+ message.toolCalls != null ? JSON.stringify(message.toolCalls) : null,
38
+ message.reasoning != null ? JSON.stringify(message.reasoning) : null,
39
+ JSON.stringify(message.metadata ?? {}),
40
+ message.tokenCount,
41
+ message.durationMs ?? null,
42
+ message.createdBy || 'system',
43
+ message.createdAt,
44
+ message.updatedBy || 'system',
45
+ message.updatedAt,
46
+ ]);
47
+ }
48
+ /**
49
+ * SELECT messages by session_id, ORDER BY created_at ASC, 支持分页
50
+ * Excludes soft-deleted records
51
+ */
52
+ async findBySessionId(sessionId, limit, offset) {
53
+ let sql = `SELECT * FROM messages WHERE session_id = $1 AND is_deleted = FALSE ORDER BY created_at ASC`;
54
+ const params = [sessionId];
55
+ if (limit !== undefined) {
56
+ sql += ` LIMIT $${params.length + 1}`;
57
+ params.push(limit);
58
+ }
59
+ if (offset !== undefined) {
60
+ sql += ` OFFSET $${params.length + 1}`;
61
+ params.push(offset);
62
+ }
63
+ const { rows } = await this.pool.query(sql, params);
64
+ return rows.map((row) => this.rowToRecord(row));
65
+ }
66
+ /**
67
+ * SELECT messages by task_id, ORDER BY created_at ASC
68
+ * Excludes soft-deleted records
69
+ */
70
+ async findByTaskId(taskId) {
71
+ const sql = `SELECT * FROM messages WHERE task_id = $1 AND is_deleted = FALSE ORDER BY created_at ASC`;
72
+ const { rows } = await this.pool.query(sql, [taskId]);
73
+ return rows.map((row) => this.rowToRecord(row));
74
+ }
75
+ /**
76
+ * Soft delete message
77
+ */
78
+ async saveMany(messages) {
79
+ for (const message of messages) {
80
+ await this.save(message);
81
+ }
82
+ }
83
+ async markAsCompressed(messageIds, compressedBy, compressedAt) {
84
+ if (messageIds.length === 0)
85
+ return;
86
+ const placeholders = messageIds.map((_, i) => `$${i + 4}`).join(',');
87
+ const patch = JSON.stringify({
88
+ compressed: true,
89
+ compressedBy,
90
+ compressedAt,
91
+ });
92
+ const sql = `
93
+ UPDATE messages
94
+ SET metadata = COALESCE(metadata, '{}'::jsonb) || $1::jsonb,
95
+ updated_by = $2,
96
+ updated_at = $3
97
+ WHERE id IN (${placeholders}) AND is_deleted = FALSE
98
+ `;
99
+ await this.pool.query(sql, [patch, compressedBy, compressedAt, ...messageIds]);
100
+ }
101
+ async softDelete(id, deletedBy) {
102
+ const sql = `
103
+ UPDATE messages
104
+ SET is_deleted = TRUE, deleted_by = $1, deleted_at = NOW()
105
+ WHERE id = $2 AND is_deleted = FALSE
106
+ `;
107
+ await this.pool.query(sql, [deletedBy, id]);
108
+ }
109
+ // ─────────────────────────────────────────────
110
+ // Private Helpers
111
+ // ─────────────────────────────────────────────
112
+ /**
113
+ * 将 PostgreSQL 行数据转换为 MessageRecord
114
+ */
115
+ rowToRecord(row) {
116
+ const metadataRaw = row.metadata != null ? this.parseJson(row.metadata) : {};
117
+ return {
118
+ id: row.id,
119
+ sessionId: row.session_id,
120
+ taskId: row.task_id,
121
+ correlationId: row.correlation_id,
122
+ role: row.role,
123
+ content: row.content,
124
+ toolCalls: row.tool_calls != null ? this.parseJson(row.tool_calls) : null,
125
+ reasoning: row.reasoning != null ? this.parseJson(row.reasoning) : null,
126
+ metadata: metadataRaw && typeof metadataRaw === 'object' && !Array.isArray(metadataRaw)
127
+ ? metadataRaw
128
+ : {},
129
+ tokenCount: row.token_count,
130
+ durationMs: row.duration_ms,
131
+ createdBy: row.created_by,
132
+ createdAt: row.created_at.toISOString(),
133
+ updatedBy: row.updated_by,
134
+ updatedAt: row.updated_at.toISOString(),
135
+ isDeleted: row.is_deleted,
136
+ deletedBy: row.deleted_by,
137
+ deletedAt: row.deleted_at?.toISOString(),
138
+ };
139
+ }
140
+ /**
141
+ * 解析 JSON 字段 — pg 可能已自动解析 JSONB 列,也可能返回字符串
142
+ */
143
+ parseJson(value) {
144
+ if (typeof value === 'string') {
145
+ return JSON.parse(value);
146
+ }
147
+ return value;
148
+ }
149
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * PostgresSessionRepository — Session 持久化 PostgreSQL 实现
3
+ *
4
+ * 基于 pg 连接池实现 ISessionRepository 接口。
5
+ * JSON 字段(metadata)使用 JSONB 类型存储。
6
+ *
7
+ * @see design.md §1.3 数据模型 — sessions 表
8
+ * @see session.service.ts ISessionRepository 接口定义
9
+ */
10
+ import type { SessionRecord, ISessionRepository } from './session.service.js';
11
+ /** pg Pool 抽象接口 */
12
+ export interface IPgPool {
13
+ query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<{
14
+ rows: T[];
15
+ }>;
16
+ }
17
+ export declare class PostgresSessionRepository implements ISessionRepository {
18
+ private readonly pool;
19
+ constructor(pool: IPgPool);
20
+ /**
21
+ * INSERT session record with all fields including audit fields
22
+ */
23
+ save(session: SessionRecord): Promise<void>;
24
+ /**
25
+ * SELECT session by id, deserialize JSON fields
26
+ * Excludes soft-deleted records
27
+ */
28
+ findById(id: string): Promise<SessionRecord | null>;
29
+ /**
30
+ * UPDATE all mutable fields by id
31
+ */
32
+ findByUserId(userId: string, limit?: number, offset?: number): Promise<SessionRecord[]>;
33
+ update(session: SessionRecord): Promise<void>;
34
+ /**
35
+ * Soft delete session
36
+ */
37
+ softDelete(id: string, deletedBy: string): Promise<void>;
38
+ /**
39
+ * 将 PostgreSQL 行数据转换为 SessionRecord
40
+ */
41
+ private rowToRecord;
42
+ /**
43
+ * 解析 JSON 字段 — pg 可能已自动解析 JSONB 列,也可能返回字符串
44
+ */
45
+ private parseJson;
46
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * PostgresSessionRepository — Session 持久化 PostgreSQL 实现
3
+ *
4
+ * 基于 pg 连接池实现 ISessionRepository 接口。
5
+ * JSON 字段(metadata)使用 JSONB 类型存储。
6
+ *
7
+ * @see design.md §1.3 数据模型 — sessions 表
8
+ * @see session.service.ts ISessionRepository 接口定义
9
+ */
10
+ // ─────────────────────────────────────────────
11
+ // PostgresSessionRepository
12
+ // ─────────────────────────────────────────────
13
+ export class PostgresSessionRepository {
14
+ pool;
15
+ constructor(pool) {
16
+ this.pool = pool;
17
+ }
18
+ /**
19
+ * INSERT session record with all fields including audit fields
20
+ */
21
+ async save(session) {
22
+ const sql = `
23
+ INSERT INTO sessions (id, user_id, agent_id, title, status, metadata, created_by, created_at, updated_by, updated_at)
24
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
25
+ `;
26
+ await this.pool.query(sql, [
27
+ session.id,
28
+ session.userId,
29
+ session.agentId,
30
+ session.title,
31
+ session.status,
32
+ JSON.stringify(session.metadata),
33
+ session.createdBy || 'system',
34
+ session.createdAt,
35
+ session.updatedBy || 'system',
36
+ session.updatedAt,
37
+ ]);
38
+ }
39
+ /**
40
+ * SELECT session by id, deserialize JSON fields
41
+ * Excludes soft-deleted records
42
+ */
43
+ async findById(id) {
44
+ const sql = `SELECT * FROM sessions WHERE id = $1 AND is_deleted = FALSE`;
45
+ const { rows } = await this.pool.query(sql, [id]);
46
+ if (rows.length === 0) {
47
+ return null;
48
+ }
49
+ return this.rowToRecord(rows[0]);
50
+ }
51
+ /**
52
+ * UPDATE all mutable fields by id
53
+ */
54
+ async findByUserId(userId, limit, offset) {
55
+ const sql = `SELECT * FROM sessions WHERE user_id = $1 AND is_deleted = false ORDER BY created_at DESC LIMIT $2 OFFSET $3`;
56
+ const result = await this.pool.query(sql, [userId, limit ?? 100, offset ?? 0]);
57
+ return result.rows.map((row) => this.rowToRecord(row));
58
+ }
59
+ async update(session) {
60
+ const sql = `
61
+ UPDATE sessions
62
+ SET title = $1, status = $2, metadata = $3, updated_by = $4, updated_at = $5
63
+ WHERE id = $6 AND is_deleted = FALSE
64
+ `;
65
+ await this.pool.query(sql, [
66
+ session.title,
67
+ session.status,
68
+ JSON.stringify(session.metadata),
69
+ session.updatedBy || 'system',
70
+ session.updatedAt,
71
+ session.id,
72
+ ]);
73
+ }
74
+ /**
75
+ * Soft delete session
76
+ */
77
+ async softDelete(id, deletedBy) {
78
+ const sql = `
79
+ UPDATE sessions
80
+ SET is_deleted = TRUE, deleted_by = $1, deleted_at = NOW()
81
+ WHERE id = $2 AND is_deleted = FALSE
82
+ `;
83
+ await this.pool.query(sql, [deletedBy, id]);
84
+ }
85
+ // ─────────────────────────────────────────────
86
+ // Private Helpers
87
+ // ─────────────────────────────────────────────
88
+ /**
89
+ * 将 PostgreSQL 行数据转换为 SessionRecord
90
+ */
91
+ rowToRecord(row) {
92
+ return {
93
+ id: row.id,
94
+ userId: row.user_id,
95
+ agentId: row.agent_id,
96
+ title: row.title,
97
+ status: row.status,
98
+ metadata: this.parseJson(row.metadata),
99
+ createdBy: row.created_by,
100
+ createdAt: row.created_at.toISOString(),
101
+ updatedBy: row.updated_by,
102
+ updatedAt: row.updated_at.toISOString(),
103
+ isDeleted: row.is_deleted,
104
+ deletedBy: row.deleted_by,
105
+ deletedAt: row.deleted_at?.toISOString(),
106
+ };
107
+ }
108
+ /**
109
+ * 解析 JSON 字段 — pg 可能已自动解析 JSONB 列,也可能返回字符串
110
+ */
111
+ parseJson(value) {
112
+ if (typeof value === 'string') {
113
+ return JSON.parse(value);
114
+ }
115
+ return value;
116
+ }
117
+ }