@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,199 @@
1
+ /**
2
+ * PostgreSQL `RunStore` (#93). Pure SQL over a `SqlExecutor`; verified by `runStoreConformance`,
3
+ * the same suite the in-memory adapter passes.
4
+ *
5
+ * Every state change is a **single compare-and-set `UPDATE … RETURNING`**, never read-then-write.
6
+ * That is the whole point of this adapter: the in-memory store's "two workers cannot claim one run"
7
+ * guarantee comes from JavaScript being single-threaded, which says nothing about two worker
8
+ * processes. Here the database adjudicates, so the guarantee survives real deployment.
9
+ *
10
+ * Where a caller needs to distinguish *why* no row changed (missing vs. illegal vs. held by someone
11
+ * else), the follow-up read happens only on the failure path — so the happy path stays one
12
+ * statement.
13
+ */
14
+ import { AgentPlatformError } from "../../core/errors.js";
15
+ import { canTransition, isTerminal } from "../../runtime/index.js";
16
+ const iso = (v) => (v instanceof Date ? v.toISOString() : new Date(v).toISOString());
17
+ const toRun = (r) => ({
18
+ id: r.id,
19
+ tenantId: r.tenant_id,
20
+ // Spread conditionally, so an absent conversation is *absent* from the object rather than an explicit
21
+ // `undefined` — `"conversationId" in run` then answers "does this belong to a conversation" without a
22
+ // second convention, which is how every other optional field in these adapters behaves (#198).
23
+ ...(r.conversation_id === null ? {} : { conversationId: r.conversation_id }),
24
+ agentId: r.agent_id,
25
+ agentVersion: r.agent_version,
26
+ // Absent stays absent: a run with no recorded input is different from one whose input was null.
27
+ ...(r.input === null || r.input === undefined
28
+ ? {}
29
+ : { input: typeof r.input === "string" ? JSON.parse(r.input) : r.input }),
30
+ ...(r.limits === null || r.limits === undefined
31
+ ? {}
32
+ : { limits: (typeof r.limits === "string" ? JSON.parse(r.limits) : r.limits) }),
33
+ status: r.status,
34
+ createdAt: iso(r.created_at),
35
+ ...(r.started_at === null ? {} : { startedAt: iso(r.started_at) }),
36
+ ...(r.finished_at === null ? {} : { finishedAt: iso(r.finished_at) }),
37
+ ...(r.error === null || r.error === undefined ? {} : { error: r.error }),
38
+ ...(r.claimed_by === null ? {} : { claimedBy: r.claimed_by }),
39
+ ...(r.keepalive_at === null ? {} : { keepaliveAt: iso(r.keepalive_at) }),
40
+ ...(r.lease_expires_at === null ? {} : { leaseExpiresAt: iso(r.lease_expires_at) }),
41
+ ...(r.cancel_requested_at === null ? {} : { cancelRequestedAt: iso(r.cancel_requested_at) }),
42
+ // #164. Null-and-undefined both mean "not recorded": the column is nullable for rows written before it
43
+ // existed, and `??` here rather than a `?? []` default because an empty role list and an unknown one are
44
+ // different facts — one is a caller with no roles, the other is a run nobody can attribute.
45
+ ...(r.principal_id === null || r.principal_id === undefined ? {} : { principalId: r.principal_id }),
46
+ ...(r.role_ids === null || r.role_ids === undefined ? {} : { roleIds: r.role_ids }),
47
+ });
48
+ const conflict = (m) => new AgentPlatformError({ code: "conflict", message: m, retryable: false });
49
+ const notFound = (id) => new AgentPlatformError({ code: "not_found", message: `Run ${id} not found`, retryable: false });
50
+ /** The statuses that can never hold a lease or transition further. Mirrors `isTerminal`. */
51
+ const TERMINAL_SQL = `('completed', 'failed', 'cancelled')`;
52
+ export const createPostgresRunStore = (sql) => {
53
+ const read = async (tenantId, id) => {
54
+ const rows = await sql.query(`SELECT * FROM runs WHERE tenant_id = $1 AND id = $2`, [tenantId, id]);
55
+ const row = rows[0];
56
+ return row ? toRun(row) : null;
57
+ };
58
+ return {
59
+ async create({ tenantId, id, conversationId, agentId, agentVersion, principalId, roleIds, input, limits }) {
60
+ const rows = await sql.query(`INSERT INTO runs (tenant_id, id, conversation_id, agent_id, agent_version, status, created_at,
61
+ principal_id, role_ids, input, limits)
62
+ VALUES ($1, $2, $3, $4, $5, 'queued', now(), $6, $7, $8::jsonb, $9::jsonb)
63
+ ON CONFLICT (tenant_id, id) DO NOTHING
64
+ RETURNING *`,
65
+ // `?? null` on the conversation since #198: absent means the run belongs to none, and a
66
+ // fabricated id here would be indistinguishable from a real conversation in every later query.
67
+ // `input` and `limits` since #202: a conversation-less run's request has nowhere else to live, and a
68
+ // flow's remaining budget has to reach the child it admits.
69
+ [
70
+ tenantId,
71
+ id,
72
+ conversationId ?? null,
73
+ agentId,
74
+ agentVersion,
75
+ principalId ?? null,
76
+ roleIds ?? null,
77
+ input === undefined ? null : JSON.stringify(input),
78
+ limits === undefined ? null : JSON.stringify(limits),
79
+ ]);
80
+ const row = rows[0];
81
+ if (!row)
82
+ throw conflict(`Run ${id} already exists`);
83
+ return toRun(row);
84
+ },
85
+ async findById({ tenantId, id }) {
86
+ return read(tenantId, id);
87
+ },
88
+ /**
89
+ * Lease-based claim, in one statement. Two claimable cases:
90
+ * - `queued` — a cold start.
91
+ * - `running` with an expired lease — **crash recovery**, the case the SPEC's original
92
+ * `WHERE status='queued'` would have removed.
93
+ * A live lease held by *another* worker excludes the row; the current holder re-claiming is
94
+ * allowed (idempotent re-entry after a transient failure).
95
+ */
96
+ async claim({ tenantId, id, workerId, leaseMs, now }) {
97
+ const rows = await sql.query(`UPDATE runs
98
+ SET status = 'running',
99
+ claimed_by = $3,
100
+ keepalive_at = $4::timestamptz,
101
+ lease_expires_at = $4::timestamptz + ($5 || ' milliseconds')::interval,
102
+ -- Only on the first claim: a recovered run keeps its original start time.
103
+ started_at = COALESCE(started_at, $4::timestamptz)
104
+ WHERE tenant_id = $1
105
+ AND id = $2
106
+ AND status NOT IN ${TERMINAL_SQL}
107
+ AND (status = 'queued' OR (status = 'running' AND lease_expires_at <= $4::timestamptz))
108
+ AND (claimed_by IS NULL
109
+ OR claimed_by = $3
110
+ OR lease_expires_at IS NULL
111
+ OR lease_expires_at <= $4::timestamptz)
112
+ RETURNING *`, [tenantId, id, workerId, now, String(leaseMs)]);
113
+ const row = rows[0];
114
+ return row ? toRun(row) : null;
115
+ },
116
+ /** False when the claim was lost (reaped or stolen) so the worker aborts rather than continuing. */
117
+ async keepalive({ tenantId, id, workerId, leaseMs, now }) {
118
+ const rows = await sql.query(`UPDATE runs
119
+ SET keepalive_at = $4::timestamptz,
120
+ lease_expires_at = $4::timestamptz + ($5 || ' milliseconds')::interval
121
+ WHERE tenant_id = $1
122
+ AND id = $2
123
+ AND claimed_by = $3
124
+ AND status NOT IN ${TERMINAL_SQL}
125
+ RETURNING id`, [tenantId, id, workerId, now, String(leaseMs)]);
126
+ return rows.length > 0;
127
+ },
128
+ /**
129
+ * Guarded transition by the claiming worker. Legality is decided in TypeScript from
130
+ * `RUN_TRANSITIONS` rather than duplicated in SQL — one source of truth, and the error message
131
+ * can name the illegal move. A same-status transition is a no-op rather than an error.
132
+ *
133
+ * Terminal and `waiting-for-*` states release the claim and lease, so a continuation can
134
+ * re-claim the run without waiting for the lease to expire.
135
+ */
136
+ async transition({ tenantId, id, workerId, to, now, error }) {
137
+ const current = await read(tenantId, id);
138
+ if (!current)
139
+ throw notFound(id);
140
+ if (current.claimedBy !== undefined && current.claimedBy !== workerId)
141
+ throw conflict(`Run ${id} is held by another worker`);
142
+ if (current.status !== to && !canTransition(current.status, to))
143
+ throw conflict(`Illegal run transition ${current.status} -> ${to}`);
144
+ const releases = isTerminal(to) || to === "waiting-for-question" || to === "waiting-for-approval";
145
+ const rows = await sql.query(`UPDATE runs
146
+ SET status = $3,
147
+ error = COALESCE($4::jsonb, error),
148
+ finished_at = CASE WHEN $5 THEN $6::timestamptz ELSE finished_at END,
149
+ claimed_by = CASE WHEN $7 THEN NULL ELSE claimed_by END,
150
+ lease_expires_at = CASE WHEN $7 THEN NULL ELSE lease_expires_at END
151
+ WHERE tenant_id = $1
152
+ AND id = $2
153
+ -- Re-check the status we based the legality decision on, so a concurrent transition
154
+ -- cannot slip between the read and this write.
155
+ AND status = $8
156
+ RETURNING *`, [
157
+ tenantId,
158
+ id,
159
+ to,
160
+ error === undefined ? null : JSON.stringify(error),
161
+ isTerminal(to),
162
+ now,
163
+ releases,
164
+ current.status,
165
+ ]);
166
+ const row = rows[0];
167
+ // Lost the race: another worker moved the run between our read and our write.
168
+ if (!row)
169
+ throw conflict(`Run ${id} changed status concurrently; transition to ${to} abandoned`);
170
+ return toRun(row);
171
+ },
172
+ /** Durable cancel request. Idempotent — the first timestamp wins — and a no-op once terminal. */
173
+ async requestCancel({ tenantId, id, now }) {
174
+ const rows = await sql.query(`UPDATE runs
175
+ SET cancel_requested_at = COALESCE(cancel_requested_at, $3::timestamptz)
176
+ WHERE tenant_id = $1 AND id = $2 AND status NOT IN ${TERMINAL_SQL}
177
+ RETURNING *`, [tenantId, id, now]);
178
+ const row = rows[0];
179
+ // No row updated ⇒ either missing or already terminal. The port returns the run as-is for a
180
+ // terminal run and null when it does not exist, so fall back to a read.
181
+ return row ? toRun(row) : await read(tenantId, id);
182
+ },
183
+ /**
184
+ * Recovery candidates: running runs whose lease expired. Cross-tenant by design — a background
185
+ * reaper has no tenant — so each row carries its own `tenantId` for re-claim, and the supporting
186
+ * index is deliberately not tenant-leading.
187
+ */
188
+ async reapExpired({ now, limit }) {
189
+ const rows = await sql.query(`SELECT * FROM runs
190
+ WHERE status = 'running'
191
+ AND lease_expires_at IS NOT NULL
192
+ AND lease_expires_at <= $1::timestamptz
193
+ ORDER BY lease_expires_at
194
+ LIMIT $2`, [now, limit]);
195
+ return rows.map(toRun);
196
+ },
197
+ };
198
+ };
199
+ //# sourceMappingURL=run-store.js.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Automatic schema provisioning — `docs/02-core-and-persistence.md`.
3
+ *
4
+ * A `SchemaManager` over the reversible migrations: it provisions a fresh database on startup
5
+ * (`auto`), logs the diff and refuses (`plan`), or leaves the schema to managed migrations
6
+ * (`off`, the default for Postgres). Forward-only and idempotent — running it twice is a no-op,
7
+ * so concurrent workers never double-provision.
8
+ */
9
+ import { type Migration } from "./migrations.js";
10
+ import type { SqlExecutor } from "./sql.js";
11
+ export type SchemaMode = "auto" | "plan" | "off";
12
+ export type SchemaChange = {
13
+ readonly id: string;
14
+ readonly statements: readonly string[];
15
+ };
16
+ export interface SchemaManager {
17
+ currentVersion(): Promise<number>;
18
+ targetVersion(): number;
19
+ /** Pending changes — no side effects. */
20
+ plan(): Promise<readonly SchemaChange[]>;
21
+ /** Create/upgrade to the target version. Idempotent. */
22
+ apply(): Promise<void>;
23
+ }
24
+ export declare const createSchemaManager: (sql: SqlExecutor, migrations?: readonly Migration[]) => SchemaManager;
25
+ export type ProvisionResult = {
26
+ readonly mode: SchemaMode;
27
+ readonly applied: readonly string[];
28
+ readonly planned: readonly SchemaChange[];
29
+ };
30
+ /**
31
+ * Startup provisioning per mode. `off` (Postgres default) leaves the schema to managed
32
+ * migrations; `plan` logs the pending diff and applies nothing; `auto` provisions.
33
+ */
34
+ export declare const provisionSchema: (sql: SqlExecutor, options?: {
35
+ readonly mode?: SchemaMode;
36
+ readonly log?: (message: string) => void;
37
+ readonly migrations?: readonly Migration[];
38
+ }) => Promise<ProvisionResult>;
39
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Automatic schema provisioning — `docs/02-core-and-persistence.md`.
3
+ *
4
+ * A `SchemaManager` over the reversible migrations: it provisions a fresh database on startup
5
+ * (`auto`), logs the diff and refuses (`plan`), or leaves the schema to managed migrations
6
+ * (`off`, the default for Postgres). Forward-only and idempotent — running it twice is a no-op,
7
+ * so concurrent workers never double-provision.
8
+ */
9
+ import { MIGRATION_LEDGER, MIGRATIONS, appliedMigrationIds } from "./migrations.js";
10
+ export const createSchemaManager = (sql, migrations = MIGRATIONS) => {
11
+ // Read-only: if the tracking table doesn't exist yet, nothing has been applied. `plan()` and
12
+ // `currentVersion()` therefore have no side effects; only `apply()` creates the table.
13
+ // Intersected with this manager's own list, not counted raw: the ledger is shared with migrations
14
+ // this manager does not own -- the vector ones -- and a raw count would report a version *above*
15
+ // the target on a database that has them, which reads as "schema ahead" rather than "ready".
16
+ const appliedIds = async () => {
17
+ const known = new Set(migrations.map((m) => m.id));
18
+ return new Set([...(await appliedMigrationIds(sql))].filter((id) => known.has(id)));
19
+ };
20
+ const pending = async () => {
21
+ const done = await appliedIds();
22
+ return migrations.filter((m) => !done.has(m.id));
23
+ };
24
+ return {
25
+ async currentVersion() {
26
+ return (await appliedIds()).size;
27
+ },
28
+ targetVersion() {
29
+ return migrations.length;
30
+ },
31
+ async plan() {
32
+ return (await pending()).map((m) => ({ id: m.id, statements: m.up }));
33
+ },
34
+ async apply() {
35
+ await sql.query(MIGRATION_LEDGER);
36
+ for (const m of await pending()) {
37
+ for (const stmt of m.up)
38
+ await sql.query(stmt);
39
+ // ON CONFLICT DO NOTHING: two workers applying the same migration can't both record it.
40
+ await sql.query(`INSERT INTO schema_migrations (id) VALUES ($1) ON CONFLICT (id) DO NOTHING`, [m.id]);
41
+ }
42
+ },
43
+ };
44
+ };
45
+ /**
46
+ * Startup provisioning per mode. `off` (Postgres default) leaves the schema to managed
47
+ * migrations; `plan` logs the pending diff and applies nothing; `auto` provisions.
48
+ */
49
+ export const provisionSchema = async (sql, options = {}) => {
50
+ const mode = options.mode ?? "off";
51
+ const manager = createSchemaManager(sql, options.migrations);
52
+ const log = options.log ?? (() => { });
53
+ if (mode === "off") {
54
+ return { mode, applied: [], planned: [] };
55
+ }
56
+ const planned = await manager.plan();
57
+ if (mode === "plan") {
58
+ if (planned.length === 0)
59
+ log("schema is up to date; no changes to apply");
60
+ else
61
+ log(`schema plan — ${planned.length} pending migration(s): ${planned.map((c) => c.id).join(", ")}`);
62
+ return { mode, applied: [], planned };
63
+ }
64
+ // auto
65
+ await manager.apply();
66
+ if (planned.length)
67
+ log(`provisioned schema: applied ${planned.map((c) => c.id).join(", ")}`);
68
+ return { mode, applied: planned.map((c) => c.id), planned };
69
+ };
70
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1,7 @@
1
+ import type { SessionStateStore, ThreadSummaryStore } from "../../persistence/index.js";
2
+ import type { SqlExecutor } from "./sql.js";
3
+ export declare const createPostgresSessionStateStore: (sql: SqlExecutor, options?: {
4
+ readonly maxBytes?: number;
5
+ }) => SessionStateStore;
6
+ export declare const createPostgresThreadSummaryStore: (sql: SqlExecutor) => ThreadSummaryStore;
7
+ //# sourceMappingURL=session-state.d.ts.map
@@ -0,0 +1,99 @@
1
+ /**
2
+ * PostgreSQL `SessionStateStore` and `ThreadSummaryStore` (#97) — cross-turn working memory and
3
+ * compacted history, the two pieces that replace Agno's fixed 20-turn re-injection.
4
+ *
5
+ * The optimistic-concurrency guard lives in the statement. `put` is one upsert whose `DO UPDATE`
6
+ * carries `WHERE session_state.version = $expectedVersion`; zero rows returned means the caller's
7
+ * version was stale. Read-then-write would reintroduce the lost-update race the `version` column
8
+ * exists to prevent — and two runs on one conversation is not hypothetical, it is precisely what the
9
+ * run coordinator (#98) exists to serialise.
10
+ *
11
+ * Note the deliberate asymmetry with `run_events` (#94): there the *caller* owns the sequence, because
12
+ * it is the client's reconnect cursor. Here the store allocates the version, because `append` takes
13
+ * none and returns the created one. Similar-looking tables, opposite correct answers.
14
+ */
15
+ import { AgentPlatformError } from "../../core/errors.js";
16
+ import { DEFAULT_SESSION_STATE_MAX_BYTES } from "../../persistence/index.js";
17
+ const iso = (v) => (v instanceof Date ? v.toISOString() : new Date(v).toISOString());
18
+ const conflict = (m) => new AgentPlatformError({ code: "conflict", message: m, retryable: false });
19
+ const invalid = (m) => new AgentPlatformError({ code: "invalid_input", message: m, retryable: false });
20
+ const toSessionState = (r) => ({
21
+ conversationId: r.conversation_id,
22
+ version: r.version,
23
+ data: (typeof r.state === "string" ? JSON.parse(r.state) : r.state),
24
+ updatedAt: iso(r.updated_at),
25
+ });
26
+ export const createPostgresSessionStateStore = (sql, options = {}) => {
27
+ const maxBytes = options.maxBytes ?? DEFAULT_SESSION_STATE_MAX_BYTES;
28
+ return {
29
+ async get({ tenantId, conversationId }) {
30
+ const rows = await sql.query(`SELECT conversation_id, state, version, updated_at
31
+ FROM session_state WHERE tenant_id = $1 AND conversation_id = $2`, [tenantId, conversationId]);
32
+ const row = rows[0];
33
+ return row ? toSessionState(row) : null;
34
+ },
35
+ async put({ tenantId, conversationId, expectedVersion, data }) {
36
+ const encoded = JSON.stringify(data);
37
+ const bytes = Buffer.byteLength(encoded, "utf8");
38
+ // Checked before the write, and with the same message shape as the reference adapter, so the
39
+ // two agree on what is storable rather than only on the happy path.
40
+ if (bytes > maxBytes)
41
+ throw invalid(`Session state ${bytes}B exceeds the ${maxBytes}B ceiling`);
42
+ const rows = await sql.query(`INSERT INTO session_state (tenant_id, conversation_id, state, version, updated_at)
43
+ VALUES ($1, $2, $3::jsonb, 1, now())
44
+ ON CONFLICT (tenant_id, conversation_id) DO UPDATE
45
+ SET state = excluded.state,
46
+ version = session_state.version + 1,
47
+ updated_at = now()
48
+ -- The compare-and-set. A stale expectedVersion matches no row, so the write is refused
49
+ -- rather than silently overwriting a newer value.
50
+ WHERE session_state.version = $4
51
+ RETURNING conversation_id, state, version, updated_at`, [tenantId, conversationId, encoded, expectedVersion]);
52
+ const row = rows[0];
53
+ if (row)
54
+ return toSessionState(row);
55
+ // No row: either the caller expected 0 but a row exists (a first write racing a second), or a
56
+ // genuinely stale version. Read to say which, since the distinction is the caller's next move.
57
+ const current = await this.get({ tenantId, conversationId });
58
+ throw conflict(`Session state for ${conversationId} version ${expectedVersion} is stale (current ${current?.version ?? 0})`);
59
+ },
60
+ };
61
+ };
62
+ const toSummary = (r) => ({
63
+ conversationId: r.conversation_id,
64
+ version: r.version,
65
+ summary: r.summary,
66
+ coversUpToMessageId: r.covers_up_to_message_id,
67
+ createdAt: iso(r.created_at),
68
+ });
69
+ export const createPostgresThreadSummaryStore = (sql) => ({
70
+ async latest({ tenantId, conversationId }) {
71
+ const rows = await sql.query(`SELECT conversation_id, version, summary, covers_up_to_message_id, created_at
72
+ FROM thread_summaries
73
+ WHERE tenant_id = $1 AND conversation_id = $2
74
+ ORDER BY version DESC
75
+ LIMIT 1`, [tenantId, conversationId]);
76
+ const row = rows[0];
77
+ return row ? toSummary(row) : null;
78
+ },
79
+ async append({ tenantId, conversationId, summary, coversUpToMessageId }) {
80
+ // Version allocated in the INSERT rather than read-then-write, so two concurrent appends cannot
81
+ // both compute the same next version — the primary key would reject the loser, which is the
82
+ // behaviour we want, but computing it in-statement means the winner does not need a retry.
83
+ const rows = await sql.query(`INSERT INTO thread_summaries
84
+ (tenant_id, conversation_id, version, summary, covers_up_to_message_id, created_at)
85
+ SELECT $1, $2,
86
+ COALESCE(MAX(version), 0) + 1,
87
+ $3, $4, now()
88
+ FROM thread_summaries
89
+ WHERE tenant_id = $1 AND conversation_id = $2
90
+ RETURNING conversation_id, version, summary, covers_up_to_message_id, created_at`, [tenantId, conversationId, summary, coversUpToMessageId]);
91
+ const row = rows[0];
92
+ // Append is not optional: a caller that asked for a summary and got nothing back would have no
93
+ // way to know its compaction was lost.
94
+ if (!row)
95
+ throw conflict(`Could not append a thread summary for ${conversationId}`);
96
+ return toSummary(row);
97
+ },
98
+ });
99
+ //# sourceMappingURL=session-state.js.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Minimal SQL executor the PostgreSQL adapters are written against, so the store code is pure
3
+ * SQL and imports no driver. Production wraps `pg.Pool` (`createPgExecutor`); tests wrap PGlite.
4
+ */
5
+ export interface SqlExecutor {
6
+ query<Row = Record<string, unknown>>(text: string, params?: readonly unknown[]): Promise<Row[]>;
7
+ }
8
+ //# sourceMappingURL=sql.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1,37 @@
1
+ import type { SqlExecutor } from "./sql.js";
2
+ /** Runs `fn` with every query inside one transaction. Nesting composes via savepoints. */
3
+ export interface TransactionRunner {
4
+ transaction<T>(fn: (sql: SqlExecutor) => Promise<T>): Promise<T>;
5
+ }
6
+ /**
7
+ * Grants exclusive use of a single connection for the duration of `fn`. The one thing a pool-backed
8
+ * `SqlExecutor` cannot express, and the only primitive the runner needs from the driver.
9
+ */
10
+ export type ConnectionOpener = <T>(fn: (sql: SqlExecutor) => Promise<T>) => Promise<T>;
11
+ export type TransactionScope = {
12
+ readonly runner: TransactionRunner;
13
+ /**
14
+ * Wrap a base executor so its queries join the ambient transaction when one is running. Stores
15
+ * built over this participate in a `UnitOfWork` without knowing transactions exist.
16
+ */
17
+ readonly scoped: (base: SqlExecutor) => SqlExecutor;
18
+ };
19
+ /**
20
+ * A transaction scope over one connection source. The `AsyncLocalStorage` is private to the scope, so
21
+ * two scopes over two different databases cannot pick up each other's transaction — a real hazard
22
+ * when a process holds several executors, as the conformance suite does.
23
+ */
24
+ export declare const createTransactionScope: (open: ConnectionOpener) => TransactionScope;
25
+ /**
26
+ * Opener over a single shared connection — PGlite, and any other single-connection executor.
27
+ *
28
+ * Serialised deliberately. One connection cannot hold two transactions, so concurrent callers must
29
+ * queue or their `BEGIN`/`COMMIT` pairs interleave into nonsense. The conformance suite fires four
30
+ * concurrent claims at the coordinator, so this is exercised rather than theoretical.
31
+ *
32
+ * The consequence to keep in mind: on this opener, concurrency is *simulated*. It proves ordering and
33
+ * single-flight, never that the database adjudicates a genuine race — which is why #98's AC-1 has a
34
+ * separate two-connection test that only runs against a real server.
35
+ */
36
+ export declare const createSingleConnectionOpener: (sql: SqlExecutor) => ConnectionOpener;
37
+ //# sourceMappingURL=transaction.d.ts.map
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Transactions for the PostgreSQL adapters (#98).
3
+ *
4
+ * **Why this file has to exist.** `SqlExecutor` is `{ query(text, params) }`, and in production it
5
+ * wraps `pg.Pool` — where `pool.query` takes *a different connection each call*. So `BEGIN`, the
6
+ * work, and `COMMIT` issued as three `query` calls land on three connections and guarantee nothing.
7
+ * Every transactional promise in this SPEC is unreachable through the bare interface.
8
+ *
9
+ * It appears to work under PGlite because PGlite is one embedded connection, so `BEGIN` on it happens
10
+ * to scope everything after — which is what #97's AC-3 test relied on. Correct locally, wrong on a
11
+ * real server. That is the class of bug the CI Postgres service exists to catch.
12
+ *
13
+ * **Why the transaction is ambient.** The port is `UnitOfWork.run<T>(fn: () => Promise<T>)` — the
14
+ * callback receives *nothing*. A store constructed before the transaction has no parameter through
15
+ * which it could be told about one, and the conformance harness constructs it exactly that way. So
16
+ * either the port widens (a bigger decision than this SPEC) or the transaction is discovered from the
17
+ * async context. `AsyncLocalStorage` is that mechanism: `scoped()` wraps a base executor so it uses
18
+ * the ambient transaction's connection while one is running, and the pool otherwise.
19
+ *
20
+ * The cost of ambient propagation is honest to state: it is invisible at the call site. A store built
21
+ * over a *non*-scoped executor silently escapes the transaction rather than failing. See the open
22
+ * question on #98.
23
+ */
24
+ import { AsyncLocalStorage } from "node:async_hooks";
25
+ /**
26
+ * A transaction scope over one connection source. The `AsyncLocalStorage` is private to the scope, so
27
+ * two scopes over two different databases cannot pick up each other's transaction — a real hazard
28
+ * when a process holds several executors, as the conformance suite does.
29
+ */
30
+ export const createTransactionScope = (open) => {
31
+ const active = new AsyncLocalStorage();
32
+ const runner = {
33
+ async transaction(fn) {
34
+ const current = active.getStore();
35
+ // Nested: a savepoint on the connection we are already holding. Taking a second connection
36
+ // here would deadlock against the row locks the outer transaction is holding.
37
+ if (current) {
38
+ const name = `agentkit_sp_${current.depth}`;
39
+ await current.sql.query(`SAVEPOINT ${name}`);
40
+ try {
41
+ const result = await active.run({ sql: current.sql, depth: current.depth + 1 }, () => fn(current.sql));
42
+ await current.sql.query(`RELEASE SAVEPOINT ${name}`);
43
+ return result;
44
+ }
45
+ catch (error) {
46
+ // Best-effort: if the rollback itself fails the connection is already unusable, and the
47
+ // original error is the one worth propagating.
48
+ await current.sql.query(`ROLLBACK TO SAVEPOINT ${name}`).catch(() => undefined);
49
+ throw error;
50
+ }
51
+ }
52
+ return open(async (sql) => {
53
+ await sql.query("BEGIN");
54
+ try {
55
+ const result = await active.run({ sql, depth: 1 }, () => fn(sql));
56
+ await sql.query("COMMIT");
57
+ return result;
58
+ }
59
+ catch (error) {
60
+ await sql.query("ROLLBACK").catch(() => undefined);
61
+ throw error;
62
+ }
63
+ });
64
+ },
65
+ };
66
+ const scoped = (base) => ({
67
+ query(text, params) {
68
+ return (active.getStore()?.sql ?? base).query(text, params);
69
+ },
70
+ });
71
+ return { runner, scoped };
72
+ };
73
+ /**
74
+ * Opener over a single shared connection — PGlite, and any other single-connection executor.
75
+ *
76
+ * Serialised deliberately. One connection cannot hold two transactions, so concurrent callers must
77
+ * queue or their `BEGIN`/`COMMIT` pairs interleave into nonsense. The conformance suite fires four
78
+ * concurrent claims at the coordinator, so this is exercised rather than theoretical.
79
+ *
80
+ * The consequence to keep in mind: on this opener, concurrency is *simulated*. It proves ordering and
81
+ * single-flight, never that the database adjudicates a genuine race — which is why #98's AC-1 has a
82
+ * separate two-connection test that only runs against a real server.
83
+ */
84
+ export const createSingleConnectionOpener = (sql) => {
85
+ let tail = Promise.resolve();
86
+ return (fn) => {
87
+ // Chained off both outcomes: a rejected predecessor must not strand every later caller.
88
+ const result = tail.then(() => fn(sql), () => fn(sql));
89
+ tail = result.then(() => undefined, () => undefined);
90
+ return result;
91
+ };
92
+ };
93
+ //# sourceMappingURL=transaction.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * PostgreSQL `UnitOfWork` (#98) — the mechanism that makes "usage and session state written
3
+ * atomically in the completion transaction" true rather than aspirational.
4
+ *
5
+ * Thin on purpose. All of the substance is in `transaction.ts`: the runner holds one connection for
6
+ * the duration and binds it to the async context, so stores built over a `scoped()` executor join the
7
+ * transaction without being passed anything. This function only has to translate the port's
8
+ * zero-argument `run` onto that.
9
+ *
10
+ * The reference in-memory adapter cannot do this — it offers caller-registered compensations through
11
+ * its own `runTx`, which the bare port cannot express, which is why `unitOfWorkConformance` gates the
12
+ * rollback case on the `transactions` capability. Postgres is the first adapter for which that gate
13
+ * opens, so that case now runs for real instead of standing down everywhere.
14
+ */
15
+ import type { UnitOfWork } from "../../persistence/index.js";
16
+ import type { TransactionRunner } from "./transaction.js";
17
+ export declare const createPostgresUnitOfWork: (runner: TransactionRunner) => UnitOfWork;
18
+ //# sourceMappingURL=unit-of-work.d.ts.map
@@ -0,0 +1,8 @@
1
+ export const createPostgresUnitOfWork = (runner) => ({
2
+ run(fn) {
3
+ // The executor is deliberately dropped: the port gives `fn` no parameter to receive it through,
4
+ // so propagation is ambient (see transaction.ts). Nested `run` calls become savepoints.
5
+ return runner.transaction(() => fn());
6
+ },
7
+ });
8
+ //# sourceMappingURL=unit-of-work.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * PostgreSQL `UsageLimitStore` — admin-configured spend limits (#175).
3
+ *
4
+ * `principal_id IS NULL` is the tenant default; a non-null row overrides it for one person. One table rather than
5
+ * two, because "the default" and "an override" are the same kind of fact — and resolution is then a single query
6
+ * ordered by specificity rather than two queries and a merge in application code.
7
+ *
8
+ * Every limit column is nullable and NULL means **unbounded**, not zero. That direction matches `QuotaLimits` and
9
+ * is the whole reason it is stated twice: a misconfigured quota that blocks everything is an outage, and one that
10
+ * blocks nothing is a bill the rollups make visible. An outage is only visible to the customer it happens to.
11
+ */
12
+ import type { UsageLimitStore } from "../../persistence/index.js";
13
+ import type { SqlExecutor } from "./sql.js";
14
+ export declare const createPostgresUsageLimitStore: (sql: SqlExecutor) => UsageLimitStore;
15
+ //# sourceMappingURL=usage-limits.d.ts.map