@retinue/agentkit 0.1.0

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 (405) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +310 -0
  3. package/dist/adapters/bullmq/consumer.d.ts +33 -0
  4. package/dist/adapters/bullmq/consumer.js +41 -0
  5. package/dist/adapters/bullmq/dispatcher.d.ts +74 -0
  6. package/dist/adapters/bullmq/dispatcher.js +160 -0
  7. package/dist/adapters/bullmq/export.d.ts +31 -0
  8. package/dist/adapters/bullmq/export.js +53 -0
  9. package/dist/adapters/bullmq/extraction.d.ts +42 -0
  10. package/dist/adapters/bullmq/extraction.js +63 -0
  11. package/dist/adapters/bullmq/index.d.ts +13 -0
  12. package/dist/adapters/bullmq/index.js +13 -0
  13. package/dist/adapters/bullmq/lock.d.ts +77 -0
  14. package/dist/adapters/bullmq/lock.js +126 -0
  15. package/dist/adapters/bullmq/queue.d.ts +50 -0
  16. package/dist/adapters/bullmq/queue.js +81 -0
  17. package/dist/adapters/memory/artifact-exports.d.ts +11 -0
  18. package/dist/adapters/memory/artifact-exports.js +102 -0
  19. package/dist/adapters/memory/artifacts.d.ts +15 -0
  20. package/dist/adapters/memory/artifacts.js +134 -0
  21. package/dist/adapters/memory/blobs.d.ts +7 -0
  22. package/dist/adapters/memory/blobs.js +27 -0
  23. package/dist/adapters/memory/evaluation.d.ts +18 -0
  24. package/dist/adapters/memory/evaluation.js +148 -0
  25. package/dist/adapters/memory/files.d.ts +27 -0
  26. package/dist/adapters/memory/files.js +0 -0
  27. package/dist/adapters/memory/flows.d.ts +16 -0
  28. package/dist/adapters/memory/flows.js +117 -0
  29. package/dist/adapters/memory/hitl.d.ts +9 -0
  30. package/dist/adapters/memory/hitl.js +130 -0
  31. package/dist/adapters/memory/idempotency.d.ts +13 -0
  32. package/dist/adapters/memory/idempotency.js +32 -0
  33. package/dist/adapters/memory/index.d.ts +39 -0
  34. package/dist/adapters/memory/index.js +107 -0
  35. package/dist/adapters/memory/knowledge.d.ts +43 -0
  36. package/dist/adapters/memory/knowledge.js +248 -0
  37. package/dist/adapters/memory/mcp.d.ts +9 -0
  38. package/dist/adapters/memory/mcp.js +37 -0
  39. package/dist/adapters/memory/message-store.d.ts +17 -0
  40. package/dist/adapters/memory/message-store.js +70 -0
  41. package/dist/adapters/memory/principal-memory.d.ts +7 -0
  42. package/dist/adapters/memory/principal-memory.js +83 -0
  43. package/dist/adapters/memory/runtime.d.ts +29 -0
  44. package/dist/adapters/memory/runtime.js +0 -0
  45. package/dist/adapters/memory/sessions.d.ts +29 -0
  46. package/dist/adapters/memory/sessions.js +0 -0
  47. package/dist/adapters/memory/skills.d.ts +10 -0
  48. package/dist/adapters/memory/skills.js +41 -0
  49. package/dist/adapters/memory/thread-summary.d.ts +7 -0
  50. package/dist/adapters/memory/thread-summary.js +29 -0
  51. package/dist/adapters/memory/usage-limits.d.ts +13 -0
  52. package/dist/adapters/memory/usage-limits.js +72 -0
  53. package/dist/adapters/memory/usage.d.ts +16 -0
  54. package/dist/adapters/memory/usage.js +279 -0
  55. package/dist/adapters/otel/index.d.ts +111 -0
  56. package/dist/adapters/otel/index.js +133 -0
  57. package/dist/adapters/postgres/artifact-exports.d.ts +12 -0
  58. package/dist/adapters/postgres/artifact-exports.js +117 -0
  59. package/dist/adapters/postgres/artifacts.d.ts +16 -0
  60. package/dist/adapters/postgres/artifacts.js +172 -0
  61. package/dist/adapters/postgres/checkpoint-store.d.ts +16 -0
  62. package/dist/adapters/postgres/checkpoint-store.js +34 -0
  63. package/dist/adapters/postgres/config.d.ts +15 -0
  64. package/dist/adapters/postgres/config.js +187 -0
  65. package/dist/adapters/postgres/conversation-store.d.ts +4 -0
  66. package/dist/adapters/postgres/conversation-store.js +82 -0
  67. package/dist/adapters/postgres/evaluation.d.ts +17 -0
  68. package/dist/adapters/postgres/evaluation.js +193 -0
  69. package/dist/adapters/postgres/file-content.d.ts +30 -0
  70. package/dist/adapters/postgres/file-content.js +111 -0
  71. package/dist/adapters/postgres/files.d.ts +19 -0
  72. package/dist/adapters/postgres/files.js +209 -0
  73. package/dist/adapters/postgres/flows.d.ts +20 -0
  74. package/dist/adapters/postgres/flows.js +206 -0
  75. package/dist/adapters/postgres/hitl.d.ts +5 -0
  76. package/dist/adapters/postgres/hitl.js +247 -0
  77. package/dist/adapters/postgres/index.d.ts +35 -0
  78. package/dist/adapters/postgres/index.js +35 -0
  79. package/dist/adapters/postgres/knowledge.d.ts +48 -0
  80. package/dist/adapters/postgres/knowledge.js +255 -0
  81. package/dist/adapters/postgres/memory.d.ts +14 -0
  82. package/dist/adapters/postgres/memory.js +194 -0
  83. package/dist/adapters/postgres/message-store.d.ts +11 -0
  84. package/dist/adapters/postgres/message-store.js +145 -0
  85. package/dist/adapters/postgres/migrations.d.ts +69 -0
  86. package/dist/adapters/postgres/migrations.js +1594 -0
  87. package/dist/adapters/postgres/pg-executor.d.ts +19 -0
  88. package/dist/adapters/postgres/pg-executor.js +32 -0
  89. package/dist/adapters/postgres/retention.d.ts +26 -0
  90. package/dist/adapters/postgres/retention.js +59 -0
  91. package/dist/adapters/postgres/rollups.d.ts +17 -0
  92. package/dist/adapters/postgres/rollups.js +267 -0
  93. package/dist/adapters/postgres/run-coordinator.d.ts +5 -0
  94. package/dist/adapters/postgres/run-coordinator.js +98 -0
  95. package/dist/adapters/postgres/run-event-log.d.ts +26 -0
  96. package/dist/adapters/postgres/run-event-log.js +30 -0
  97. package/dist/adapters/postgres/run-store.d.ts +4 -0
  98. package/dist/adapters/postgres/run-store.js +199 -0
  99. package/dist/adapters/postgres/schema.d.ts +39 -0
  100. package/dist/adapters/postgres/schema.js +70 -0
  101. package/dist/adapters/postgres/session-state.d.ts +7 -0
  102. package/dist/adapters/postgres/session-state.js +99 -0
  103. package/dist/adapters/postgres/sql.d.ts +8 -0
  104. package/dist/adapters/postgres/sql.js +2 -0
  105. package/dist/adapters/postgres/transaction.d.ts +37 -0
  106. package/dist/adapters/postgres/transaction.js +93 -0
  107. package/dist/adapters/postgres/unit-of-work.d.ts +18 -0
  108. package/dist/adapters/postgres/unit-of-work.js +8 -0
  109. package/dist/adapters/postgres/usage-limits.d.ts +15 -0
  110. package/dist/adapters/postgres/usage-limits.js +136 -0
  111. package/dist/adapters/postgres/usage.d.ts +15 -0
  112. package/dist/adapters/postgres/usage.js +226 -0
  113. package/dist/adapters/redis/index.d.ts +9 -0
  114. package/dist/adapters/redis/index.js +9 -0
  115. package/dist/adapters/redis/realtime.d.ts +74 -0
  116. package/dist/adapters/redis/realtime.js +112 -0
  117. package/dist/adapters/supabase/index.d.ts +88 -0
  118. package/dist/adapters/supabase/index.js +84 -0
  119. package/dist/adapters/supabase/realtime.d.ts +30 -0
  120. package/dist/adapters/supabase/realtime.js +53 -0
  121. package/dist/adapters/supabase/rls.d.ts +99 -0
  122. package/dist/adapters/supabase/rls.js +216 -0
  123. package/dist/adapters/supabase/storage.d.ts +50 -0
  124. package/dist/adapters/supabase/storage.js +207 -0
  125. package/dist/agents/agent.d.ts +66 -0
  126. package/dist/agents/agent.js +209 -0
  127. package/dist/agents/define.d.ts +21 -0
  128. package/dist/agents/define.js +63 -0
  129. package/dist/agents/engine.d.ts +98 -0
  130. package/dist/agents/engine.js +462 -0
  131. package/dist/agents/index.d.ts +50 -0
  132. package/dist/agents/index.js +17 -0
  133. package/dist/artifacts/index.d.ts +114 -0
  134. package/dist/artifacts/index.js +219 -0
  135. package/dist/authorization/index.d.ts +76 -0
  136. package/dist/authorization/index.js +76 -0
  137. package/dist/capabilities/index.d.ts +120 -0
  138. package/dist/capabilities/index.js +167 -0
  139. package/dist/capabilities/runtime.d.ts +89 -0
  140. package/dist/capabilities/runtime.js +84 -0
  141. package/dist/citations/index.d.ts +161 -0
  142. package/dist/citations/index.js +182 -0
  143. package/dist/context/assembler.d.ts +82 -0
  144. package/dist/context/assembler.js +129 -0
  145. package/dist/context/compaction.d.ts +45 -0
  146. package/dist/context/compaction.js +55 -0
  147. package/dist/context/index.d.ts +75 -0
  148. package/dist/context/index.js +17 -0
  149. package/dist/core/content-parts.d.ts +194 -0
  150. package/dist/core/content-parts.js +23 -0
  151. package/dist/core/context.d.ts +51 -0
  152. package/dist/core/context.js +9 -0
  153. package/dist/core/env.d.ts +25 -0
  154. package/dist/core/env.js +41 -0
  155. package/dist/core/errors.d.ts +30 -0
  156. package/dist/core/errors.js +65 -0
  157. package/dist/core/events.d.ts +139 -0
  158. package/dist/core/events.js +99 -0
  159. package/dist/core/ids.d.ts +52 -0
  160. package/dist/core/ids.js +13 -0
  161. package/dist/core/index.d.ts +9 -0
  162. package/dist/core/index.js +9 -0
  163. package/dist/core/tokens.d.ts +22 -0
  164. package/dist/core/tokens.js +22 -0
  165. package/dist/core/validation.d.ts +34 -0
  166. package/dist/core/validation.js +176 -0
  167. package/dist/documents/extraction.d.ts +121 -0
  168. package/dist/documents/extraction.js +293 -0
  169. package/dist/documents/index.d.ts +199 -0
  170. package/dist/documents/index.js +65 -0
  171. package/dist/documents/parsers/pdf.d.ts +47 -0
  172. package/dist/documents/parsers/pdf.js +508 -0
  173. package/dist/documents/parsers/text.d.ts +59 -0
  174. package/dist/documents/parsers/text.js +325 -0
  175. package/dist/documents/read-tool.d.ts +52 -0
  176. package/dist/documents/read-tool.js +109 -0
  177. package/dist/documents/render.d.ts +29 -0
  178. package/dist/documents/render.js +59 -0
  179. package/dist/documents/vision.d.ts +159 -0
  180. package/dist/documents/vision.js +214 -0
  181. package/dist/entries/adapters-bullmq.d.ts +8 -0
  182. package/dist/entries/adapters-bullmq.js +8 -0
  183. package/dist/entries/adapters-otel.d.ts +13 -0
  184. package/dist/entries/adapters-otel.js +13 -0
  185. package/dist/entries/adapters-postgres.d.ts +10 -0
  186. package/dist/entries/adapters-postgres.js +10 -0
  187. package/dist/entries/adapters-redis.d.ts +3 -0
  188. package/dist/entries/adapters-redis.js +3 -0
  189. package/dist/entries/context.d.ts +20 -0
  190. package/dist/entries/context.js +20 -0
  191. package/dist/entries/flows.d.ts +15 -0
  192. package/dist/entries/flows.js +15 -0
  193. package/dist/entries/hitl.d.ts +10 -0
  194. package/dist/entries/hitl.js +10 -0
  195. package/dist/entries/knowledge.d.ts +18 -0
  196. package/dist/entries/knowledge.js +19 -0
  197. package/dist/entries/mcp.d.ts +10 -0
  198. package/dist/entries/mcp.js +10 -0
  199. package/dist/entries/observability.d.ts +14 -0
  200. package/dist/entries/observability.js +16 -0
  201. package/dist/entries/persistence.d.ts +11 -0
  202. package/dist/entries/persistence.js +11 -0
  203. package/dist/entries/providers.d.ts +14 -0
  204. package/dist/entries/providers.js +14 -0
  205. package/dist/entries/runtime.d.ts +13 -0
  206. package/dist/entries/runtime.js +13 -0
  207. package/dist/entries/server.d.ts +24 -0
  208. package/dist/entries/server.js +24 -0
  209. package/dist/entries/tools.d.ts +21 -0
  210. package/dist/entries/tools.js +21 -0
  211. package/dist/entries/usage.d.ts +10 -0
  212. package/dist/entries/usage.js +10 -0
  213. package/dist/evaluation/gate.d.ts +168 -0
  214. package/dist/evaluation/gate.js +180 -0
  215. package/dist/evaluation/graders.d.ts +125 -0
  216. package/dist/evaluation/graders.js +203 -0
  217. package/dist/evaluation/index.d.ts +120 -0
  218. package/dist/evaluation/index.js +183 -0
  219. package/dist/evaluation/judge.d.ts +75 -0
  220. package/dist/evaluation/judge.js +111 -0
  221. package/dist/export/index.d.ts +162 -0
  222. package/dist/export/index.js +363 -0
  223. package/dist/export/markdown.d.ts +19 -0
  224. package/dist/export/markdown.js +29 -0
  225. package/dist/export/pdf.d.ts +73 -0
  226. package/dist/export/pdf.js +407 -0
  227. package/dist/files/context.d.ts +97 -0
  228. package/dist/files/context.js +185 -0
  229. package/dist/files/index.d.ts +210 -0
  230. package/dist/files/index.js +338 -0
  231. package/dist/files/read-tool.d.ts +81 -0
  232. package/dist/files/read-tool.js +163 -0
  233. package/dist/files/turn-parts.d.ts +96 -0
  234. package/dist/files/turn-parts.js +171 -0
  235. package/dist/flows/index.d.ts +270 -0
  236. package/dist/flows/index.js +62 -0
  237. package/dist/flows/interpreter.d.ts +146 -0
  238. package/dist/flows/interpreter.js +426 -0
  239. package/dist/flows/runner.d.ts +145 -0
  240. package/dist/flows/runner.js +270 -0
  241. package/dist/graphql/index.d.ts +8 -0
  242. package/dist/graphql/index.js +8 -0
  243. package/dist/graphql/resolvers.d.ts +237 -0
  244. package/dist/graphql/resolvers.js +253 -0
  245. package/dist/graphql/schema.d.ts +11 -0
  246. package/dist/graphql/schema.js +258 -0
  247. package/dist/graphql/sse.d.ts +77 -0
  248. package/dist/graphql/sse.js +100 -0
  249. package/dist/hitl/approved-execution.d.ts +127 -0
  250. package/dist/hitl/approved-execution.js +177 -0
  251. package/dist/hitl/index.d.ts +79 -0
  252. package/dist/hitl/index.js +12 -0
  253. package/dist/hitl/service.d.ts +221 -0
  254. package/dist/hitl/service.js +268 -0
  255. package/dist/idempotency/index.d.ts +70 -0
  256. package/dist/idempotency/index.js +59 -0
  257. package/dist/index.d.ts +103 -0
  258. package/dist/index.js +60 -0
  259. package/dist/knowledge/chunking.d.ts +57 -0
  260. package/dist/knowledge/chunking.js +158 -0
  261. package/dist/knowledge/index.d.ts +119 -0
  262. package/dist/knowledge/index.js +166 -0
  263. package/dist/knowledge/retrieval.d.ts +146 -0
  264. package/dist/knowledge/retrieval.js +170 -0
  265. package/dist/loadtest/harness.d.ts +168 -0
  266. package/dist/loadtest/harness.js +507 -0
  267. package/dist/loadtest/index.d.ts +13 -0
  268. package/dist/loadtest/index.js +13 -0
  269. package/dist/loadtest/injection.d.ts +89 -0
  270. package/dist/loadtest/injection.js +147 -0
  271. package/dist/loadtest/metrics.d.ts +197 -0
  272. package/dist/loadtest/metrics.js +160 -0
  273. package/dist/loadtest/runbooks.d.ts +28 -0
  274. package/dist/loadtest/runbooks.js +159 -0
  275. package/dist/loadtest/scenario.d.ts +104 -0
  276. package/dist/loadtest/scenario.js +208 -0
  277. package/dist/mcp/egress.d.ts +53 -0
  278. package/dist/mcp/egress.js +115 -0
  279. package/dist/mcp/index.d.ts +93 -0
  280. package/dist/mcp/index.js +33 -0
  281. package/dist/mcp/provider.d.ts +62 -0
  282. package/dist/mcp/provider.js +0 -0
  283. package/dist/models/index.d.ts +98 -0
  284. package/dist/models/index.js +74 -0
  285. package/dist/models/pricing.d.ts +24 -0
  286. package/dist/models/pricing.js +37 -0
  287. package/dist/models/provider-factory.d.ts +31 -0
  288. package/dist/models/provider-factory.js +67 -0
  289. package/dist/models/streaming.d.ts +145 -0
  290. package/dist/models/streaming.js +272 -0
  291. package/dist/models/vision.d.ts +38 -0
  292. package/dist/models/vision.js +62 -0
  293. package/dist/persistence/index.d.ts +1654 -0
  294. package/dist/persistence/index.js +226 -0
  295. package/dist/principal-memory/index.d.ts +106 -0
  296. package/dist/principal-memory/index.js +89 -0
  297. package/dist/retention/index.d.ts +89 -0
  298. package/dist/retention/index.js +70 -0
  299. package/dist/runtime/checkpoint.d.ts +37 -0
  300. package/dist/runtime/checkpoint.js +22 -0
  301. package/dist/runtime/index.d.ts +118 -0
  302. package/dist/runtime/index.js +69 -0
  303. package/dist/runtime/retry.d.ts +95 -0
  304. package/dist/runtime/retry.js +126 -0
  305. package/dist/runtime/serialization.d.ts +85 -0
  306. package/dist/runtime/serialization.js +95 -0
  307. package/dist/runtime/streaming.d.ts +54 -0
  308. package/dist/runtime/streaming.js +115 -0
  309. package/dist/runtime/worker.d.ts +130 -0
  310. package/dist/runtime/worker.js +405 -0
  311. package/dist/security/checklist.d.ts +53 -0
  312. package/dist/security/checklist.js +204 -0
  313. package/dist/security/findings.d.ts +56 -0
  314. package/dist/security/findings.js +168 -0
  315. package/dist/security/index.d.ts +14 -0
  316. package/dist/security/index.js +14 -0
  317. package/dist/security/prompt-safety.d.ts +100 -0
  318. package/dist/security/prompt-safety.js +133 -0
  319. package/dist/server/boot.d.ts +32 -0
  320. package/dist/server/boot.js +36 -0
  321. package/dist/server/cli-worker.d.ts +37 -0
  322. package/dist/server/cli-worker.js +151 -0
  323. package/dist/server/cli.d.ts +27 -0
  324. package/dist/server/cli.js +74 -0
  325. package/dist/server/config.d.ts +42 -0
  326. package/dist/server/config.js +127 -0
  327. package/dist/server/health.d.ts +59 -0
  328. package/dist/server/health.js +90 -0
  329. package/dist/server/host.d.ts +39 -0
  330. package/dist/server/host.js +124 -0
  331. package/dist/server/index.d.ts +15 -0
  332. package/dist/server/index.js +15 -0
  333. package/dist/server/main.d.ts +16 -0
  334. package/dist/server/main.js +31 -0
  335. package/dist/server/sse-route.d.ts +21 -0
  336. package/dist/server/sse-route.js +282 -0
  337. package/dist/skills/index.d.ts +67 -0
  338. package/dist/skills/index.js +31 -0
  339. package/dist/skills/resolver.d.ts +54 -0
  340. package/dist/skills/resolver.js +121 -0
  341. package/dist/teams/index.d.ts +93 -0
  342. package/dist/teams/index.js +207 -0
  343. package/dist/telemetry/index.d.ts +157 -0
  344. package/dist/telemetry/index.js +71 -0
  345. package/dist/telemetry/instrument.d.ts +108 -0
  346. package/dist/telemetry/instrument.js +232 -0
  347. package/dist/telemetry/log-events.d.ts +17 -0
  348. package/dist/telemetry/log-events.js +58 -0
  349. package/dist/telemetry/metrics.d.ts +123 -0
  350. package/dist/telemetry/metrics.js +135 -0
  351. package/dist/telemetry/noop.d.ts +39 -0
  352. package/dist/telemetry/noop.js +143 -0
  353. package/dist/telemetry/redaction.d.ts +64 -0
  354. package/dist/telemetry/redaction.js +153 -0
  355. package/dist/telemetry/spans.d.ts +56 -0
  356. package/dist/telemetry/spans.js +78 -0
  357. package/dist/telemetry/trace-context.d.ts +55 -0
  358. package/dist/telemetry/trace-context.js +60 -0
  359. package/dist/toolkit/compute.d.ts +53 -0
  360. package/dist/toolkit/compute.js +152 -0
  361. package/dist/toolkit/data.d.ts +98 -0
  362. package/dist/toolkit/data.js +235 -0
  363. package/dist/toolkit/http.d.ts +113 -0
  364. package/dist/toolkit/http.js +205 -0
  365. package/dist/toolkit/index.d.ts +21 -0
  366. package/dist/toolkit/index.js +17 -0
  367. package/dist/toolkit/web.d.ts +107 -0
  368. package/dist/toolkit/web.js +147 -0
  369. package/dist/tools/define.d.ts +25 -0
  370. package/dist/tools/define.js +45 -0
  371. package/dist/tools/delegating.d.ts +132 -0
  372. package/dist/tools/delegating.js +211 -0
  373. package/dist/tools/index.d.ts +129 -0
  374. package/dist/tools/index.js +33 -0
  375. package/dist/tools/library/compute.d.ts +11 -0
  376. package/dist/tools/library/compute.js +46 -0
  377. package/dist/tools/library/data.d.ts +16 -0
  378. package/dist/tools/library/data.js +92 -0
  379. package/dist/tools/library/http.d.ts +28 -0
  380. package/dist/tools/library/http.js +71 -0
  381. package/dist/tools/library/index.d.ts +97 -0
  382. package/dist/tools/library/index.js +134 -0
  383. package/dist/tools/library/knowledge.d.ts +39 -0
  384. package/dist/tools/library/knowledge.js +58 -0
  385. package/dist/tools/library/web.d.ts +19 -0
  386. package/dist/tools/library/web.js +65 -0
  387. package/dist/tools/meta-tools.d.ts +19 -0
  388. package/dist/tools/meta-tools.js +36 -0
  389. package/dist/tools/registry.d.ts +146 -0
  390. package/dist/tools/registry.js +291 -0
  391. package/dist/usage/index.d.ts +105 -0
  392. package/dist/usage/index.js +20 -0
  393. package/dist/usage/quota.d.ts +258 -0
  394. package/dist/usage/quota.js +510 -0
  395. package/dist/usage/recorder.d.ts +29 -0
  396. package/dist/usage/recorder.js +96 -0
  397. package/dist/usage/rollups.d.ts +121 -0
  398. package/dist/usage/rollups.js +157 -0
  399. package/dist/worker/export.d.ts +57 -0
  400. package/dist/worker/export.js +81 -0
  401. package/dist/worker/extraction.d.ts +57 -0
  402. package/dist/worker/extraction.js +84 -0
  403. package/dist/worker/main.d.ts +103 -0
  404. package/dist/worker/main.js +159 -0
  405. package/package.json +187 -0
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Postgres `ArtifactStore` (#133).
3
+ *
4
+ * Two properties are in the SQL rather than above it, for the reason every other adapter here puts them
5
+ * there: a check the caller performs is a check a second caller can skip.
6
+ *
7
+ * - **`addVersion` is a compare-and-set in the statement** — `WHERE latest_version = $expected` — so two
8
+ * concurrent regenerations cannot both become version 2. The `UNIQUE (tenant_id, artifact_id, version)`
9
+ * constraint says the same thing a second time, at the level where the application cannot be wrong about it.
10
+ * - **Content is a reference and there is no column it could be inlined into.** AC-5 is enforced by the
11
+ * schema's shape, not by a rule someone follows.
12
+ */
13
+ import type { ArtifactStore } from "../../persistence/index.js";
14
+ import type { SqlExecutor } from "./sql.js";
15
+ export declare const createPostgresArtifactStore: (sql: SqlExecutor) => ArtifactStore;
16
+ //# sourceMappingURL=artifacts.d.ts.map
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Postgres `ArtifactStore` (#133).
3
+ *
4
+ * Two properties are in the SQL rather than above it, for the reason every other adapter here puts them
5
+ * there: a check the caller performs is a check a second caller can skip.
6
+ *
7
+ * - **`addVersion` is a compare-and-set in the statement** — `WHERE latest_version = $expected` — so two
8
+ * concurrent regenerations cannot both become version 2. The `UNIQUE (tenant_id, artifact_id, version)`
9
+ * constraint says the same thing a second time, at the level where the application cannot be wrong about it.
10
+ * - **Content is a reference and there is no column it could be inlined into.** AC-5 is enforced by the
11
+ * schema's shape, not by a rule someone follows.
12
+ */
13
+ import { AgentPlatformError } from "../../core/errors.js";
14
+ import { asId } from "../../core/ids.js";
15
+ const iso = (v) => (v instanceof Date ? v.toISOString() : v);
16
+ const toArtifact = (r) => ({
17
+ id: asId(r.id),
18
+ conversationId: asId(r.conversation_id),
19
+ kind: r.kind,
20
+ name: r.name,
21
+ latestVersion: Number(r.latest_version),
22
+ createdAt: iso(r.created_at),
23
+ updatedAt: iso(r.updated_at),
24
+ ...(r.deleted_at === null ? {} : { deletedAt: iso(r.deleted_at) }),
25
+ });
26
+ const toVersion = (r) => ({
27
+ id: asId(r.id),
28
+ artifactId: asId(r.artifact_id),
29
+ version: Number(r.version),
30
+ contentRef: asId(r.content_ref),
31
+ // `bigint` comes back as a string from node-postgres, correct past 2^53 and wrong for arithmetic. An
32
+ // artifact's size is well inside the safe range, so it is narrowed here rather than left for a caller to
33
+ // remember.
34
+ byteSize: Number(r.byte_size),
35
+ ...(r.checksum === null ? {} : { checksum: r.checksum }),
36
+ // `jsonb` comes back parsed from node-postgres and as a string from some drivers, so both are handled —
37
+ // a store that assumed one would work in tests and fail on the other.
38
+ provenance: (typeof r.provenance === "string"
39
+ ? JSON.parse(r.provenance)
40
+ : r.provenance),
41
+ createdBy: asId(r.created_by),
42
+ createdAt: iso(r.created_at),
43
+ });
44
+ const ARTIFACT_COLUMNS = `id, conversation_id, kind, name, latest_version, created_at, updated_at, deleted_at`;
45
+ const VERSION_COLUMNS = `id, artifact_id, version, content_ref, byte_size, checksum, provenance,
46
+ created_by, created_at`;
47
+ const encodeCursor = (createdAt, id) => Buffer.from(`${createdAt} ${id}`, "utf8").toString("base64url");
48
+ const decodeCursor = (cursor) => {
49
+ const [createdAt, id] = Buffer.from(cursor, "base64url").toString("utf8").split(" ");
50
+ return createdAt === undefined || id === undefined ? null : { createdAt, id };
51
+ };
52
+ export const createPostgresArtifactStore = (sql) => ({
53
+ async create({ tenantId, artifact, version }) {
54
+ const rows = await sql.query(`INSERT INTO artifacts (tenant_id, id, conversation_id, kind, name, latest_version,
55
+ created_at, updated_at, deleted_at)
56
+ VALUES ($1,$2,$3,$4,$5,1,$6,$6,NULL)
57
+ -- Nothing updated on conflict: a duplicate id is a caller bug, and overwriting would repoint a name
58
+ -- at different content while leaving the old versions attached to it.
59
+ ON CONFLICT (tenant_id, id) DO NOTHING
60
+ RETURNING ${ARTIFACT_COLUMNS}`, [tenantId, artifact.id, artifact.conversationId, artifact.kind, artifact.name, artifact.createdAt]);
61
+ const created = rows[0];
62
+ if (created === undefined)
63
+ throw new AgentPlatformError({
64
+ code: "conflict",
65
+ message: `artifact ${artifact.id} already exists`,
66
+ retryable: false,
67
+ });
68
+ // Version 1 in the same call. An artifact with no version is not something a reader can resolve, so the
69
+ // state is never observable -- and the FK means this insert cannot precede the row above.
70
+ await sql.query(`INSERT INTO artifact_versions (tenant_id, id, artifact_id, version, content_ref, byte_size,
71
+ checksum, provenance, created_by, created_at)
72
+ VALUES ($1,$2,$3,1,$4,$5,$6,$7::jsonb,$8,$9)`, [
73
+ tenantId,
74
+ version.id,
75
+ artifact.id,
76
+ version.contentRef,
77
+ version.byteSize,
78
+ version.checksum ?? null,
79
+ JSON.stringify(version.provenance),
80
+ version.createdBy,
81
+ version.createdAt,
82
+ ]);
83
+ return toArtifact(created);
84
+ },
85
+ async addVersion({ tenantId, id, expectedLatestVersion, version }) {
86
+ const bumped = await sql.query(`UPDATE artifacts
87
+ SET latest_version = latest_version + 1, updated_at = $4::timestamptz
88
+ WHERE tenant_id = $1 AND id = $2
89
+ -- The compare, in the statement. Two concurrent regenerations both hold expectedLatestVersion = 1;
90
+ -- exactly one UPDATE matches, and the loser is told so rather than overwriting the winner.
91
+ AND latest_version = $3
92
+ -- A deleted artifact gains no versions: a new version would resurrect it in every listing that
93
+ -- filters on deleted_at through the artifact row.
94
+ AND deleted_at IS NULL
95
+ RETURNING latest_version`, [tenantId, id, expectedLatestVersion, version.createdAt]);
96
+ const next = bumped[0];
97
+ if (next === undefined)
98
+ return { added: false };
99
+ const nextVersion = Number(next.latest_version);
100
+ await sql.query(`INSERT INTO artifact_versions (tenant_id, id, artifact_id, version, content_ref, byte_size,
101
+ checksum, provenance, created_by, created_at)
102
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8::jsonb,$9,$10)`, [
103
+ tenantId,
104
+ version.id,
105
+ id,
106
+ nextVersion,
107
+ version.contentRef,
108
+ version.byteSize,
109
+ version.checksum ?? null,
110
+ JSON.stringify(version.provenance),
111
+ version.createdBy,
112
+ version.createdAt,
113
+ ]);
114
+ return { added: true, version: nextVersion };
115
+ },
116
+ async get({ tenantId, id }) {
117
+ const rows = await sql.query(`SELECT ${ARTIFACT_COLUMNS} FROM artifacts WHERE tenant_id = $1 AND id = $2`, [tenantId, id]);
118
+ // A foreign id yields no row, so it is null without a comparison anyone could get wrong.
119
+ return rows[0] === undefined ? null : toArtifact(rows[0]);
120
+ },
121
+ async getVersion({ tenantId, id, version }) {
122
+ const rows = await sql.query(`SELECT ${VERSION_COLUMNS} FROM artifact_versions
123
+ WHERE tenant_id = $1 AND artifact_id = $2
124
+ -- The latest when none is asked for. Ordering and LIMIT rather than a join on latest_version, so
125
+ -- this answers correctly even if the denormalised counter were ever wrong.
126
+ AND ($3::integer IS NULL OR version = $3::integer)
127
+ ORDER BY version DESC
128
+ LIMIT 1`, [tenantId, id, version ?? null]);
129
+ return rows[0] === undefined ? null : toVersion(rows[0]);
130
+ },
131
+ async listByConversation({ tenantId, conversationId, limit, cursor }) {
132
+ const after = cursor === undefined ? null : decodeCursor(cursor);
133
+ const rows = await sql.query(`SELECT ${ARTIFACT_COLUMNS} FROM artifacts
134
+ WHERE tenant_id = $1 AND conversation_id = $2
135
+ -- Live only: a deleted artifact reappearing here is a deleted document coming back.
136
+ AND deleted_at IS NULL
137
+ AND ($3::text IS NULL OR (created_at, id) > ($3::timestamptz, $4::text))
138
+ ORDER BY created_at, id
139
+ LIMIT $5`, [tenantId, conversationId, after?.createdAt ?? null, after?.id ?? null, limit + 1]);
140
+ const items = rows.slice(0, limit).map(toArtifact);
141
+ const last = items[items.length - 1];
142
+ return rows.length > limit && last !== undefined
143
+ ? { items, nextCursor: encodeCursor(last.createdAt, last.id) }
144
+ : { items };
145
+ },
146
+ async listVersions({ tenantId, id, limit, cursor }) {
147
+ // Paged on the version number: it is 1-based and contiguous, so it is an exact cursor, and two versions
148
+ // created in the same millisecond would tie under a timestamp keyset -- which for a history is the one
149
+ // place order must not be approximate.
150
+ const after = cursor === undefined ? 0 : Number.parseInt(cursor, 10);
151
+ const from = Number.isSafeInteger(after) && after > 0 ? after : 0;
152
+ const rows = await sql.query(`SELECT ${VERSION_COLUMNS} FROM artifact_versions
153
+ WHERE tenant_id = $1 AND artifact_id = $2 AND version > $3
154
+ ORDER BY version
155
+ LIMIT $4`, [tenantId, id, from, limit + 1]);
156
+ const items = rows.slice(0, limit).map(toVersion);
157
+ const last = items[items.length - 1];
158
+ return rows.length > limit && last !== undefined
159
+ ? { items, nextCursor: String(last.version) }
160
+ : { items };
161
+ },
162
+ async softDelete({ tenantId, id, at }) {
163
+ const rows = await sql.query(`UPDATE artifacts
164
+ -- COALESCE, so a retried delete keeps the first timestamp: the answer to "when was this deleted"
165
+ -- must not move every time someone clicks again.
166
+ SET deleted_at = COALESCE(deleted_at, $3::timestamptz), updated_at = $3::timestamptz
167
+ WHERE tenant_id = $1 AND id = $2
168
+ RETURNING id`, [tenantId, id, at]);
169
+ return { deleted: rows.length > 0 };
170
+ },
171
+ });
172
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * PostgreSQL `CheckpointStore` (#95). The durable resume point: a recovered worker reloads the
3
+ * latest checkpoint, finalises any tool calls that were mid-flight, and continues from there.
4
+ *
5
+ * The monotonic guarantee lives in the statement, not in the caller. `save` is a single upsert whose
6
+ * `DO UPDATE` carries `WHERE excluded.sequence >= checkpoints.sequence`, so a late write from a
7
+ * worker whose lease was already reaped cannot rewind the run. Read-then-write could not hold that
8
+ * across two processes — and "two workers, one run, briefly overlapping" is exactly what lease
9
+ * expiry produces.
10
+ */
11
+ import type { RunId, TenantId } from "../../core/ids.js";
12
+ import type { CheckpointStore } from "../../persistence/index.js";
13
+ import type { SqlExecutor } from "./sql.js";
14
+ export declare const createPostgresCheckpointStore: (sql: SqlExecutor) => CheckpointStore;
15
+ export type { RunId, TenantId };
16
+ //# sourceMappingURL=checkpoint-store.d.ts.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The whole checkpoint round-trips through `state`; `sequence` and `step` are lifted into columns for
3
+ * the monotonic guard and the non-negative constraint. Reading from `state` rather than reassembling
4
+ * from columns keeps one source of truth, so a column and the payload cannot disagree.
5
+ */
6
+ const toCheckpoint = (row) => (typeof row.state === "string" ? JSON.parse(row.state) : row.state);
7
+ export const createPostgresCheckpointStore = (sql) => ({
8
+ async latest({ tenantId, runId }) {
9
+ const rows = await sql.query(`SELECT state FROM checkpoints WHERE tenant_id = $1 AND run_id = $2`, [tenantId, runId]);
10
+ const row = rows[0];
11
+ return row ? toCheckpoint(row) : null;
12
+ },
13
+ async save({ tenantId, checkpoint }) {
14
+ await sql.query(`INSERT INTO checkpoints (tenant_id, run_id, sequence, step, state, updated_at)
15
+ VALUES ($1, $2, $3, $4, $5::jsonb, $6::timestamptz)
16
+ ON CONFLICT (tenant_id, run_id) DO UPDATE
17
+ SET sequence = excluded.sequence,
18
+ step = excluded.step,
19
+ state = excluded.state,
20
+ updated_at = excluded.updated_at
21
+ -- Monotonic: a save at a lower sequence is ignored, so a reaped worker's late write cannot
22
+ -- rewind a run that a newer claim has already advanced. Greater-or-equal rather than
23
+ -- strictly-greater, so an equal sequence is an idempotent refresh, not a rejected write.
24
+ WHERE excluded.sequence >= checkpoints.sequence`, [
25
+ tenantId,
26
+ checkpoint.runId,
27
+ checkpoint.sequence,
28
+ checkpoint.step,
29
+ JSON.stringify(checkpoint),
30
+ checkpoint.updatedAt,
31
+ ]);
32
+ },
33
+ });
34
+ //# sourceMappingURL=checkpoint-store.js.map
@@ -0,0 +1,15 @@
1
+ import { type EgressPolicy } from "../../mcp/egress.js";
2
+ import type { McpConnectionStore } from "../../mcp/provider.js";
3
+ import type { SkillStore } from "../../persistence/index.js";
4
+ import type { SkillVersion } from "../../skills/index.js";
5
+ import type { SqlExecutor } from "./sql.js";
6
+ export declare const createPostgresSkillStore: (sql: SqlExecutor) => SkillStore & {
7
+ add(tenantId: string, skill: SkillVersion): Promise<void>;
8
+ };
9
+ /**
10
+ * The egress policy is a constructor parameter, not a column — it is a deployment-level rule rather
11
+ * than per-connection data, which is why the SPEC's `egress_policy jsonb` had nothing to populate it.
12
+ * What survives a restart is the connection; the policy comes from whatever store is built at boot.
13
+ */
14
+ export declare const createPostgresMcpConnectionStore: (sql: SqlExecutor, egress: EgressPolicy) => McpConnectionStore;
15
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,187 @@
1
+ /**
2
+ * PostgreSQL `SkillStore` and `McpConnectionStore` (#101) — tenant configuration.
3
+ *
4
+ * Two things worth stating up front, because both are places the SPEC and the code disagree.
5
+ *
6
+ * **`listCatalog` returns the latest *active* version per name.** That is what the reference adapter
7
+ * does, and the SPEC says nothing about it. The consequence is deliberate: a draft or archived
8
+ * version is invisible to discovery while remaining resolvable by `findVersion`, so a run pinned to
9
+ * an archived version keeps working and no new run picks it up.
10
+ *
11
+ * **A credential is a reference and nothing else.** `McpAuth` has no field capable of holding a
12
+ * secret value, and this table has no column that could either. That is the whole guarantee — and it
13
+ * is stronger than the pattern-matching constraint the SPEC proposed, which could not distinguish a
14
+ * reference from a secret in the general case.
15
+ */
16
+ import { AgentPlatformError } from "../../core/errors.js";
17
+ import { validateEndpoint } from "../../mcp/egress.js";
18
+ import { validateSkillInput } from "../../skills/resolver.js";
19
+ const iso = (v) => (v instanceof Date ? v.toISOString() : new Date(v).toISOString());
20
+ const toSkill = (r) => ({
21
+ id: r.id,
22
+ name: r.name,
23
+ description: r.description,
24
+ source: r.source,
25
+ version: Number(r.version),
26
+ instructions: r.instructions,
27
+ status: r.status,
28
+ tenantId: r.tenant_id,
29
+ createdAt: iso(r.created_at),
30
+ ...(r.created_by === null ? {} : { createdBy: r.created_by }),
31
+ });
32
+ const SKILL_COLUMNS = `tenant_id, id, name, description, source, version, instructions, status,
33
+ created_at, created_by`;
34
+ export const createPostgresSkillStore = (sql) => ({
35
+ /**
36
+ * Validated before the write, with the same function the reference adapter uses, so the two agree
37
+ * on what is storable rather than only on the happy path. The schema repeats the same bounds as
38
+ * CHECK constraints for the path that bypasses this method entirely.
39
+ */
40
+ async add(tenantId, skill) {
41
+ validateSkillInput(skill);
42
+ await sql.query(`INSERT INTO skills
43
+ (tenant_id, id, name, description, source, version, instructions, status, created_at, created_by)
44
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::timestamptz, $10)
45
+ ON CONFLICT (tenant_id, name, version) DO UPDATE
46
+ SET id = excluded.id,
47
+ description = excluded.description,
48
+ source = excluded.source,
49
+ instructions = excluded.instructions,
50
+ status = excluded.status,
51
+ created_at = excluded.created_at,
52
+ created_by = excluded.created_by`, [
53
+ tenantId,
54
+ skill.id,
55
+ skill.name,
56
+ skill.description,
57
+ skill.source,
58
+ skill.version,
59
+ skill.instructions,
60
+ skill.status,
61
+ skill.createdAt,
62
+ skill.createdBy ?? null,
63
+ ]);
64
+ },
65
+ async listCatalog({ tenantId }) {
66
+ // Latest active version per name. DISTINCT ON is the direct expression of that, and it reads off
67
+ // the partial index rather than sorting the tenant's whole skill history.
68
+ //
69
+ // Bodies are deliberately not selected: `SkillCatalogEntry` is documented as what discovery puts
70
+ // in context, and pulling 20k-character instructions into a catalog listing would defeat the
71
+ // lazy-loading the split exists for (AC-5).
72
+ const rows = await sql.query(`SELECT DISTINCT ON (name) id, name, description, source, version
73
+ FROM skills
74
+ WHERE tenant_id = $1 AND status = 'active'
75
+ ORDER BY name, version DESC`, [tenantId]);
76
+ return rows.map((r) => ({
77
+ id: r.id,
78
+ name: r.name,
79
+ description: r.description,
80
+ source: r.source,
81
+ version: Number(r.version),
82
+ }));
83
+ },
84
+ async findVersion({ tenantId, name, version }) {
85
+ // Exact version, never the nearest: a run records the version it used, and resolving to a
86
+ // neighbour would silently change behaviour on replay.
87
+ const rows = await sql.query(`SELECT ${SKILL_COLUMNS} FROM skills
88
+ WHERE tenant_id = $1 AND name = $2 AND version = $3`, [tenantId, name, version]);
89
+ const row = rows[0];
90
+ return row ? toSkill(row) : null;
91
+ },
92
+ });
93
+ /** Rebuilds the discriminated union from the two columns the pairing CHECK keeps consistent. */
94
+ const toAuth = (kind, ref) => {
95
+ if (kind === "bearer" || kind === "oauth") {
96
+ // Unreachable while the pairing constraint holds; throwing rather than defaulting because a
97
+ // bearer connection with no reference would otherwise fail later, at handshake, far from here.
98
+ if (ref === null) {
99
+ throw new AgentPlatformError({
100
+ code: "invalid_input",
101
+ message: `MCP auth kind ${kind} is missing its credential reference`,
102
+ retryable: false,
103
+ });
104
+ }
105
+ return { kind, credentialRef: ref };
106
+ }
107
+ return { kind: "none" };
108
+ };
109
+ const toConnection = (r) => ({
110
+ id: r.id,
111
+ tenantId: r.tenant_id,
112
+ label: r.label,
113
+ transport: r.transport,
114
+ endpoint: r.endpoint,
115
+ auth: toAuth(r.auth_kind, r.auth_credential_ref),
116
+ enabled: r.enabled,
117
+ createdAt: iso(r.created_at),
118
+ ...(r.last_handshake_at === null ? {} : { lastHandshakeAt: iso(r.last_handshake_at) }),
119
+ ...(r.last_error === null ? {} : { lastError: r.last_error }),
120
+ });
121
+ const CONNECTION_COLUMNS = `id, tenant_id, label, transport, endpoint, auth_kind,
122
+ auth_credential_ref, enabled, created_at, last_handshake_at, last_error`;
123
+ /**
124
+ * The egress policy is a constructor parameter, not a column — it is a deployment-level rule rather
125
+ * than per-connection data, which is why the SPEC's `egress_policy jsonb` had nothing to populate it.
126
+ * What survives a restart is the connection; the policy comes from whatever store is built at boot.
127
+ */
128
+ export const createPostgresMcpConnectionStore = (sql, egress) => ({
129
+ async register({ tenantId, connection }) {
130
+ // Validated at registration and again at handshake by the client. Registration is the cheaper
131
+ // place to refuse, and it stops a policy-violating endpoint from ever being persisted.
132
+ validateEndpoint(egress, connection.transport, connection.endpoint);
133
+ if (connection.tenantId !== tenantId) {
134
+ throw new AgentPlatformError({
135
+ code: "forbidden",
136
+ message: "connection tenant mismatch",
137
+ retryable: false,
138
+ });
139
+ }
140
+ const ref = connection.auth.kind === "none" ? null : connection.auth.credentialRef;
141
+ await sql.query(`INSERT INTO mcp_connections
142
+ (tenant_id, id, label, transport, endpoint, auth_kind, auth_credential_ref,
143
+ enabled, created_at, last_handshake_at, last_error)
144
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::timestamptz, $10::timestamptz, $11)
145
+ ON CONFLICT (tenant_id, id) DO UPDATE
146
+ SET label = excluded.label,
147
+ transport = excluded.transport,
148
+ endpoint = excluded.endpoint,
149
+ auth_kind = excluded.auth_kind,
150
+ auth_credential_ref = excluded.auth_credential_ref,
151
+ enabled = excluded.enabled,
152
+ created_at = excluded.created_at,
153
+ last_handshake_at = excluded.last_handshake_at,
154
+ last_error = excluded.last_error`, [
155
+ tenantId,
156
+ connection.id,
157
+ connection.label,
158
+ connection.transport,
159
+ connection.endpoint,
160
+ connection.auth.kind,
161
+ ref,
162
+ connection.enabled,
163
+ connection.createdAt,
164
+ connection.lastHandshakeAt ?? null,
165
+ connection.lastError ?? null,
166
+ ]);
167
+ },
168
+ async get({ tenantId, id }) {
169
+ const rows = await sql.query(`SELECT ${CONNECTION_COLUMNS} FROM mcp_connections WHERE tenant_id = $1 AND id = $2`, [tenantId, id]);
170
+ const row = rows[0];
171
+ return row ? toConnection(row) : null;
172
+ },
173
+ async list({ tenantId }) {
174
+ const rows = await sql.query(`SELECT ${CONNECTION_COLUMNS} FROM mcp_connections WHERE tenant_id = $1 ORDER BY created_at, id`, [tenantId]);
175
+ return rows.map(toConnection);
176
+ },
177
+ async setEnabled({ tenantId, id, enabled }) {
178
+ // Silent on a missing connection, matching the reference adapter: disabling something absent has
179
+ // already achieved its purpose.
180
+ await sql.query(`UPDATE mcp_connections SET enabled = $3 WHERE tenant_id = $1 AND id = $2`, [
181
+ tenantId,
182
+ id,
183
+ enabled,
184
+ ]);
185
+ },
186
+ });
187
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,4 @@
1
+ import type { ConversationStore } from "../../persistence/index.js";
2
+ import type { SqlExecutor } from "./sql.js";
3
+ export declare const createPostgresConversationStore: (sql: SqlExecutor, clock?: () => string) => ConversationStore;
4
+ //# sourceMappingURL=conversation-store.d.ts.map
@@ -0,0 +1,82 @@
1
+ /**
2
+ * PostgreSQL `ConversationStore`. Pure SQL over a `SqlExecutor`; verified by the shared
3
+ * conformance harness (the same suite the in-memory adapter passes).
4
+ */
5
+ import { AgentPlatformError } from "../../core/errors.js";
6
+ const iso = (v) => (v instanceof Date ? v.toISOString() : new Date(v).toISOString());
7
+ const toConversation = (r) => ({
8
+ id: r.id,
9
+ tenantId: r.tenant_id,
10
+ title: r.title,
11
+ version: r.version,
12
+ ...(r.archived_at === null ? {} : { archivedAt: iso(r.archived_at) }),
13
+ ...(r.deleted_at === null ? {} : { deletedAt: iso(r.deleted_at) }),
14
+ createdAt: iso(r.created_at),
15
+ updatedAt: iso(r.updated_at),
16
+ });
17
+ const conflict = (m) => new AgentPlatformError({ code: "conflict", message: m, retryable: false });
18
+ const notFound = (id) => new AgentPlatformError({ code: "not_found", message: `Conversation ${id} not found`, retryable: false });
19
+ const encodeCursor = (r) => Buffer.from(JSON.stringify({ c: iso(r.created_at), i: r.id })).toString("base64");
20
+ const decodeCursor = (cursor) => JSON.parse(Buffer.from(cursor, "base64").toString("utf8"));
21
+ /** Monotonic ISO clock, injectable for deterministic ordering in tests. */
22
+ const defaultClock = () => {
23
+ let n = 0;
24
+ return () => new Date(Date.UTC(2020, 0, 1, 0, 0, 0, ++n)).toISOString();
25
+ };
26
+ export const createPostgresConversationStore = (sql, clock = defaultClock()) => ({
27
+ async create({ tenantId, id, title }) {
28
+ const now = clock();
29
+ const rows = await sql.query(`INSERT INTO conversations (tenant_id, id, title, version, created_at, updated_at)
30
+ VALUES ($1, $2, $3, 1, $4, $4)
31
+ ON CONFLICT (tenant_id, id) DO NOTHING
32
+ RETURNING *`, [tenantId, id, title, now]);
33
+ const row = rows[0];
34
+ if (!row)
35
+ throw conflict(`Conversation ${id} already exists`);
36
+ return toConversation(row);
37
+ },
38
+ async findById({ tenantId, id }) {
39
+ const rows = await sql.query(`SELECT * FROM conversations WHERE tenant_id = $1 AND id = $2 AND deleted_at IS NULL`, [tenantId, id]);
40
+ const row = rows[0];
41
+ return row ? toConversation(row) : null;
42
+ },
43
+ async list({ tenantId, limit, cursor }) {
44
+ const params = [tenantId, limit + 1];
45
+ let where = `tenant_id = $1 AND deleted_at IS NULL`;
46
+ if (cursor) {
47
+ const { c, i } = decodeCursor(cursor);
48
+ where += ` AND (created_at, id) > ($3, $4)`;
49
+ params.push(c, i);
50
+ }
51
+ const rows = await sql.query(`SELECT * FROM conversations WHERE ${where} ORDER BY created_at, id LIMIT $2`, params);
52
+ const hasMore = rows.length > limit;
53
+ const items = (hasMore ? rows.slice(0, limit) : rows).map(toConversation);
54
+ const last = hasMore ? rows[limit - 1] : undefined;
55
+ const page = last ? { items, nextCursor: encodeCursor(last) } : { items };
56
+ return page;
57
+ },
58
+ async update({ tenantId, id, expectedVersion, patch }) {
59
+ const changeArchived = patch.archivedAt !== undefined;
60
+ const rows = await sql.query(`UPDATE conversations
61
+ SET title = COALESCE($4, title),
62
+ archived_at = CASE WHEN $5 THEN $6 ELSE archived_at END,
63
+ version = version + 1,
64
+ updated_at = $7
65
+ WHERE tenant_id = $1 AND id = $2 AND version = $3 AND deleted_at IS NULL
66
+ RETURNING *`, [tenantId, id, expectedVersion, patch.title ?? null, changeArchived, patch.archivedAt ?? null, clock()]);
67
+ const row = rows[0];
68
+ if (row)
69
+ return toConversation(row);
70
+ // No row updated: distinguish a missing row from a stale version.
71
+ const exists = await this.findById({ tenantId, id });
72
+ throw exists ? conflict(`Conversation ${id} version ${expectedVersion} is stale`) : notFound(id);
73
+ },
74
+ async softDelete({ tenantId, id }) {
75
+ const now = clock();
76
+ const rows = await sql.query(`UPDATE conversations SET deleted_at = $3, version = version + 1, updated_at = $3
77
+ WHERE tenant_id = $1 AND id = $2 AND deleted_at IS NULL RETURNING id`, [tenantId, id, now]);
78
+ if (!rows[0])
79
+ throw notFound(id);
80
+ },
81
+ });
82
+ //# sourceMappingURL=conversation-store.js.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Postgres `EvaluationStore` (#141).
3
+ *
4
+ * Two properties are in the SQL.
5
+ *
6
+ * **`recordCase` upserts on the primary key**, so a resumed run re-recording a case it already scored replaces
7
+ * rather than double-counts it in the aggregate. The key is the idempotency; there is no applied-case set to
8
+ * keep right.
9
+ *
10
+ * **`completeRun` computes the aggregate from the case rows in one statement.** Accumulating as cases arrive
11
+ * would let a run's totals disagree with its own evidence after a re-record — and the number that gates a
12
+ * release must be derivable from what it was derived from.
13
+ */
14
+ import type { EvaluationStore } from "../../persistence/index.js";
15
+ import type { SqlExecutor } from "./sql.js";
16
+ export declare const createPostgresEvaluationStore: (sql: SqlExecutor) => EvaluationStore;
17
+ //# sourceMappingURL=evaluation.d.ts.map