@fllf/agent-sdk 0.1.2 → 0.1.3

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 (266) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/README.md +824 -198
  3. package/dist/agent/Agent.d.ts +16 -5
  4. package/dist/agent/Agent.d.ts.map +1 -1
  5. package/dist/agent/Agent.js +283 -2
  6. package/dist/agent/Agent.js.map +1 -1
  7. package/dist/agent/index.d.ts +1 -1
  8. package/dist/agent/index.d.ts.map +1 -1
  9. package/dist/agent/types.d.ts +27 -3
  10. package/dist/agent/types.d.ts.map +1 -1
  11. package/dist/config/config.d.ts +22 -3
  12. package/dist/config/config.d.ts.map +1 -1
  13. package/dist/config/config.js +194 -47
  14. package/dist/config/config.js.map +1 -1
  15. package/dist/config/index.d.ts +1 -1
  16. package/dist/config/index.d.ts.map +1 -1
  17. package/dist/errors.d.ts +74 -0
  18. package/dist/errors.d.ts.map +1 -0
  19. package/dist/errors.js +186 -0
  20. package/dist/errors.js.map +1 -0
  21. package/dist/executors/base-executor.d.ts +14 -0
  22. package/dist/executors/base-executor.d.ts.map +1 -0
  23. package/dist/executors/base-executor.js +31 -0
  24. package/dist/executors/base-executor.js.map +1 -0
  25. package/dist/executors/base.d.ts +36 -5
  26. package/dist/executors/base.d.ts.map +1 -1
  27. package/dist/executors/chat-request-builder.d.ts +10 -0
  28. package/dist/executors/chat-request-builder.d.ts.map +1 -0
  29. package/dist/executors/chat-request-builder.js +96 -0
  30. package/dist/executors/chat-request-builder.js.map +1 -0
  31. package/dist/executors/index.d.ts +4 -1
  32. package/dist/executors/index.d.ts.map +1 -1
  33. package/dist/executors/index.js +6 -1
  34. package/dist/executors/index.js.map +1 -1
  35. package/dist/executors/rag-executor.js +1 -1
  36. package/dist/executors/rag-executor.js.map +1 -1
  37. package/dist/executors/simple-chat-executor.d.ts +4 -2
  38. package/dist/executors/simple-chat-executor.d.ts.map +1 -1
  39. package/dist/executors/simple-chat-executor.js +59 -57
  40. package/dist/executors/simple-chat-executor.js.map +1 -1
  41. package/dist/executors/tool-calling-executor.d.ts +20 -2
  42. package/dist/executors/tool-calling-executor.d.ts.map +1 -1
  43. package/dist/executors/tool-calling-executor.js +189 -91
  44. package/dist/executors/tool-calling-executor.js.map +1 -1
  45. package/dist/history/base.d.ts +55 -2
  46. package/dist/history/base.d.ts.map +1 -1
  47. package/dist/history/base.js +49 -0
  48. package/dist/history/base.js.map +1 -1
  49. package/dist/history/compression.d.ts +49 -0
  50. package/dist/history/compression.d.ts.map +1 -0
  51. package/dist/history/compression.js +53 -0
  52. package/dist/history/compression.js.map +1 -0
  53. package/dist/history/context-window.d.ts +33 -0
  54. package/dist/history/context-window.d.ts.map +1 -0
  55. package/dist/history/context-window.js +68 -0
  56. package/dist/history/context-window.js.map +1 -0
  57. package/dist/history/in-memory.d.ts +6 -4
  58. package/dist/history/in-memory.d.ts.map +1 -1
  59. package/dist/history/in-memory.js +25 -39
  60. package/dist/history/in-memory.js.map +1 -1
  61. package/dist/history/index.d.ts +9 -2
  62. package/dist/history/index.d.ts.map +1 -1
  63. package/dist/history/index.js +18 -1
  64. package/dist/history/index.js.map +1 -1
  65. package/dist/history/postgres/index.d.ts +4 -0
  66. package/dist/history/postgres/index.d.ts.map +1 -0
  67. package/dist/history/postgres/index.js +20 -0
  68. package/dist/history/postgres/index.js.map +1 -0
  69. package/dist/history/postgres/postgres-message-history-store.d.ts +35 -0
  70. package/dist/history/postgres/postgres-message-history-store.d.ts.map +1 -0
  71. package/dist/history/postgres/postgres-message-history-store.js +195 -0
  72. package/dist/history/postgres/postgres-message-history-store.js.map +1 -0
  73. package/dist/history/postgres/schema.d.ts +18 -0
  74. package/dist/history/postgres/schema.d.ts.map +1 -0
  75. package/dist/history/postgres/schema.js +46 -0
  76. package/dist/history/postgres/schema.js.map +1 -0
  77. package/dist/history/postgres/sql.d.ts +29 -0
  78. package/dist/history/postgres/sql.d.ts.map +1 -0
  79. package/dist/history/postgres/sql.js +102 -0
  80. package/dist/history/postgres/sql.js.map +1 -0
  81. package/dist/history/postgres/types.d.ts +20 -0
  82. package/dist/history/postgres/types.d.ts.map +1 -0
  83. package/dist/history/postgres/types.js +3 -0
  84. package/dist/history/postgres/types.js.map +1 -0
  85. package/dist/history/tool-pairing.d.ts +11 -0
  86. package/dist/history/tool-pairing.d.ts.map +1 -0
  87. package/dist/history/tool-pairing.js +52 -0
  88. package/dist/history/tool-pairing.js.map +1 -0
  89. package/dist/index.d.ts +2 -0
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +2 -0
  92. package/dist/index.js.map +1 -1
  93. package/dist/llm/LLM.d.ts +1 -0
  94. package/dist/llm/LLM.d.ts.map +1 -1
  95. package/dist/llm/LLM.js +136 -26
  96. package/dist/llm/LLM.js.map +1 -1
  97. package/dist/llm/errors.d.ts +11 -1
  98. package/dist/llm/errors.d.ts.map +1 -1
  99. package/dist/llm/errors.js +50 -1
  100. package/dist/llm/errors.js.map +1 -1
  101. package/dist/llm/factory.d.ts +14 -2
  102. package/dist/llm/factory.d.ts.map +1 -1
  103. package/dist/llm/factory.js +48 -9
  104. package/dist/llm/factory.js.map +1 -1
  105. package/dist/llm/index.d.ts +8 -3
  106. package/dist/llm/index.d.ts.map +1 -1
  107. package/dist/llm/index.js +10 -1
  108. package/dist/llm/index.js.map +1 -1
  109. package/dist/llm/providers/anthropic.d.ts +14 -0
  110. package/dist/llm/providers/anthropic.d.ts.map +1 -0
  111. package/dist/llm/providers/anthropic.js +336 -0
  112. package/dist/llm/providers/anthropic.js.map +1 -0
  113. package/dist/llm/providers/openai-compatible.d.ts +7 -0
  114. package/dist/llm/providers/openai-compatible.d.ts.map +1 -1
  115. package/dist/llm/providers/openai-compatible.js +151 -47
  116. package/dist/llm/providers/openai-compatible.js.map +1 -1
  117. package/dist/llm/stream-accumulator.d.ts +17 -0
  118. package/dist/llm/stream-accumulator.d.ts.map +1 -0
  119. package/dist/llm/stream-accumulator.js +83 -0
  120. package/dist/llm/stream-accumulator.js.map +1 -0
  121. package/dist/llm/tool-arguments.d.ts +6 -0
  122. package/dist/llm/tool-arguments.d.ts.map +1 -0
  123. package/dist/llm/tool-arguments.js +20 -0
  124. package/dist/llm/tool-arguments.js.map +1 -0
  125. package/dist/llm/types.d.ts +76 -4
  126. package/dist/llm/types.d.ts.map +1 -1
  127. package/dist/messages/content.d.ts +36 -0
  128. package/dist/messages/content.d.ts.map +1 -0
  129. package/dist/messages/content.js +70 -0
  130. package/dist/messages/content.js.map +1 -0
  131. package/dist/messages/index.d.ts +4 -2
  132. package/dist/messages/index.d.ts.map +1 -1
  133. package/dist/messages/index.js +10 -1
  134. package/dist/messages/index.js.map +1 -1
  135. package/dist/messages/message.d.ts +11 -9
  136. package/dist/messages/message.d.ts.map +1 -1
  137. package/dist/messages/message.js +69 -4
  138. package/dist/messages/message.js.map +1 -1
  139. package/dist/messages/types.d.ts +12 -0
  140. package/dist/messages/types.d.ts.map +1 -1
  141. package/dist/observability/collecting-observer.d.ts +8 -0
  142. package/dist/observability/collecting-observer.d.ts.map +1 -0
  143. package/dist/observability/collecting-observer.js +15 -0
  144. package/dist/observability/collecting-observer.js.map +1 -0
  145. package/dist/observability/index.d.ts +1 -0
  146. package/dist/observability/index.d.ts.map +1 -1
  147. package/dist/observability/index.js +3 -1
  148. package/dist/observability/index.js.map +1 -1
  149. package/dist/observability/observer.d.ts.map +1 -1
  150. package/dist/observability/observer.js +14 -1
  151. package/dist/observability/observer.js.map +1 -1
  152. package/dist/observability/types.d.ts +16 -1
  153. package/dist/observability/types.d.ts.map +1 -1
  154. package/dist/rag/chunking/auto-chunker.d.ts +7 -0
  155. package/dist/rag/chunking/auto-chunker.d.ts.map +1 -1
  156. package/dist/rag/chunking/auto-chunker.js +13 -0
  157. package/dist/rag/chunking/auto-chunker.js.map +1 -1
  158. package/dist/rag/chunking/chunker.d.ts.map +1 -1
  159. package/dist/rag/chunking/chunker.js +29 -5
  160. package/dist/rag/chunking/chunker.js.map +1 -1
  161. package/dist/rag/chunking/index.d.ts +2 -0
  162. package/dist/rag/chunking/index.d.ts.map +1 -1
  163. package/dist/rag/chunking/index.js +2 -0
  164. package/dist/rag/chunking/index.js.map +1 -1
  165. package/dist/rag/chunking/markdown-chunker.d.ts.map +1 -1
  166. package/dist/rag/chunking/markdown-chunker.js.map +1 -1
  167. package/dist/rag/chunking/qa-pair-chunker.d.ts +23 -0
  168. package/dist/rag/chunking/qa-pair-chunker.d.ts.map +1 -0
  169. package/dist/rag/chunking/qa-pair-chunker.js +162 -0
  170. package/dist/rag/chunking/qa-pair-chunker.js.map +1 -0
  171. package/dist/rag/chunking/semantic-chunker.d.ts +19 -0
  172. package/dist/rag/chunking/semantic-chunker.d.ts.map +1 -0
  173. package/dist/rag/chunking/semantic-chunker.js +291 -0
  174. package/dist/rag/chunking/semantic-chunker.js.map +1 -0
  175. package/dist/rag/embeddings/embedder.d.ts.map +1 -1
  176. package/dist/rag/embeddings/embedder.js +6 -0
  177. package/dist/rag/embeddings/embedder.js.map +1 -1
  178. package/dist/rag/generation/context-builder.d.ts +7 -0
  179. package/dist/rag/generation/context-builder.d.ts.map +1 -1
  180. package/dist/rag/generation/context-builder.js +4 -1
  181. package/dist/rag/generation/context-builder.js.map +1 -1
  182. package/dist/rag/ingestion/metadata.d.ts +6 -1
  183. package/dist/rag/ingestion/metadata.d.ts.map +1 -1
  184. package/dist/rag/ingestion/metadata.js +6 -2
  185. package/dist/rag/ingestion/metadata.js.map +1 -1
  186. package/dist/rag/pipeline.d.ts.map +1 -1
  187. package/dist/rag/pipeline.js +34 -11
  188. package/dist/rag/pipeline.js.map +1 -1
  189. package/dist/rag/retrieval/index.d.ts +1 -0
  190. package/dist/rag/retrieval/index.d.ts.map +1 -1
  191. package/dist/rag/retrieval/index.js +1 -0
  192. package/dist/rag/retrieval/index.js.map +1 -1
  193. package/dist/rag/retrieval/parent-child-expanding-retriever.d.ts +31 -0
  194. package/dist/rag/retrieval/parent-child-expanding-retriever.d.ts.map +1 -0
  195. package/dist/rag/retrieval/parent-child-expanding-retriever.js +194 -0
  196. package/dist/rag/retrieval/parent-child-expanding-retriever.js.map +1 -0
  197. package/dist/rag/stores/in-memory-keyword-store.d.ts.map +1 -1
  198. package/dist/rag/stores/in-memory-keyword-store.js +3 -8
  199. package/dist/rag/stores/in-memory-keyword-store.js.map +1 -1
  200. package/dist/rag/stores/keyword-tokenizer.d.ts +4 -0
  201. package/dist/rag/stores/keyword-tokenizer.d.ts.map +1 -0
  202. package/dist/rag/stores/keyword-tokenizer.js +113 -0
  203. package/dist/rag/stores/keyword-tokenizer.js.map +1 -0
  204. package/dist/rag/stores/postgres/pg-vector-store.d.ts.map +1 -1
  205. package/dist/rag/stores/postgres/pg-vector-store.js +21 -8
  206. package/dist/rag/stores/postgres/pg-vector-store.js.map +1 -1
  207. package/dist/rag/stores/postgres/postgres-document-store.d.ts.map +1 -1
  208. package/dist/rag/stores/postgres/postgres-document-store.js +26 -13
  209. package/dist/rag/stores/postgres/postgres-document-store.js.map +1 -1
  210. package/dist/rag/stores/postgres/postgres-keyword-store.d.ts.map +1 -1
  211. package/dist/rag/stores/postgres/postgres-keyword-store.js +43 -43
  212. package/dist/rag/stores/postgres/postgres-keyword-store.js.map +1 -1
  213. package/dist/rag/stores/postgres/sql.d.ts +22 -0
  214. package/dist/rag/stores/postgres/sql.d.ts.map +1 -1
  215. package/dist/rag/stores/postgres/sql.js +42 -0
  216. package/dist/rag/stores/postgres/sql.js.map +1 -1
  217. package/dist/rag/stores/types.d.ts +5 -0
  218. package/dist/rag/stores/types.d.ts.map +1 -1
  219. package/dist/rag/types.d.ts +6 -0
  220. package/dist/rag/types.d.ts.map +1 -1
  221. package/dist/testing/agent.d.ts +11 -0
  222. package/dist/testing/agent.d.ts.map +1 -0
  223. package/dist/testing/agent.js +45 -0
  224. package/dist/testing/agent.js.map +1 -0
  225. package/dist/testing/history-contract.d.ts +12 -0
  226. package/dist/testing/history-contract.d.ts.map +1 -0
  227. package/dist/testing/history-contract.js +111 -0
  228. package/dist/testing/history-contract.js.map +1 -0
  229. package/dist/testing/index.d.ts +11 -0
  230. package/dist/testing/index.d.ts.map +1 -0
  231. package/dist/testing/index.js +16 -0
  232. package/dist/testing/index.js.map +1 -0
  233. package/dist/testing/models.d.ts +34 -0
  234. package/dist/testing/models.d.ts.map +1 -0
  235. package/dist/testing/models.js +74 -0
  236. package/dist/testing/models.js.map +1 -0
  237. package/dist/testing/tool-schema.d.ts +6 -0
  238. package/dist/testing/tool-schema.d.ts.map +1 -0
  239. package/dist/testing/tool-schema.js +29 -0
  240. package/dist/testing/tool-schema.js.map +1 -0
  241. package/dist/testing/tools.d.ts +21 -0
  242. package/dist/testing/tools.d.ts.map +1 -0
  243. package/dist/testing/tools.js +43 -0
  244. package/dist/testing/tools.js.map +1 -0
  245. package/dist/tools/base.d.ts +38 -7
  246. package/dist/tools/base.d.ts.map +1 -1
  247. package/dist/tools/base.js +238 -11
  248. package/dist/tools/base.js.map +1 -1
  249. package/dist/tools/builtin/advancedSearchTool.d.ts.map +1 -1
  250. package/dist/tools/builtin/advancedSearchTool.js +30 -4
  251. package/dist/tools/builtin/advancedSearchTool.js.map +1 -1
  252. package/dist/tools/builtin/ragSearchTool.d.ts +6 -3
  253. package/dist/tools/builtin/ragSearchTool.d.ts.map +1 -1
  254. package/dist/tools/builtin/ragSearchTool.js +8 -6
  255. package/dist/tools/builtin/ragSearchTool.js.map +1 -1
  256. package/dist/tools/executor.d.ts +30 -2
  257. package/dist/tools/executor.d.ts.map +1 -1
  258. package/dist/tools/executor.js +83 -15
  259. package/dist/tools/executor.js.map +1 -1
  260. package/dist/tools/index.d.ts +3 -1
  261. package/dist/tools/index.d.ts.map +1 -1
  262. package/dist/tools/registry.d.ts +15 -3
  263. package/dist/tools/registry.d.ts.map +1 -1
  264. package/dist/tools/registry.js +21 -2
  265. package/dist/tools/registry.js.map +1 -1
  266. package/package.json +58 -4
@@ -0,0 +1,33 @@
1
+ import type { Message } from '../messages';
2
+ export interface TokenEstimator {
3
+ estimate(message: Message): number;
4
+ }
5
+ /**
6
+ * 无 tokenizer 依赖的近似估算:约 4 字符 = 1 token,再加每条消息的
7
+ * 固定协议开销和 toolCalls 参数的 JSON 体积。
8
+ * 结果偏保守(宁可高估),用于截断预算而非计费。
9
+ */
10
+ export declare class HeuristicTokenEstimator implements TokenEstimator {
11
+ private static readonly CHARS_PER_TOKEN;
12
+ private static readonly PER_MESSAGE_OVERHEAD;
13
+ estimate(message: Message): number;
14
+ }
15
+ export declare const defaultTokenEstimator: TokenEstimator;
16
+ export interface TokenBudgetSplit {
17
+ kept: Message[];
18
+ dropped: Message[];
19
+ }
20
+ /**
21
+ * truncateToTokenBudget 的可观察版本:除了保留的后缀,还返回被丢弃的
22
+ * 前缀,供上层(如 ContextCompressor)把旧消息压缩成摘要再注入。
23
+ * kept 与 truncateToTokenBudget 的结果完全一致(含 tool 配对修复),
24
+ * 因此 kept 永远是原序列的一个后缀,dropped 是对应的前缀。
25
+ */
26
+ export declare function splitByTokenBudget(messages: readonly Message[], maxTokens: number, estimator?: TokenEstimator): TokenBudgetSplit;
27
+ /**
28
+ * 从最新消息向前保留,直到 token 预算耗尽。
29
+ * 最新一条消息永远保留(即使超预算,请求也应该带上当前输入让 provider 报错,
30
+ * 而不是发出一个空消息列表)。截断后修复开头的孤儿 tool 上下文。
31
+ */
32
+ export declare function truncateToTokenBudget(messages: readonly Message[], maxTokens: number, estimator?: TokenEstimator): Message[];
33
+ //# sourceMappingURL=context-window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-window.d.ts","sourceRoot":"","sources":["../../src/history/context-window.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;CACtC;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,YAAW,cAAc;IAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAK;IAC5C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAK;IAEjD,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;CAerC;AAED,eAAO,MAAM,qBAAqB,EAAE,cAA8C,CAAC;AAEnF,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,OAAO,EAAE,OAAO,EAAE,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,cAAsC,GAClD,gBAAgB,CAOlB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACjC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,cAAsC,GAClD,OAAO,EAAE,CAqBX"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultTokenEstimator = exports.HeuristicTokenEstimator = void 0;
4
+ exports.splitByTokenBudget = splitByTokenBudget;
5
+ exports.truncateToTokenBudget = truncateToTokenBudget;
6
+ const messages_1 = require("../messages");
7
+ const tool_pairing_1 = require("./tool-pairing");
8
+ /**
9
+ * 无 tokenizer 依赖的近似估算:约 4 字符 = 1 token,再加每条消息的
10
+ * 固定协议开销和 toolCalls 参数的 JSON 体积。
11
+ * 结果偏保守(宁可高估),用于截断预算而非计费。
12
+ */
13
+ class HeuristicTokenEstimator {
14
+ static CHARS_PER_TOKEN = 4;
15
+ static PER_MESSAGE_OVERHEAD = 8;
16
+ estimate(message) {
17
+ let characters = (0, messages_1.contentToText)(message.content).length;
18
+ const toolCalls = message.metadata.toolCalls;
19
+ if (toolCalls !== undefined && toolCalls.length > 0) {
20
+ try {
21
+ characters += JSON.stringify(toolCalls).length;
22
+ }
23
+ catch {
24
+ characters += 256 * toolCalls.length;
25
+ }
26
+ }
27
+ return Math.ceil(characters / HeuristicTokenEstimator.CHARS_PER_TOKEN)
28
+ + HeuristicTokenEstimator.PER_MESSAGE_OVERHEAD;
29
+ }
30
+ }
31
+ exports.HeuristicTokenEstimator = HeuristicTokenEstimator;
32
+ exports.defaultTokenEstimator = new HeuristicTokenEstimator();
33
+ /**
34
+ * truncateToTokenBudget 的可观察版本:除了保留的后缀,还返回被丢弃的
35
+ * 前缀,供上层(如 ContextCompressor)把旧消息压缩成摘要再注入。
36
+ * kept 与 truncateToTokenBudget 的结果完全一致(含 tool 配对修复),
37
+ * 因此 kept 永远是原序列的一个后缀,dropped 是对应的前缀。
38
+ */
39
+ function splitByTokenBudget(messages, maxTokens, estimator = exports.defaultTokenEstimator) {
40
+ const kept = truncateToTokenBudget(messages, maxTokens, estimator);
41
+ return {
42
+ kept,
43
+ dropped: messages.slice(0, messages.length - kept.length),
44
+ };
45
+ }
46
+ /**
47
+ * 从最新消息向前保留,直到 token 预算耗尽。
48
+ * 最新一条消息永远保留(即使超预算,请求也应该带上当前输入让 provider 报错,
49
+ * 而不是发出一个空消息列表)。截断后修复开头的孤儿 tool 上下文。
50
+ */
51
+ function truncateToTokenBudget(messages, maxTokens, estimator = exports.defaultTokenEstimator) {
52
+ if (messages.length === 0 || maxTokens <= 0) {
53
+ return messages.length > 0 ? (0, tool_pairing_1.withRepairedLeadingToolContext)([messages[messages.length - 1]]) : [];
54
+ }
55
+ const kept = [];
56
+ let budget = maxTokens;
57
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
58
+ const message = messages[index];
59
+ const cost = estimator.estimate(message);
60
+ if (cost > budget && kept.length > 0) {
61
+ break;
62
+ }
63
+ kept.unshift(message);
64
+ budget -= cost;
65
+ }
66
+ return (0, tool_pairing_1.withRepairedLeadingToolContext)(kept);
67
+ }
68
+ //# sourceMappingURL=context-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-window.js","sourceRoot":"","sources":["../../src/history/context-window.ts"],"names":[],"mappings":";;;AA+CA,gDAWC;AAOD,sDAyBC;AA1FD,0CAA4C;AAE5C,iDAAgE;AAMhE;;;;GAIG;AACH,MAAa,uBAAuB;IACxB,MAAM,CAAU,eAAe,GAAG,CAAC,CAAC;IACpC,MAAM,CAAU,oBAAoB,GAAG,CAAC,CAAC;IAEjD,QAAQ,CAAC,OAAgB;QACrB,IAAI,UAAU,GAAG,IAAA,wBAAa,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QAEvD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC7C,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC;gBACD,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;YACnD,CAAC;YAAC,MAAM,CAAC;gBACL,UAAU,IAAI,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC;YACzC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,uBAAuB,CAAC,eAAe,CAAC;cAChE,uBAAuB,CAAC,oBAAoB,CAAC;IACvD,CAAC;;AAlBL,0DAmBC;AAEY,QAAA,qBAAqB,GAAmB,IAAI,uBAAuB,EAAE,CAAC;AAOnF;;;;;GAKG;AACH,SAAgB,kBAAkB,CAC9B,QAA4B,EAC5B,SAAiB,EACjB,YAA4B,6BAAqB;IAEjD,MAAM,IAAI,GAAG,qBAAqB,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAEnE,OAAO;QACH,IAAI;QACJ,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;KAC5D,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,SAAgB,qBAAqB,CACjC,QAA4B,EAC5B,SAAiB,EACjB,YAA4B,6BAAqB;IAEjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAC1C,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAA,6CAA8B,EAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvG,CAAC;IAED,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,IAAI,MAAM,GAAG,SAAS,CAAC;IAEvB,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3D,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAE,CAAC;QACjC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEzC,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM;QACV,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,IAAI,IAAI,CAAC;IACnB,CAAC;IAED,OAAO,IAAA,6CAA8B,EAAC,IAAI,CAAC,CAAC;AAChD,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { Message } from '../messages';
2
- import type { MessageHistory, MessageHistoryStore } from './base';
2
+ import type { MessageHistory, MessageHistoryAddOptions, MessageHistoryGetOptions, MessageHistoryStore } from './base';
3
3
  export interface InMemoryMessageHistoryOptions {
4
4
  maxMessages?: number;
5
5
  }
@@ -8,17 +8,19 @@ export interface InMemoryMessageHistoryStoreOptions extends InMemoryMessageHisto
8
8
  export declare class InMemoryMessageHistory implements MessageHistory {
9
9
  private readonly messages;
10
10
  private readonly maxMessages;
11
+ private version;
11
12
  constructor(options?: InMemoryMessageHistoryOptions);
12
13
  add(message: Message): Promise<void>;
13
- addMany(messages: Message[]): Promise<void>;
14
- get(): Promise<Message[]>;
14
+ addMany(messages: Message[], options?: MessageHistoryAddOptions): Promise<void>;
15
+ get(options?: MessageHistoryGetOptions): Promise<Message[]>;
15
16
  clear(): Promise<void>;
17
+ getVersion(): Promise<number>;
16
18
  }
17
19
  export declare class InMemoryMessageHistoryStore implements MessageHistoryStore {
18
20
  private readonly histories;
19
21
  private readonly options;
20
22
  constructor(options?: InMemoryMessageHistoryStoreOptions);
21
- get(sessionId: string): MessageHistory;
23
+ get(sessionId: string): InMemoryMessageHistory;
22
24
  clear(sessionId: string): Promise<void>;
23
25
  deleteSession(sessionId: string): Promise<void>;
24
26
  clearAll(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"in-memory.d.ts","sourceRoot":"","sources":["../../src/history/in-memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAElE,MAAM,WAAW,6BAA6B;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kCAAmC,SAAQ,6BAA6B;CAAG;AAE5F,qBAAa,sBAAuB,YAAW,cAAc;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,OAAO,GAAE,6BAAkC;IAIjD,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAU3C,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAIzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B;AAED,qBAAa,2BAA4B,YAAW,mBAAmB;IACnE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6C;IACvE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;gBAEjD,OAAO,GAAE,kCAAuC;IAI5D,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc;IAWhC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGlC"}
1
+ {"version":3,"file":"in-memory.d.ts","sourceRoot":"","sources":["../../src/history/in-memory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAItC,OAAO,KAAK,EACR,cAAc,EACd,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACtB,MAAM,QAAQ,CAAC;AAGhB,MAAM,WAAW,6BAA6B;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kCAAmC,SAAQ,6BAA6B;CAAG;AAE5F,qBAAa,sBAAuB,YAAW,cAAc;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,OAAO,CAAK;gBAER,OAAO,GAAE,6BAAkC;IAIjD,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBnF,GAAG,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAI/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;CAGtC;AAED,qBAAa,2BAA4B,YAAW,mBAAmB;IACnE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6C;IACvE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;gBAEjD,OAAO,GAAE,kCAAuC;IAI5D,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,sBAAsB;IAWxC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGlC"}
@@ -1,27 +1,48 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InMemoryMessageHistoryStore = exports.InMemoryMessageHistory = void 0;
4
+ const errors_1 = require("../errors");
5
+ const base_1 = require("./base");
6
+ const tool_pairing_1 = require("./tool-pairing");
4
7
  class InMemoryMessageHistory {
5
8
  messages = [];
6
9
  maxMessages;
10
+ version = 0;
7
11
  constructor(options = {}) {
8
12
  this.maxMessages = options.maxMessages ?? Number.POSITIVE_INFINITY;
9
13
  }
10
14
  async add(message) {
11
15
  await this.addMany([message]);
12
16
  }
13
- async addMany(messages) {
17
+ async addMany(messages, options = {}) {
18
+ // 空批次是完整 no-op:不做版本检查也不递增版本(与 Postgres 实现一致)。
19
+ if (messages.length === 0) {
20
+ return;
21
+ }
22
+ if (options.expectedVersion !== undefined && options.expectedVersion !== this.version) {
23
+ throw new errors_1.HistoryVersionConflictError({
24
+ expectedVersion: options.expectedVersion,
25
+ actualVersion: this.version,
26
+ });
27
+ }
14
28
  this.messages.push(...messages);
15
29
  if (this.messages.length > this.maxMessages) {
16
30
  this.messages.splice(0, this.messages.length - this.maxMessages);
17
31
  }
18
- removeInvalidLeadingToolContext(this.messages);
32
+ (0, tool_pairing_1.repairLeadingToolContext)(this.messages);
33
+ this.version += 1;
19
34
  }
20
- async get() {
21
- return [...this.messages];
35
+ async get(options = {}) {
36
+ return (0, base_1.applyMessageHistoryWindow)(this.messages, options);
22
37
  }
23
38
  async clear() {
24
39
  this.messages.length = 0;
40
+ // clear 递增而非重置版本:若重置为 0,"读到 v → 清空 → 重写"的 ABA
41
+ // 序列会让持有旧版本号的 CAS 写入意外成功。
42
+ this.version += 1;
43
+ }
44
+ async getVersion() {
45
+ return this.version;
25
46
  }
26
47
  }
27
48
  exports.InMemoryMessageHistory = InMemoryMessageHistory;
@@ -50,39 +71,4 @@ class InMemoryMessageHistoryStore {
50
71
  }
51
72
  }
52
73
  exports.InMemoryMessageHistoryStore = InMemoryMessageHistoryStore;
53
- function removeInvalidLeadingToolContext(messages) {
54
- while (messages.length > 0) {
55
- const firstMessage = messages[0];
56
- if (firstMessage?.role === 'tool') {
57
- messages.shift();
58
- continue;
59
- }
60
- if (firstMessage === undefined || !hasToolCalls(firstMessage)) {
61
- return;
62
- }
63
- const toolCalls = firstMessage.metadata.toolCalls ?? [];
64
- const toolResponseEnd = findFollowingToolResponseEnd(messages);
65
- const toolResponseIds = new Set(messages
66
- .slice(1, toolResponseEnd)
67
- .map((message) => message.metadata.toolCallId)
68
- .filter((toolCallId) => toolCallId !== undefined));
69
- const hasAllToolResponses = toolCalls.every((toolCall) => (toolResponseIds.has(toolCall.id)));
70
- if (hasAllToolResponses) {
71
- return;
72
- }
73
- messages.splice(0, toolResponseEnd);
74
- }
75
- }
76
- function hasToolCalls(message) {
77
- return message.role === 'assistant'
78
- && message.metadata.toolCalls !== undefined
79
- && message.metadata.toolCalls.length > 0;
80
- }
81
- function findFollowingToolResponseEnd(messages) {
82
- let index = 1;
83
- while (messages[index]?.role === 'tool') {
84
- index += 1;
85
- }
86
- return index;
87
- }
88
74
  //# sourceMappingURL=in-memory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"in-memory.js","sourceRoot":"","sources":["../../src/history/in-memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"in-memory.js","sourceRoot":"","sources":["../../src/history/in-memory.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,12 @@
1
- export { DEFAULT_SESSION_ID, normalizeSessionId, } from './base';
1
+ export { applyMessageHistoryWindow, assertValidMessageHistoryLimit, DEFAULT_SESSION_ID, normalizeSessionId, parseMessageHistoryBefore, } from './base';
2
+ export { SummarizingContextCompressor } from './compression';
3
+ export type { ContextCompressor, ContextCompressorInput, SummarizingContextCompressorOptions, } from './compression';
4
+ export { defaultTokenEstimator, HeuristicTokenEstimator, splitByTokenBudget, truncateToTokenBudget, } from './context-window';
5
+ export type { TokenBudgetSplit, TokenEstimator, } from './context-window';
2
6
  export { InMemoryMessageHistory, InMemoryMessageHistoryStore, } from './in-memory';
3
- export type { MessageHistory, MessageHistoryStore, } from './base';
7
+ export { createPostgresMessageHistorySchemaSql, PostgresMessageHistory, PostgresMessageHistoryStore, } from './postgres';
8
+ export { repairLeadingToolContext, withRepairedLeadingToolContext, } from './tool-pairing';
9
+ export type { MessageHistory, MessageHistoryAddOptions, MessageHistoryGetOptions, MessageHistoryStore, } from './base';
4
10
  export type { InMemoryMessageHistoryOptions, InMemoryMessageHistoryStoreOptions, } from './in-memory';
11
+ export type { PostgresHistoryTableNames, PostgresMessageHistorySchemaOptions, PostgresMessageHistoryStoreOptions, PostgresQueryExecutor, PostgresQueryResult, } from './postgres';
5
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,kBAAkB,EAClB,kBAAkB,GACrB,MAAM,QAAQ,CAAC;AAChB,OAAO,EACH,sBAAsB,EACtB,2BAA2B,GAC9B,MAAM,aAAa,CAAC;AACrB,YAAY,EACR,cAAc,EACd,mBAAmB,GACtB,MAAM,QAAQ,CAAC;AAChB,YAAY,EACR,6BAA6B,EAC7B,kCAAkC,GACrC,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,yBAAyB,EACzB,8BAA8B,EAC9B,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,GAC5B,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EACR,iBAAiB,EACjB,sBAAsB,EACtB,mCAAmC,GACtC,MAAM,eAAe,CAAC;AACvB,OAAO,EACH,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACR,gBAAgB,EAChB,cAAc,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACH,sBAAsB,EACtB,2BAA2B,GAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,EACH,qCAAqC,EACrC,sBAAsB,EACtB,2BAA2B,GAC9B,MAAM,YAAY,CAAC;AACpB,OAAO,EACH,wBAAwB,EACxB,8BAA8B,GACjC,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACR,cAAc,EACd,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,GACtB,MAAM,QAAQ,CAAC;AAChB,YAAY,EACR,6BAA6B,EAC7B,kCAAkC,GACrC,MAAM,aAAa,CAAC;AACrB,YAAY,EACR,yBAAyB,EACzB,mCAAmC,EACnC,kCAAkC,EAClC,qBAAqB,EACrB,mBAAmB,GACtB,MAAM,YAAY,CAAC"}
@@ -1,10 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InMemoryMessageHistoryStore = exports.InMemoryMessageHistory = exports.normalizeSessionId = exports.DEFAULT_SESSION_ID = void 0;
3
+ exports.withRepairedLeadingToolContext = exports.repairLeadingToolContext = exports.PostgresMessageHistoryStore = exports.PostgresMessageHistory = exports.createPostgresMessageHistorySchemaSql = exports.InMemoryMessageHistoryStore = exports.InMemoryMessageHistory = exports.truncateToTokenBudget = exports.splitByTokenBudget = exports.HeuristicTokenEstimator = exports.defaultTokenEstimator = exports.SummarizingContextCompressor = exports.parseMessageHistoryBefore = exports.normalizeSessionId = exports.DEFAULT_SESSION_ID = exports.assertValidMessageHistoryLimit = exports.applyMessageHistoryWindow = void 0;
4
4
  var base_1 = require("./base");
5
+ Object.defineProperty(exports, "applyMessageHistoryWindow", { enumerable: true, get: function () { return base_1.applyMessageHistoryWindow; } });
6
+ Object.defineProperty(exports, "assertValidMessageHistoryLimit", { enumerable: true, get: function () { return base_1.assertValidMessageHistoryLimit; } });
5
7
  Object.defineProperty(exports, "DEFAULT_SESSION_ID", { enumerable: true, get: function () { return base_1.DEFAULT_SESSION_ID; } });
6
8
  Object.defineProperty(exports, "normalizeSessionId", { enumerable: true, get: function () { return base_1.normalizeSessionId; } });
9
+ Object.defineProperty(exports, "parseMessageHistoryBefore", { enumerable: true, get: function () { return base_1.parseMessageHistoryBefore; } });
10
+ var compression_1 = require("./compression");
11
+ Object.defineProperty(exports, "SummarizingContextCompressor", { enumerable: true, get: function () { return compression_1.SummarizingContextCompressor; } });
12
+ var context_window_1 = require("./context-window");
13
+ Object.defineProperty(exports, "defaultTokenEstimator", { enumerable: true, get: function () { return context_window_1.defaultTokenEstimator; } });
14
+ Object.defineProperty(exports, "HeuristicTokenEstimator", { enumerable: true, get: function () { return context_window_1.HeuristicTokenEstimator; } });
15
+ Object.defineProperty(exports, "splitByTokenBudget", { enumerable: true, get: function () { return context_window_1.splitByTokenBudget; } });
16
+ Object.defineProperty(exports, "truncateToTokenBudget", { enumerable: true, get: function () { return context_window_1.truncateToTokenBudget; } });
7
17
  var in_memory_1 = require("./in-memory");
8
18
  Object.defineProperty(exports, "InMemoryMessageHistory", { enumerable: true, get: function () { return in_memory_1.InMemoryMessageHistory; } });
9
19
  Object.defineProperty(exports, "InMemoryMessageHistoryStore", { enumerable: true, get: function () { return in_memory_1.InMemoryMessageHistoryStore; } });
20
+ var postgres_1 = require("./postgres");
21
+ Object.defineProperty(exports, "createPostgresMessageHistorySchemaSql", { enumerable: true, get: function () { return postgres_1.createPostgresMessageHistorySchemaSql; } });
22
+ Object.defineProperty(exports, "PostgresMessageHistory", { enumerable: true, get: function () { return postgres_1.PostgresMessageHistory; } });
23
+ Object.defineProperty(exports, "PostgresMessageHistoryStore", { enumerable: true, get: function () { return postgres_1.PostgresMessageHistoryStore; } });
24
+ var tool_pairing_1 = require("./tool-pairing");
25
+ Object.defineProperty(exports, "repairLeadingToolContext", { enumerable: true, get: function () { return tool_pairing_1.repairLeadingToolContext; } });
26
+ Object.defineProperty(exports, "withRepairedLeadingToolContext", { enumerable: true, get: function () { return tool_pairing_1.withRepairedLeadingToolContext; } });
10
27
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":";;;AAAA,+BAGgB;AAFZ,0GAAA,kBAAkB,OAAA;AAClB,0GAAA,kBAAkB,OAAA;AAEtB,yCAGqB;AAFjB,mHAAA,sBAAsB,OAAA;AACtB,wHAAA,2BAA2B,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":";;;AAAA,+BAMgB;AALZ,iHAAA,yBAAyB,OAAA;AACzB,sHAAA,8BAA8B,OAAA;AAC9B,0GAAA,kBAAkB,OAAA;AAClB,0GAAA,kBAAkB,OAAA;AAClB,iHAAA,yBAAyB,OAAA;AAE7B,6CAA6D;AAApD,2HAAA,4BAA4B,OAAA;AAMrC,mDAK0B;AAJtB,uHAAA,qBAAqB,OAAA;AACrB,yHAAA,uBAAuB,OAAA;AACvB,oHAAA,kBAAkB,OAAA;AAClB,uHAAA,qBAAqB,OAAA;AAMzB,yCAGqB;AAFjB,mHAAA,sBAAsB,OAAA;AACtB,wHAAA,2BAA2B,OAAA;AAE/B,uCAIoB;AAHhB,iIAAA,qCAAqC,OAAA;AACrC,kHAAA,sBAAsB,OAAA;AACtB,uHAAA,2BAA2B,OAAA;AAE/B,+CAGwB;AAFpB,wHAAA,wBAAwB,OAAA;AACxB,8HAAA,8BAA8B,OAAA"}
@@ -0,0 +1,4 @@
1
+ export * from './types';
2
+ export * from './schema';
3
+ export * from './postgres-message-history-store';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/history/postgres/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,kCAAkC,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./schema"), exports);
19
+ __exportStar(require("./postgres-message-history-store"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/history/postgres/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,2CAAyB;AACzB,mEAAiD"}
@@ -0,0 +1,35 @@
1
+ import type { Message } from '../../messages';
2
+ import type { MessageHistory, MessageHistoryAddOptions, MessageHistoryGetOptions, MessageHistoryStore } from '../base';
3
+ import type { PostgresHistoryTableNames, PostgresMessageHistoryStoreOptions, PostgresQueryExecutor } from './types';
4
+ /**
5
+ * 参考级 Postgres 消息历史。设计约束:
6
+ *
7
+ * - 只依赖注入的 query(sql, params)(可直接传 pg.Pool),不使用客户端事务
8
+ * API——调用方传进来的可能就是连接池,每次 query 可能落在不同连接上。
9
+ * - 因此所有需要原子性的写路径都压缩为单条 SQL 语句(data-modifying CTE),
10
+ * 单条语句在 Postgres 里天然具备事务语义。
11
+ * - 乐观并发:addMany 带 expectedVersion 时用
12
+ * UPDATE ... SET version = version + 1 WHERE session_id = $1 AND version = $2
13
+ * RETURNING version 的 CAS 模式,无行返回即版本冲突。
14
+ */
15
+ export declare class PostgresMessageHistory implements MessageHistory {
16
+ private readonly db;
17
+ private readonly tables;
18
+ private readonly sessionId;
19
+ constructor(db: PostgresQueryExecutor, tables: PostgresHistoryTableNames, sessionId: string);
20
+ add(message: Message): Promise<void>;
21
+ addMany(messages: Message[], options?: MessageHistoryAddOptions): Promise<void>;
22
+ get(options?: MessageHistoryGetOptions): Promise<Message[]>;
23
+ clear(): Promise<void>;
24
+ getVersion(): Promise<number>;
25
+ }
26
+ export declare class PostgresMessageHistoryStore implements MessageHistoryStore {
27
+ private readonly db;
28
+ private readonly tables;
29
+ constructor(options: PostgresMessageHistoryStoreOptions);
30
+ get(sessionId: string): PostgresMessageHistory;
31
+ clear(sessionId: string): Promise<void>;
32
+ deleteSession(sessionId: string): Promise<void>;
33
+ clearAll(): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=postgres-message-history-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-message-history-store.d.ts","sourceRoot":"","sources":["../../../src/history/postgres/postgres-message-history-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,KAAK,EACR,cAAc,EACd,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACtB,MAAM,SAAS,CAAC;AAQjB,OAAO,KAAK,EACR,yBAAyB,EACzB,kCAAkC,EAClC,qBAAqB,EACxB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;GAUG;AACH,qBAAa,sBAAuB,YAAW,cAAc;IACzD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAwB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAG/B,EAAE,EAAE,qBAAqB,EACzB,MAAM,EAAE,yBAAyB,EACjC,SAAS,EAAE,MAAM;IAOf,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,IAAI,CAAC;IAoCnF,GAAG,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IA2C/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;CAQtC;AAED,qBAAa,2BAA4B,YAAW,mBAAmB;IACnE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAwB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;gBAEvC,OAAO,EAAE,kCAAkC;IAKvD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,sBAAsB;IAKxC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGlC"}
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgresMessageHistoryStore = exports.PostgresMessageHistory = void 0;
4
+ const errors_1 = require("../../errors");
5
+ const base_1 = require("../base");
6
+ const tool_pairing_1 = require("../tool-pairing");
7
+ const sql_1 = require("./sql");
8
+ /**
9
+ * 参考级 Postgres 消息历史。设计约束:
10
+ *
11
+ * - 只依赖注入的 query(sql, params)(可直接传 pg.Pool),不使用客户端事务
12
+ * API——调用方传进来的可能就是连接池,每次 query 可能落在不同连接上。
13
+ * - 因此所有需要原子性的写路径都压缩为单条 SQL 语句(data-modifying CTE),
14
+ * 单条语句在 Postgres 里天然具备事务语义。
15
+ * - 乐观并发:addMany 带 expectedVersion 时用
16
+ * UPDATE ... SET version = version + 1 WHERE session_id = $1 AND version = $2
17
+ * RETURNING version 的 CAS 模式,无行返回即版本冲突。
18
+ */
19
+ class PostgresMessageHistory {
20
+ db;
21
+ tables;
22
+ sessionId;
23
+ constructor(db, tables, sessionId) {
24
+ this.db = db;
25
+ this.tables = tables;
26
+ this.sessionId = sessionId;
27
+ }
28
+ async add(message) {
29
+ await this.addMany([message]);
30
+ }
31
+ async addMany(messages, options = {}) {
32
+ // 空批次是完整 no-op:不做版本检查也不递增版本(与内存实现一致)。
33
+ if (messages.length === 0) {
34
+ return;
35
+ }
36
+ const expectedVersion = options.expectedVersion;
37
+ const statement = buildAddManyStatement(this.tables, this.sessionId, messages, expectedVersion);
38
+ const result = await this.db.query(statement.text, statement.values);
39
+ if (result.rows.length > 0) {
40
+ return;
41
+ }
42
+ if (expectedVersion === undefined) {
43
+ // 无条件写入(INSERT ... ON CONFLICT DO UPDATE)总会返回一行,
44
+ // 走到这里说明执行器行为异常,而不是版本冲突。
45
+ throw new errors_1.HistoryError('Postgres message history write returned no version row.', {
46
+ metadata: {
47
+ sessionId: this.sessionId,
48
+ },
49
+ });
50
+ }
51
+ throw new errors_1.HistoryVersionConflictError({
52
+ expectedVersion,
53
+ actualVersion: await this.getVersion(),
54
+ sessionId: this.sessionId,
55
+ });
56
+ }
57
+ async get(options = {}) {
58
+ const values = [this.sessionId];
59
+ const conditions = ['session_id = $1'];
60
+ if (options.before !== undefined) {
61
+ values.push((0, base_1.parseMessageHistoryBefore)(options.before).toISOString());
62
+ conditions.push(`"timestamp" < $${values.length}::timestamptz`);
63
+ }
64
+ let limitClause = '';
65
+ if (options.limit !== undefined) {
66
+ (0, base_1.assertValidMessageHistoryLimit)(options.limit);
67
+ if (options.limit === 0) {
68
+ return [];
69
+ }
70
+ values.push(options.limit);
71
+ limitClause = `\nLIMIT $${values.length}`;
72
+ }
73
+ // limit 语义是「最近 N 条」:SQL 侧按 seq 倒序截断,Node 侧再翻回正序。
74
+ const orderDirection = options.limit === undefined ? 'ASC' : 'DESC';
75
+ const result = await this.db.query(`
76
+ SELECT role, content, "timestamp", metadata
77
+ FROM ${this.tables.messages}
78
+ WHERE ${conditions.join(' AND ')}
79
+ ORDER BY seq ${orderDirection}${limitClause}
80
+ `.trim(), values);
81
+ const messages = result.rows.map(sql_1.rowToMessage);
82
+ if (options.limit !== undefined) {
83
+ messages.reverse();
84
+ // 与内存实现一致:limit 切片可能砍在 assistant(toolCalls)/tool
85
+ // 配对中间,修复窗口开头的孤儿 tool 上下文。
86
+ (0, tool_pairing_1.repairLeadingToolContext)(messages);
87
+ }
88
+ return messages;
89
+ }
90
+ async clear() {
91
+ // 单条语句内完成「版本 +1 + 删除消息」,共享同一事务语义。
92
+ // clear 递增而非重置版本:防止 "读到 v → 清空 → 重写" 的 ABA 序列
93
+ // 让持有旧版本号的 CAS 写入意外成功。
94
+ await this.db.query(`
95
+ WITH bump AS (
96
+ UPDATE ${this.tables.sessions}
97
+ SET version = version + 1
98
+ WHERE session_id = $1
99
+ RETURNING version
100
+ )
101
+ DELETE FROM ${this.tables.messages}
102
+ WHERE session_id = $1
103
+ `.trim(), [this.sessionId]);
104
+ }
105
+ async getVersion() {
106
+ const result = await this.db.query(`SELECT version FROM ${this.tables.sessions} WHERE session_id = $1`, [this.sessionId]);
107
+ return (0, sql_1.readVersionColumn)(result.rows[0]?.version);
108
+ }
109
+ }
110
+ exports.PostgresMessageHistory = PostgresMessageHistory;
111
+ class PostgresMessageHistoryStore {
112
+ db;
113
+ tables;
114
+ constructor(options) {
115
+ this.db = options.db;
116
+ this.tables = (0, sql_1.resolvePostgresHistoryTableNames)(options.tablePrefix);
117
+ }
118
+ get(sessionId) {
119
+ // 无进程内状态,按需构造轻量句柄即可;会话状态全部在数据库里。
120
+ return new PostgresMessageHistory(this.db, this.tables, sessionId);
121
+ }
122
+ async clear(sessionId) {
123
+ await this.get(sessionId).clear();
124
+ }
125
+ async deleteSession(sessionId) {
126
+ // ON DELETE CASCADE 级联删除消息;会话行删除后版本从 0 重新开始。
127
+ await this.db.query(`DELETE FROM ${this.tables.sessions} WHERE session_id = $1`, [sessionId]);
128
+ }
129
+ async clearAll() {
130
+ await this.db.query(`DELETE FROM ${this.tables.sessions}`);
131
+ }
132
+ }
133
+ exports.PostgresMessageHistoryStore = PostgresMessageHistoryStore;
134
+ /**
135
+ * 生成单条 addMany 语句:版本检查/自增 + multi-row 批量插入全部放进同一条
136
+ * data-modifying CTE,天然原子,不依赖调用方的事务 API。
137
+ *
138
+ * - expectedVersion 为 N>0:UPDATE ... WHERE version = $2 RETURNING version,
139
+ * 无行返回即冲突(会话不存在同样视为冲突,实际版本按 0 处理)。
140
+ * - expectedVersion 为 0:首次写入,INSERT ... ON CONFLICT (session_id)
141
+ * DO UPDATE ... WHERE s.version = 0,同时兼容「行不存在」与「行存在但
142
+ * 从未成功写入」两种状态。
143
+ * - 未提供 expectedVersion:INSERT ... ON CONFLICT DO UPDATE 无条件自增,
144
+ * 总是成功,退化为 last-writer-wins 追加。
145
+ *
146
+ * 消息插入通过 CROSS JOIN cas 与版本检查联动:cas 无行时一条消息也不会
147
+ * 插入。seq 由 IDENTITY 生成,ORDER BY nm.ord 保证批内顺序与入参一致。
148
+ * 单条 addMany 不做分批:一次调用只对应一次版本 +1;每条消息 4 个参数,
149
+ * Postgres 协议 65535 个参数的上限足以容纳现实的单轮写入量。
150
+ */
151
+ function buildAddManyStatement(tables, sessionId, messages, expectedVersion) {
152
+ const values = [sessionId];
153
+ let casSql;
154
+ if (expectedVersion === undefined || expectedVersion === 0) {
155
+ const casGuard = expectedVersion === 0 ? '\n WHERE s.version = 0' : '';
156
+ casSql = `
157
+ INSERT INTO ${tables.sessions} AS s (session_id, version)
158
+ VALUES ($1, 1)
159
+ ON CONFLICT (session_id) DO UPDATE SET version = s.version + 1${casGuard}
160
+ RETURNING version`;
161
+ }
162
+ else {
163
+ values.push(expectedVersion);
164
+ casSql = `
165
+ UPDATE ${tables.sessions}
166
+ SET version = version + 1
167
+ WHERE session_id = $1 AND version = $2
168
+ RETURNING version`;
169
+ }
170
+ const rows = messages.map((message, index) => {
171
+ const json = message.toJSON();
172
+ const base = values.length;
173
+ values.push(json.role, (0, sql_1.createJson)(json.content), json.timestamp, (0, sql_1.createJson)(json.metadata));
174
+ return ` (${index + 1}, $${base + 1}, $${base + 2}::jsonb, $${base + 3}::timestamptz, $${base + 4}::jsonb)`;
175
+ });
176
+ const text = `
177
+ WITH cas AS (${casSql}
178
+ ),
179
+ new_messages (ord, role, content, "timestamp", metadata) AS (
180
+ VALUES
181
+ ${rows.join(',\n')}
182
+ ),
183
+ inserted AS (
184
+ INSERT INTO ${tables.messages} (session_id, role, content, "timestamp", metadata)
185
+ SELECT $1, nm.role, nm.content, nm."timestamp", nm.metadata
186
+ FROM new_messages AS nm
187
+ CROSS JOIN cas
188
+ ORDER BY nm.ord
189
+ )
190
+ SELECT cas.version AS version
191
+ FROM cas
192
+ `.trim();
193
+ return { text, values };
194
+ }
195
+ //# sourceMappingURL=postgres-message-history-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-message-history-store.js","sourceRoot":"","sources":["../../../src/history/postgres/postgres-message-history-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export interface PostgresMessageHistorySchemaOptions {
2
+ tablePrefix?: string;
3
+ createIndexes?: boolean;
4
+ }
5
+ /**
6
+ * 消息历史建表 SQL。设计约束:
7
+ *
8
+ * - sessions.version 是乐观并发的 CAS 目标:0 表示尚无成功写入,
9
+ * 每次成功 addMany +1(clear 也 +1,防止版本回卷造成 ABA)。
10
+ * - messages.seq 用全局 IDENTITY 而不是 per-session 连续序号:READ COMMITTED
11
+ * 下单条语句的快照看不到并发已提交的行,无法无竞态地计算 MAX(seq)+1;
12
+ * IDENTITY 保证全局唯一且批内有序。因此 seq 在会话内单调递增但不保证连续,
13
+ * 排序语义不受影响。
14
+ * - content 直接存 Message.toJSON() 的 content 字段:字符串与 block 数组
15
+ * 都能落进 jsonb。
16
+ */
17
+ export declare function createPostgresMessageHistorySchemaSql(options?: PostgresMessageHistorySchemaOptions): string;
18
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/history/postgres/schema.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,mCAAmC;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qCAAqC,CACjD,OAAO,GAAE,mCAAwC,GAClD,MAAM,CA4BR"}