@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,97 @@
1
+ /**
2
+ * TokenBudgetGuard — Token 配额守卫
3
+ *
4
+ * 在每次 LLM/Tool 调用后执行配额检查:
5
+ * 1. 累加消耗到 task / session / agent 三级 scope
6
+ * 2. 检查三级配额是否耗尽
7
+ * 3. 若任一级耗尽,抛出 TokenBudgetExhaustedError,Graph 执行循环捕获后标记 Task 为 token_exhausted
8
+ *
9
+ * @see design.md §1.2 Token Budget检查(贯穿执行过程)
10
+ * @see requirements.md Requirement 12 AC2
11
+ */
12
+ // ─────────────────────────────────────────────
13
+ // TokenBudgetExhaustedError — 配额耗尽异常
14
+ // ─────────────────────────────────────────────
15
+ /**
16
+ * TokenBudgetExhaustedError — Token 配额耗尽时抛出
17
+ *
18
+ * Graph 执行循环应捕获此错误并将 Task 标记为 token_exhausted。
19
+ */
20
+ export class TokenBudgetExhaustedError extends Error {
21
+ /** 耗尽的配额作用域 */
22
+ scope;
23
+ /** 对应 scope 的实体 ID */
24
+ scopeId;
25
+ /** 已消耗 Token 数 */
26
+ consumed;
27
+ /** 配额上限 */
28
+ quota;
29
+ constructor(scope, scopeId, consumed, quota) {
30
+ super(`Token budget exhausted: scope=${scope}, scopeId=${scopeId}, consumed=${consumed}, quota=${quota}`);
31
+ this.name = 'TokenBudgetExhaustedError';
32
+ this.scope = scope;
33
+ this.scopeId = scopeId;
34
+ this.consumed = consumed;
35
+ this.quota = quota;
36
+ }
37
+ }
38
+ // ─────────────────────────────────────────────
39
+ // TokenBudgetGuard — 配额守卫实现
40
+ // ─────────────────────────────────────────────
41
+ /**
42
+ * TokenBudgetGuard — 每次 LLM/Tool 调用后的配额检查守卫
43
+ *
44
+ * 使用方式:在 Graph 执行循环中,每次 LLM/Tool 调用完成后调用 checkAndConsume。
45
+ * 若配额耗尽,将抛出 TokenBudgetExhaustedError,Graph 循环捕获后终止执行。
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const guard = new TokenBudgetGuard(budgetService);
50
+ * try {
51
+ * // ... LLM/Tool 调用 ...
52
+ * await guard.checkAndConsume(taskId, sessionId, agentCode, tokensUsed);
53
+ * } catch (e) {
54
+ * if (e instanceof TokenBudgetExhaustedError) {
55
+ * await taskService.updateStatus(taskId, 'token_exhausted');
56
+ * }
57
+ * }
58
+ * ```
59
+ */
60
+ export class TokenBudgetGuard {
61
+ budgetService;
62
+ constructor(budgetService) {
63
+ this.budgetService = budgetService;
64
+ }
65
+ /**
66
+ * 消耗并检查三级配额
67
+ *
68
+ * 执行顺序:
69
+ * 1. 对 task / session / agent 三个 scope 依次调用 consume 累加消耗
70
+ * 2. 按优先级 task → session → agent 检查是否耗尽
71
+ * 3. 任一级耗尽即抛出 TokenBudgetExhaustedError
72
+ *
73
+ * @param taskId - 当前 Task ID
74
+ * @param sessionId - 当前 Session ID
75
+ * @param agentCode - 当前 Agent ID
76
+ * @param amount - 本次调用消耗的 Token 数量
77
+ * @throws {TokenBudgetExhaustedError} 当任一级配额耗尽时
78
+ */
79
+ async checkAndConsume(taskId, sessionId, agentCode, amount) {
80
+ // 1. 对三个 scope 累加消耗
81
+ await this.budgetService.consume('task', taskId, amount);
82
+ await this.budgetService.consume('session', sessionId, amount);
83
+ await this.budgetService.consume('agent', agentCode, amount);
84
+ // 2. 按优先级检查:per-Task → per-Session → per-Agent
85
+ const scopes = [
86
+ { scope: 'task', scopeId: taskId },
87
+ { scope: 'session', scopeId: sessionId },
88
+ { scope: 'agent', scopeId: agentCode },
89
+ ];
90
+ for (const { scope, scopeId } of scopes) {
91
+ const result = await this.budgetService.check(scope, scopeId);
92
+ if (result.isExhausted) {
93
+ throw new TokenBudgetExhaustedError(scope, scopeId, result.consumed, result.quota);
94
+ }
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * TokenBudgetService — Token 配额控制服务实现
3
+ *
4
+ * 实现三级配额体系:
5
+ * - per-Task: 单次 Task 执行的 Token 上限 (per-execution)
6
+ * - per-Session: 会话级日预算 (daily)
7
+ * - per-Agent: 单次 Agent 执行 cap (per-execution)
8
+ *
9
+ * @see design.md §1.3 token_budgets 数据模型
10
+ * @see requirements.md Requirement 12 AC1-AC3
11
+ */
12
+ import type { ITokenBudgetService, BudgetScope, BudgetPeriod, BudgetCheckResult } from './contracts/index.js';
13
+ /**
14
+ * BudgetRecord — token_budgets 表对应的领域模型
15
+ */
16
+ export interface BudgetRecord {
17
+ id: string;
18
+ scope: BudgetScope;
19
+ scopeId: string;
20
+ quota: number;
21
+ consumed: number;
22
+ period: BudgetPeriod;
23
+ status: 'active' | 'exhausted';
24
+ createdBy: string;
25
+ createdAt: string;
26
+ updatedBy: string;
27
+ updatedAt: string;
28
+ isDeleted: boolean;
29
+ deletedBy?: string | null;
30
+ deletedAt?: string | null;
31
+ }
32
+ /**
33
+ * ITokenBudgetRepository — 配额记录持久化抽象
34
+ *
35
+ * 由 InMemoryTokenBudgetRepository(默认)或 MySQL 实现注入。
36
+ */
37
+ export interface ITokenBudgetRepository {
38
+ /**
39
+ * 获取或创建指定 scope + scopeId 的配额记录
40
+ */
41
+ getOrCreate(scope: BudgetScope, scopeId: string, defaultQuota: number, period: BudgetPeriod): Promise<BudgetRecord>;
42
+ /**
43
+ * 更新配额记录(consumed / status 等字段)
44
+ */
45
+ update(record: BudgetRecord): Promise<void>;
46
+ }
47
+ /**
48
+ * InMemoryTokenBudgetRepository — 基于 Map 的内存持久化
49
+ *
50
+ * 适用于单进程/测试场景。生产环境应替换为 MySQL 实现。
51
+ */
52
+ export declare class InMemoryTokenBudgetRepository implements ITokenBudgetRepository {
53
+ private store;
54
+ private buildKey;
55
+ getOrCreate(scope: BudgetScope, scopeId: string, defaultQuota: number, period: BudgetPeriod): Promise<BudgetRecord>;
56
+ update(record: BudgetRecord): Promise<void>;
57
+ }
58
+ /**
59
+ * 三级配额默认值配置
60
+ */
61
+ export interface TokenBudgetServiceOptions {
62
+ /** per-Task Token 上限(默认 100,000) */
63
+ taskQuota: number;
64
+ /** per-Session 日预算(默认 500,000) */
65
+ sessionDailyQuota: number;
66
+ /** per-Agent 单次执行 cap(默认 200,000) */
67
+ agentExecutionQuota: number;
68
+ }
69
+ /**
70
+ * TokenBudgetService — ITokenBudgetService 的具体实现
71
+ *
72
+ * 通过 ITokenBudgetRepository 管理配额记录,
73
+ * 支持三级配额:per-Task / per-Session(daily) / per-Agent(execution)。
74
+ */
75
+ export declare class TokenBudgetService implements ITokenBudgetService {
76
+ private readonly options;
77
+ private readonly repository;
78
+ constructor(repository: ITokenBudgetRepository, options?: Partial<TokenBudgetServiceOptions>);
79
+ /**
80
+ * 根据 scope 获取对应的默认配额上限
81
+ */
82
+ private getDefaultQuota;
83
+ check(scope: BudgetScope, scopeId: string): Promise<BudgetCheckResult>;
84
+ consume(scope: BudgetScope, scopeId: string, amount: number): Promise<void>;
85
+ isExhausted(scope: BudgetScope, scopeId: string): Promise<boolean>;
86
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * TokenBudgetService — Token 配额控制服务实现
3
+ *
4
+ * 实现三级配额体系:
5
+ * - per-Task: 单次 Task 执行的 Token 上限 (per-execution)
6
+ * - per-Session: 会话级日预算 (daily)
7
+ * - per-Agent: 单次 Agent 执行 cap (per-execution)
8
+ *
9
+ * @see design.md §1.3 token_budgets 数据模型
10
+ * @see requirements.md Requirement 12 AC1-AC3
11
+ */
12
+ // ─────────────────────────────────────────────
13
+ // InMemoryTokenBudgetRepository — 默认内存实现
14
+ // ─────────────────────────────────────────────
15
+ /**
16
+ * InMemoryTokenBudgetRepository — 基于 Map 的内存持久化
17
+ *
18
+ * 适用于单进程/测试场景。生产环境应替换为 MySQL 实现。
19
+ */
20
+ export class InMemoryTokenBudgetRepository {
21
+ store = new Map();
22
+ buildKey(scope, scopeId) {
23
+ return `${scope}:${scopeId}`;
24
+ }
25
+ async getOrCreate(scope, scopeId, defaultQuota, period) {
26
+ const key = this.buildKey(scope, scopeId);
27
+ const existing = this.store.get(key);
28
+ if (existing) {
29
+ return existing;
30
+ }
31
+ const now = new Date();
32
+ const record = {
33
+ id: `budget_${scope}_${scopeId}_${now.getTime()}`,
34
+ scope,
35
+ scopeId,
36
+ quota: defaultQuota,
37
+ consumed: 0,
38
+ period,
39
+ status: 'active',
40
+ createdBy: 'system',
41
+ createdAt: now.toISOString(),
42
+ updatedBy: 'system',
43
+ updatedAt: now.toISOString(),
44
+ isDeleted: false,
45
+ };
46
+ this.store.set(key, record);
47
+ return record;
48
+ }
49
+ async update(record) {
50
+ const key = this.buildKey(record.scope, record.scopeId);
51
+ record.updatedAt = new Date().toISOString();
52
+ this.store.set(key, record);
53
+ }
54
+ }
55
+ // ─────────────────────────────────────────────
56
+ // TokenBudgetService — 服务实现
57
+ // ─────────────────────────────────────────────
58
+ /**
59
+ * 根据 scope 推导对应的 BudgetPeriod
60
+ */
61
+ function scopeToPeriod(scope) {
62
+ switch (scope) {
63
+ case 'session':
64
+ return 'daily';
65
+ case 'task':
66
+ case 'agent':
67
+ return 'per-execution';
68
+ }
69
+ }
70
+ /**
71
+ * TokenBudgetService — ITokenBudgetService 的具体实现
72
+ *
73
+ * 通过 ITokenBudgetRepository 管理配额记录,
74
+ * 支持三级配额:per-Task / per-Session(daily) / per-Agent(execution)。
75
+ */
76
+ export class TokenBudgetService {
77
+ options;
78
+ repository;
79
+ constructor(repository, options) {
80
+ this.repository = repository;
81
+ this.options = {
82
+ taskQuota: options?.taskQuota ?? 100_000,
83
+ sessionDailyQuota: options?.sessionDailyQuota ?? 500_000,
84
+ agentExecutionQuota: options?.agentExecutionQuota ?? 200_000,
85
+ };
86
+ }
87
+ /**
88
+ * 根据 scope 获取对应的默认配额上限
89
+ */
90
+ getDefaultQuota(scope) {
91
+ switch (scope) {
92
+ case 'task':
93
+ return this.options.taskQuota;
94
+ case 'session':
95
+ return this.options.sessionDailyQuota;
96
+ case 'agent':
97
+ return this.options.agentExecutionQuota;
98
+ }
99
+ }
100
+ async check(scope, scopeId) {
101
+ const defaultQuota = this.getDefaultQuota(scope);
102
+ const period = scopeToPeriod(scope);
103
+ const record = await this.repository.getOrCreate(scope, scopeId, defaultQuota, period);
104
+ const remaining = Math.max(0, record.quota - record.consumed);
105
+ const isExhausted = record.consumed >= record.quota;
106
+ return {
107
+ quota: record.quota,
108
+ consumed: record.consumed,
109
+ remaining,
110
+ isExhausted,
111
+ period: record.period,
112
+ };
113
+ }
114
+ async consume(scope, scopeId, amount) {
115
+ const defaultQuota = this.getDefaultQuota(scope);
116
+ const period = scopeToPeriod(scope);
117
+ const record = await this.repository.getOrCreate(scope, scopeId, defaultQuota, period);
118
+ record.consumed += amount;
119
+ if (record.consumed >= record.quota) {
120
+ record.status = 'exhausted';
121
+ }
122
+ await this.repository.update(record);
123
+ }
124
+ async isExhausted(scope, scopeId) {
125
+ const defaultQuota = this.getDefaultQuota(scope);
126
+ const period = scopeToPeriod(scope);
127
+ const record = await this.repository.getOrCreate(scope, scopeId, defaultQuota, period);
128
+ return record.consumed >= record.quota;
129
+ }
130
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * TokenDetailMode — Token 统计输出粒度控制
3
+ *
4
+ * 通过 tokenDetail 参数控制 Token 消耗的 SSE 输出行为:
5
+ * - none: 不输出任何 Token 统计事件
6
+ * - summary: 仅 Task 结束时输出 stats.token_usage 汇总
7
+ * - detail: 每次 LLM 调用输出 stats.node_token + 结束时汇总
8
+ *
9
+ * `eap dev` 默认 detail;线上默认 summary。
10
+ *
11
+ * @see design.md §1.6 Token统计输出控制
12
+ * @see requirements.md Requirement 6 AC1
13
+ */
14
+ import type { ISSEEmitter } from '../sse/contracts/index.js';
15
+ import type { NodeTokenUsage, TaskTokenSummary } from './token-stats.service.js';
16
+ import { TokenStatsService } from './token-stats.service.js';
17
+ /**
18
+ * TokenDetailMode — tokenDetail 参数类型
19
+ *
20
+ * | 值 | 行为 | 场景 |
21
+ * |---------|----------------------------------------------|-------------------|
22
+ * | none | 不输出任何 Token 统计事件 | 生产环境前端 |
23
+ * | summary | 仅 Task 结束时输出 stats.token_usage 汇总 | 生产环境后台/API |
24
+ * | detail | 每次 LLM 调用输出 stats.node_token + 汇总 | 本地开发调试 |
25
+ */
26
+ export type TokenDetailMode = 'none' | 'summary' | 'detail';
27
+ /**
28
+ * TokenStatsEmitter — 整合 TokenStatsService 与 ISSEEmitter 的输出控制器
29
+ *
30
+ * 职责:
31
+ * 1. 始终记录 Token 消耗到 TokenStatsService(无论模式)
32
+ * 2. 根据 TokenDetailMode 有条件地通过 SSE 发射统计事件
33
+ *
34
+ * 用法:
35
+ * ```ts
36
+ * const emitter = new TokenStatsEmitter(statsService, sseEmitter, 'detail');
37
+ * // 每次 LLM 调用后
38
+ * emitter.recordAndEmit(taskId, usage, correlationId);
39
+ * // Task 结束时
40
+ * emitter.emitSummary(taskId, correlationId);
41
+ * ```
42
+ */
43
+ export declare class TokenStatsEmitter {
44
+ private readonly statsService;
45
+ private readonly sseEmitter;
46
+ private readonly mode;
47
+ constructor(statsService: TokenStatsService, sseEmitter: ISSEEmitter | null, mode: TokenDetailMode);
48
+ /**
49
+ * 记录 Token 消耗并按模式决定是否立即发射 stats.node_token 事件
50
+ *
51
+ * - 始终调用 statsService.record() 记录数据
52
+ * - mode='detail': 立即 emit stats.node_token SSE 事件
53
+ * - mode='none' / 'summary': 不 emit per-call 事件
54
+ *
55
+ * @param taskId - 所属 Task ID
56
+ * @param usage - 本次 LLM 调用的 Token 消耗
57
+ * @param correlationId - 请求关联 ID
58
+ */
59
+ recordAndEmit(taskId: string, usage: NodeTokenUsage, correlationId: string): void;
60
+ /**
61
+ * Task 结束时发射 stats.token_usage 汇总事件
62
+ *
63
+ * - mode='summary' / 'detail': emit stats.token_usage SSE 事件
64
+ * - mode='none': 不 emit
65
+ *
66
+ * @param taskId - 所属 Task ID
67
+ * @param correlationId - 请求关联 ID
68
+ * @returns 聚合后的 TaskTokenSummary(无论是否 emit 都返回,供业务层使用)
69
+ */
70
+ emitSummary(taskId: string, correlationId: string): TaskTokenSummary;
71
+ /** 获取当前输出模式 */
72
+ get detailMode(): TokenDetailMode;
73
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * TokenDetailMode — Token 统计输出粒度控制
3
+ *
4
+ * 通过 tokenDetail 参数控制 Token 消耗的 SSE 输出行为:
5
+ * - none: 不输出任何 Token 统计事件
6
+ * - summary: 仅 Task 结束时输出 stats.token_usage 汇总
7
+ * - detail: 每次 LLM 调用输出 stats.node_token + 结束时汇总
8
+ *
9
+ * `eap dev` 默认 detail;线上默认 summary。
10
+ *
11
+ * @see design.md §1.6 Token统计输出控制
12
+ * @see requirements.md Requirement 6 AC1
13
+ */
14
+ // ─────────────────────────────────────────────
15
+ // TokenStatsEmitter
16
+ // ─────────────────────────────────────────────
17
+ /**
18
+ * TokenStatsEmitter — 整合 TokenStatsService 与 ISSEEmitter 的输出控制器
19
+ *
20
+ * 职责:
21
+ * 1. 始终记录 Token 消耗到 TokenStatsService(无论模式)
22
+ * 2. 根据 TokenDetailMode 有条件地通过 SSE 发射统计事件
23
+ *
24
+ * 用法:
25
+ * ```ts
26
+ * const emitter = new TokenStatsEmitter(statsService, sseEmitter, 'detail');
27
+ * // 每次 LLM 调用后
28
+ * emitter.recordAndEmit(taskId, usage, correlationId);
29
+ * // Task 结束时
30
+ * emitter.emitSummary(taskId, correlationId);
31
+ * ```
32
+ */
33
+ export class TokenStatsEmitter {
34
+ statsService;
35
+ sseEmitter;
36
+ mode;
37
+ constructor(statsService, sseEmitter, mode) {
38
+ this.statsService = statsService;
39
+ this.sseEmitter = sseEmitter;
40
+ this.mode = mode;
41
+ }
42
+ /**
43
+ * 记录 Token 消耗并按模式决定是否立即发射 stats.node_token 事件
44
+ *
45
+ * - 始终调用 statsService.record() 记录数据
46
+ * - mode='detail': 立即 emit stats.node_token SSE 事件
47
+ * - mode='none' / 'summary': 不 emit per-call 事件
48
+ *
49
+ * @param taskId - 所属 Task ID
50
+ * @param usage - 本次 LLM 调用的 Token 消耗
51
+ * @param correlationId - 请求关联 ID
52
+ */
53
+ recordAndEmit(taskId, usage, correlationId) {
54
+ // 始终记录到统计服务
55
+ this.statsService.record(taskId, usage);
56
+ // detail 模式: 立即发射 per-call 事件
57
+ if (this.mode === 'detail' && this.sseEmitter) {
58
+ const event = {
59
+ type: 'stats.node_token',
60
+ data: {
61
+ nodeId: usage.nodeId,
62
+ model: usage.model,
63
+ inputTokens: usage.inputTokens,
64
+ outputTokens: usage.outputTokens,
65
+ costEstimate: usage.costEstimate,
66
+ },
67
+ correlationId,
68
+ taskId,
69
+ timestamp: new Date().toISOString(),
70
+ };
71
+ this.sseEmitter.emit(event);
72
+ }
73
+ }
74
+ /**
75
+ * Task 结束时发射 stats.token_usage 汇总事件
76
+ *
77
+ * - mode='summary' / 'detail': emit stats.token_usage SSE 事件
78
+ * - mode='none': 不 emit
79
+ *
80
+ * @param taskId - 所属 Task ID
81
+ * @param correlationId - 请求关联 ID
82
+ * @returns 聚合后的 TaskTokenSummary(无论是否 emit 都返回,供业务层使用)
83
+ */
84
+ emitSummary(taskId, correlationId) {
85
+ const summary = this.statsService.getTaskStats(taskId);
86
+ if ((this.mode === 'summary' || this.mode === 'detail') && this.sseEmitter) {
87
+ const event = {
88
+ type: 'stats.token_usage',
89
+ data: {
90
+ total: summary.total,
91
+ byNode: summary.byNode,
92
+ byModel: summary.byModel,
93
+ costEstimate: summary.costEstimate,
94
+ },
95
+ correlationId,
96
+ taskId,
97
+ timestamp: new Date().toISOString(),
98
+ };
99
+ this.sseEmitter.emit(event);
100
+ }
101
+ return summary;
102
+ }
103
+ /** 获取当前输出模式 */
104
+ get detailMode() {
105
+ return this.mode;
106
+ }
107
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * TiktokenEstimator — 基于 tiktoken 的 Token 估算器
3
+ *
4
+ * 提供更精确的 Token 计数,支持多种模型的 tokenizer。
5
+ * 当 tiktoken 不可用时,回退到基于字符的估算。
6
+ *
7
+ * @see message-compression.service.ts Token 估算
8
+ */
9
+ /**
10
+ * Token 估算器接口
11
+ */
12
+ export interface ITokenEstimator {
13
+ /**
14
+ * 估算文本的 Token 数
15
+ *
16
+ * @param text - 文本内容
17
+ * @returns Token 数
18
+ */
19
+ estimateTokens(text: string): number;
20
+ /**
21
+ * 估算消息列表的 Token 数
22
+ *
23
+ * @param messages - 消息列表
24
+ * @returns Token 数
25
+ */
26
+ estimateMessagesTokens(messages: Array<{
27
+ role: string;
28
+ content: string;
29
+ toolCalls?: unknown;
30
+ }>): number;
31
+ }
32
+ /**
33
+ * 基于字符的 Token 估算器
34
+ *
35
+ * 粗略但快速,适用于:
36
+ * - tiktoken 不可用时的回退方案
37
+ * - 对精度要求不高的场景
38
+ */
39
+ export declare class CharBasedTokenEstimator implements ITokenEstimator {
40
+ /**
41
+ * 估算文本的 Token 数
42
+ *
43
+ * 基于字符数估算:
44
+ * - 中文约 1.5 字符 = 1 Token
45
+ * - 英文约 4 字符 = 1 Token
46
+ */
47
+ estimateTokens(text: string): number;
48
+ estimateMessagesTokens(messages: Array<{
49
+ role: string;
50
+ content: string;
51
+ toolCalls?: unknown;
52
+ }>): number;
53
+ }
54
+ /**
55
+ * 模型特定的 Token 估算器
56
+ *
57
+ * 基于不同模型的 tokenizer 特性进行更精确的估算。
58
+ */
59
+ export declare class ModelBasedTokenEstimator implements ITokenEstimator {
60
+ private readonly model;
61
+ private readonly charsPerToken;
62
+ constructor(model?: string);
63
+ estimateTokens(text: string): number;
64
+ estimateMessagesTokens(messages: Array<{
65
+ role: string;
66
+ content: string;
67
+ toolCalls?: unknown;
68
+ }>): number;
69
+ /**
70
+ * 获取模型的字符/Token 比率
71
+ */
72
+ private getCharsPerToken;
73
+ }
74
+ /**
75
+ * 创建 Token 估算器
76
+ *
77
+ * @param model - 模型名称(可选)
78
+ * @returns Token 估算器实例
79
+ */
80
+ export declare function createTokenEstimator(model?: string): ITokenEstimator;