@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,206 @@
1
+ /**
2
+ * Flow definitions and executions in Postgres — #187, #186.
3
+ *
4
+ * Two things are enforced by the schema rather than by this file, because a rule in code is a rule one code path
5
+ * can miss:
6
+ *
7
+ * - **A version cannot be overwritten.** `(tenant_id, flow_id, version)` is the primary key and the insert has no
8
+ * `ON CONFLICT`, so a second write of the same version is a constraint violation. An execution pins a version
9
+ * and reads it for its whole life; a definition that could change under it would change an automation's shape
10
+ * halfway through.
11
+ * - **A save cannot move an execution backwards.** The update carries `WHERE steps <= $n`, so a stale document
12
+ * from a slower worker updates nothing. A flow that goes backwards re-performs external writes, which is the
13
+ * failure the whole module exists to prevent — and doing it in the `WHERE` means two concurrent saves are
14
+ * ordered by the database rather than by whichever read happened first.
15
+ */
16
+ import { AgentPlatformError } from "../../core/errors.js";
17
+ const int = (value) => (typeof value === "number" ? value : Number.parseInt(value, 10));
18
+ const iso = (value) => (value instanceof Date ? value.toISOString() : value);
19
+ const toDefinition = (row) => ({
20
+ flowId: row.flow_id,
21
+ version: int(row.version),
22
+ name: row.name,
23
+ kind: row.kind === "team" ? "team" : "flow",
24
+ // `jsonb` comes back parsed from `pg`, and as a string from some executors. Handling both means the adapter
25
+ // works under PGlite and a pool without a second code path for "which driver is this".
26
+ definition: typeof row.definition === "string" ? JSON.parse(row.definition) : row.definition,
27
+ createdAt: iso(row.created_at),
28
+ ...(row.created_by === null ? {} : { createdBy: row.created_by }),
29
+ });
30
+ const take = (limit) => Math.max(1, Math.min(limit ?? 50, 500));
31
+ export const createPostgresFlowDefinitionStore = (sql) => ({
32
+ async put({ tenantId, definition }) {
33
+ try {
34
+ await sql.query(`INSERT INTO flow_definitions (tenant_id, flow_id, version, name, kind, definition, created_at, created_by)
35
+ VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7::timestamptz, $8)`, [
36
+ tenantId,
37
+ definition.flowId,
38
+ definition.version,
39
+ definition.name,
40
+ definition.kind,
41
+ JSON.stringify(definition.definition),
42
+ definition.createdAt,
43
+ definition.createdBy ?? null,
44
+ ]);
45
+ }
46
+ catch (error) {
47
+ /**
48
+ * Translated, not passed through.
49
+ *
50
+ * The port's contract is that overwriting a version is refused; a caller should not have to recognise a
51
+ * Postgres unique-violation code to know that happened. Anything else is rethrown, because swallowing an
52
+ * unrelated failure here would report a conflict for a disk that is full.
53
+ */
54
+ const code = error.code;
55
+ if (code === "23505" || /duplicate key|unique/i.test(String(error.message))) {
56
+ throw new AgentPlatformError({
57
+ code: "conflict",
58
+ message: `${definition.flowId} version ${definition.version} already exists — publish a new version instead`,
59
+ retryable: false,
60
+ });
61
+ }
62
+ throw error;
63
+ }
64
+ },
65
+ async get({ tenantId, flowId, version }) {
66
+ const rows = await sql.query(`SELECT flow_id, version, name, kind, definition, created_at, created_by
67
+ FROM flow_definitions WHERE tenant_id = $1 AND flow_id = $2 AND version = $3`, [tenantId, flowId, version]);
68
+ return rows[0] === undefined ? null : toDefinition(rows[0]);
69
+ },
70
+ async latest({ tenantId, flowId }) {
71
+ const rows = await sql.query(`SELECT flow_id, version, name, kind, definition, created_at, created_by
72
+ FROM flow_definitions WHERE tenant_id = $1 AND flow_id = $2
73
+ ORDER BY version DESC LIMIT 1`, [tenantId, flowId]);
74
+ return rows[0] === undefined ? null : toDefinition(rows[0]);
75
+ },
76
+ async list({ tenantId, limit, cursor }) {
77
+ const size = take(limit);
78
+ /**
79
+ * The latest version per flow, in one query.
80
+ *
81
+ * `DISTINCT ON` rather than a window function or a join against a grouped subquery: it is the shortest
82
+ * statement that says "one row per flow_id, the highest version", and a caller asking what flows exist means
83
+ * distinct flows rather than every version of every one.
84
+ */
85
+ const rows = await sql.query(`SELECT * FROM (
86
+ SELECT DISTINCT ON (flow_id) flow_id, version, name, kind, definition, created_at, created_by
87
+ FROM flow_definitions WHERE tenant_id = $1
88
+ ORDER BY flow_id, version DESC
89
+ ) latest
90
+ WHERE ($2::text IS NULL OR flow_id > $2)
91
+ ORDER BY flow_id
92
+ LIMIT $3`, [tenantId, cursor ?? null, size + 1]);
93
+ const page = rows.slice(0, size).map(toDefinition);
94
+ return {
95
+ items: page,
96
+ ...(rows.length > size && page.length > 0 ? { nextCursor: page[page.length - 1].flowId } : {}),
97
+ };
98
+ },
99
+ });
100
+ const toExecution = (row) => ({
101
+ id: row.id,
102
+ flowId: row.flow_id,
103
+ flowVersion: int(row.flow_version),
104
+ runId: row.run_id,
105
+ status: row.status,
106
+ currentStep: row.current_step,
107
+ steps: int(row.steps),
108
+ execution: typeof row.execution === "string" ? JSON.parse(row.execution) : row.execution,
109
+ ...(row.waiting_signal === null ? {} : { waitingSignal: row.waiting_signal }),
110
+ ...(row.waiting_run_id === null ? {} : { waitingRunId: row.waiting_run_id }),
111
+ startedAt: iso(row.started_at),
112
+ ...(row.finished_at === null ? {} : { finishedAt: iso(row.finished_at) }),
113
+ });
114
+ const EXECUTION_COLUMNS = `id, flow_id, flow_version, run_id, status, current_step, steps, execution,
115
+ waiting_signal, waiting_run_id, started_at, finished_at`;
116
+ export const createPostgresFlowExecutionStore = (sql) => ({
117
+ async create({ tenantId, execution }) {
118
+ try {
119
+ await sql.query(`INSERT INTO flow_executions
120
+ (tenant_id, id, flow_id, flow_version, run_id, status, current_step, steps, execution,
121
+ waiting_signal, waiting_run_id, started_at, finished_at)
122
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::jsonb, $10, $11, $12::timestamptz, $13::timestamptz)`, [
123
+ tenantId,
124
+ execution.id,
125
+ execution.flowId,
126
+ execution.flowVersion,
127
+ execution.runId,
128
+ execution.status,
129
+ execution.currentStep,
130
+ execution.steps,
131
+ JSON.stringify(execution.execution),
132
+ execution.waitingSignal ?? null,
133
+ execution.waitingRunId ?? null,
134
+ execution.startedAt,
135
+ execution.finishedAt ?? null,
136
+ ]);
137
+ }
138
+ catch (error) {
139
+ const code = error.code;
140
+ if (code === "23505" || /duplicate key|unique/i.test(String(error.message))) {
141
+ throw new AgentPlatformError({
142
+ code: "conflict",
143
+ message: `flow execution ${execution.id} already exists`,
144
+ retryable: false,
145
+ });
146
+ }
147
+ throw error;
148
+ }
149
+ },
150
+ async save({ tenantId, execution }) {
151
+ /**
152
+ * `steps <= $8` in the predicate, so the database orders two concurrent saves.
153
+ *
154
+ * `<=` and not `<`: parking on a question completes no step, so an equal count is a legitimate status change.
155
+ * Rejecting it would make "waiting" unrecordable, which is a whole class of state that could never be stored.
156
+ */
157
+ await sql.query(`UPDATE flow_executions
158
+ SET status = $3, current_step = $4, steps = $5, execution = $6::jsonb,
159
+ waiting_signal = $7, waiting_run_id = $10, finished_at = $9::timestamptz
160
+ WHERE tenant_id = $1 AND id = $2 AND steps <= $8`, [
161
+ tenantId,
162
+ execution.id,
163
+ execution.status,
164
+ execution.currentStep,
165
+ execution.steps,
166
+ JSON.stringify(execution.execution),
167
+ execution.waitingSignal ?? null,
168
+ execution.steps,
169
+ execution.finishedAt ?? null,
170
+ execution.waitingRunId ?? null,
171
+ ]);
172
+ },
173
+ async get({ tenantId, executionId }) {
174
+ const rows = await sql.query(`SELECT ${EXECUTION_COLUMNS} FROM flow_executions WHERE tenant_id = $1 AND id = $2`, [tenantId, executionId]);
175
+ return rows[0] === undefined ? null : toExecution(rows[0]);
176
+ },
177
+ async waitingOnSignal({ tenantId, signal, limit }) {
178
+ // `status = 'waiting'` in the predicate, not only the signal: a signal must not resume an execution that
179
+ // never asked for it, and a stale `waiting_signal` on a running row is exactly that.
180
+ const rows = await sql.query(`SELECT ${EXECUTION_COLUMNS} FROM flow_executions
181
+ WHERE tenant_id = $1 AND status = 'waiting' AND waiting_signal = $2
182
+ ORDER BY started_at LIMIT $3`, [tenantId, signal, take(limit)]);
183
+ return rows.map(toExecution);
184
+ },
185
+ async waitingOnRun({ tenantId, runId }) {
186
+ // `status = 'waiting'` as well as the id: a stale `waiting_run_id` on a running execution is not something a
187
+ // settled run should resume, because it is not waiting for one.
188
+ const rows = await sql.query(`SELECT ${EXECUTION_COLUMNS} FROM flow_executions
189
+ WHERE tenant_id = $1 AND status = 'waiting' AND waiting_run_id = $2
190
+ LIMIT 1`, [tenantId, runId]);
191
+ return rows[0] === undefined ? null : toExecution(rows[0]);
192
+ },
193
+ async listByFlow({ tenantId, flowId, limit, cursor }) {
194
+ const size = take(limit);
195
+ const rows = await sql.query(`SELECT ${EXECUTION_COLUMNS} FROM flow_executions
196
+ WHERE tenant_id = $1 AND flow_id = $2 AND ($3::text IS NULL OR id > $3)
197
+ ORDER BY started_at DESC, id
198
+ LIMIT $4`, [tenantId, flowId, cursor ?? null, size + 1]);
199
+ const page = rows.slice(0, size).map(toExecution);
200
+ return {
201
+ items: page,
202
+ ...(rows.length > size && page.length > 0 ? { nextCursor: page[page.length - 1].id } : {}),
203
+ };
204
+ },
205
+ });
206
+ //# sourceMappingURL=flows.js.map
@@ -0,0 +1,5 @@
1
+ import type { ApprovalGrantStore, InteractionStore } from "../../persistence/index.js";
2
+ import type { SqlExecutor } from "./sql.js";
3
+ export declare const createPostgresInteractionStore: (sql: SqlExecutor) => InteractionStore;
4
+ export declare const createPostgresApprovalGrantStore: (sql: SqlExecutor) => ApprovalGrantStore;
5
+ //# sourceMappingURL=hitl.d.ts.map
@@ -0,0 +1,247 @@
1
+ /**
2
+ * PostgreSQL `InteractionStore` and `ApprovalGrantStore` (#99) — durable questions, approvals and
3
+ * standing grants.
4
+ *
5
+ * Approvals gate every external write, so the two failure modes are asymmetric but both bad: a lost
6
+ * approval blocks the work forever, and a *replayed* one authorises the same side effect twice — a
7
+ * duplicate publish, a duplicate charge. The second is why `idempotency_key` carries a unique index
8
+ * and why resolution is a compare-and-set rather than a read-then-write.
9
+ *
10
+ * **Resolution is guarded in the statement.** `UPDATE … WHERE answered_at IS NULL RETURNING *`: zero
11
+ * rows means someone already resolved it, so the store reads back to distinguish "already resolved"
12
+ * from "no such interaction". A read-then-write would let two concurrent answers both report
13
+ * `alreadyResolved: false`, and the harness is explicit about what that costs — the continuation gets
14
+ * queued twice.
15
+ */
16
+ import { AgentPlatformError } from "../../core/errors.js";
17
+ const notFound = (id) => new AgentPlatformError({ code: "not_found", message: `Interaction ${id} not found`, retryable: false });
18
+ const iso = (v) => (v instanceof Date ? v.toISOString() : new Date(v).toISOString());
19
+ const isoOrUndefined = (v) => (v === null ? undefined : iso(v));
20
+ /** jsonb arrives parsed from PGlite and as text from some drivers; normalise both. */
21
+ const json = (value) => (typeof value === "string" ? JSON.parse(value) : value);
22
+ const toQuestion = (r) => ({
23
+ id: r.id,
24
+ tenantId: r.tenant_id,
25
+ runId: r.run_id,
26
+ questions: json(r.questions),
27
+ createdAt: iso(r.created_at),
28
+ // Spread-in rather than assigned: the type marks both optional, and writing `answeredAt: undefined`
29
+ // would put the key in the object with an undefined value, which `toEqual` treats differently.
30
+ ...(r.answered_at === null ? {} : { answeredAt: iso(r.answered_at) }),
31
+ ...(r.answers === null || r.answers === undefined
32
+ ? {}
33
+ : { answers: json(r.answers) }),
34
+ });
35
+ const QUESTION_COLUMNS = `tenant_id, id, run_id, questions, created_at, answered_at, answers`;
36
+ const toApproval = (r) => ({
37
+ id: r.id,
38
+ tenantId: r.tenant_id,
39
+ runId: r.run_id,
40
+ toolName: r.tool_name,
41
+ normalizedInput: json(r.normalized_input),
42
+ riskCategory: r.risk_category,
43
+ summary: r.summary,
44
+ ...(r.estimated_cost_minor_units === null
45
+ ? {}
46
+ : { estimatedCostMinorUnits: r.estimated_cost_minor_units }),
47
+ expiresAt: iso(r.expires_at),
48
+ idempotencyKey: r.idempotency_key,
49
+ ...(r.decided_at === null ? {} : { decidedAt: iso(r.decided_at) }),
50
+ ...(r.decision === null ? {} : { decision: r.decision }),
51
+ ...(r.consumed_at === null ? {} : { consumedAt: iso(r.consumed_at) }),
52
+ });
53
+ const APPROVAL_COLUMNS = `tenant_id, id, run_id, tool_name, normalized_input, risk_category, summary,
54
+ estimated_cost_minor_units, expires_at, idempotency_key, decided_at, decision, consumed_at`;
55
+ export const createPostgresInteractionStore = (sql) => {
56
+ const readQuestion = async (tenantId, id) => {
57
+ const rows = await sql.query(`SELECT ${QUESTION_COLUMNS} FROM interaction_questions WHERE tenant_id = $1 AND id = $2`, [tenantId, id]);
58
+ const row = rows[0];
59
+ return row ? toQuestion(row) : null;
60
+ };
61
+ const readApproval = async (tenantId, id) => {
62
+ const rows = await sql.query(`SELECT ${APPROVAL_COLUMNS} FROM interaction_approvals WHERE tenant_id = $1 AND id = $2`, [tenantId, id]);
63
+ const row = rows[0];
64
+ return row ? toApproval(row) : null;
65
+ };
66
+ return {
67
+ async createQuestion({ tenantId, question }) {
68
+ await sql.query(`INSERT INTO interaction_questions (tenant_id, id, run_id, questions, created_at, answered_at, answers)
69
+ VALUES ($1, $2, $3, $4::jsonb, $5::timestamptz, $6::timestamptz, $7::jsonb)
70
+ ON CONFLICT (tenant_id, id) DO NOTHING`, [
71
+ tenantId,
72
+ question.id,
73
+ question.runId,
74
+ JSON.stringify(question.questions),
75
+ question.createdAt,
76
+ question.answeredAt ?? null,
77
+ question.answers === undefined ? null : JSON.stringify(question.answers),
78
+ ]);
79
+ },
80
+ async findPendingQuestion({ tenantId, runId }) {
81
+ const rows = await sql.query(`SELECT ${QUESTION_COLUMNS} FROM interaction_questions
82
+ WHERE tenant_id = $1 AND run_id = $2 AND answered_at IS NULL
83
+ ORDER BY created_at, id
84
+ LIMIT 1`, [tenantId, runId]);
85
+ const row = rows[0];
86
+ return row ? toQuestion(row) : null;
87
+ },
88
+ /**
89
+ * The newest answered question for the run — #163. Ordered by `answered_at` rather than `created_at`: a run
90
+ * that asked twice has both answered, and the one to tell the model about is the one just answered.
91
+ */
92
+ async findAnsweredQuestion({ tenantId, runId }) {
93
+ const rows = await sql.query(`SELECT ${QUESTION_COLUMNS} FROM interaction_questions
94
+ WHERE tenant_id = $1 AND run_id = $2 AND answered_at IS NOT NULL
95
+ ORDER BY answered_at DESC, id DESC
96
+ LIMIT 1`, [tenantId, runId]);
97
+ const row = rows[0];
98
+ return row ? toQuestion(row) : null;
99
+ },
100
+ async answerQuestion({ tenantId, interactionId, answers, at }) {
101
+ // The guard is `answered_at IS NULL`, so exactly one of two concurrent answers can win. The
102
+ // loser gets zero rows and reports alreadyResolved, which is what keeps the continuation from
103
+ // being queued twice.
104
+ const rows = await sql.query(`UPDATE interaction_questions
105
+ SET answered_at = $3::timestamptz, answers = $4::jsonb
106
+ WHERE tenant_id = $1 AND id = $2 AND answered_at IS NULL
107
+ RETURNING ${QUESTION_COLUMNS}`, [tenantId, interactionId, at, JSON.stringify(answers)]);
108
+ const row = rows[0];
109
+ if (row)
110
+ return { question: toQuestion(row), alreadyResolved: false };
111
+ const existing = await readQuestion(tenantId, interactionId);
112
+ if (!existing)
113
+ throw notFound(interactionId);
114
+ return { question: existing, alreadyResolved: true };
115
+ },
116
+ async createApproval({ tenantId, approval }) {
117
+ await sql.query(`INSERT INTO interaction_approvals
118
+ (tenant_id, id, run_id, tool_name, normalized_input, risk_category, summary,
119
+ estimated_cost_minor_units, expires_at, idempotency_key, decided_at, decision, consumed_at)
120
+ VALUES ($1, $2, $3, $4, $5::jsonb, $6, $7, $8, $9::timestamptz, $10, $11::timestamptz, $12,
121
+ $13::timestamptz)
122
+ ON CONFLICT (tenant_id, id) DO NOTHING`, [
123
+ tenantId,
124
+ approval.id,
125
+ approval.runId,
126
+ approval.toolName,
127
+ JSON.stringify(approval.normalizedInput ?? null),
128
+ approval.riskCategory,
129
+ approval.summary,
130
+ approval.estimatedCostMinorUnits ?? null,
131
+ approval.expiresAt,
132
+ approval.idempotencyKey,
133
+ approval.decidedAt ?? null,
134
+ approval.decision ?? null,
135
+ approval.consumedAt ?? null,
136
+ ]);
137
+ },
138
+ async findPendingApproval({ tenantId, runId }) {
139
+ const rows = await sql.query(`SELECT ${APPROVAL_COLUMNS} FROM interaction_approvals
140
+ WHERE tenant_id = $1 AND run_id = $2 AND decided_at IS NULL
141
+ ORDER BY expires_at, id
142
+ LIMIT 1`, [tenantId, runId]);
143
+ const row = rows[0];
144
+ return row ? toApproval(row) : null;
145
+ },
146
+ async decideApproval({ tenantId, interactionId, decision, at }) {
147
+ // AC-5 lives here: a denied approval can never become granted, because the second decision
148
+ // matches no row and the store returns the stored one unchanged.
149
+ const rows = await sql.query(`UPDATE interaction_approvals
150
+ SET decided_at = $3::timestamptz, decision = $4
151
+ WHERE tenant_id = $1 AND id = $2 AND decided_at IS NULL
152
+ RETURNING ${APPROVAL_COLUMNS}`, [tenantId, interactionId, at, decision]);
153
+ const row = rows[0];
154
+ if (row)
155
+ return { approval: toApproval(row), alreadyResolved: false };
156
+ const existing = await readApproval(tenantId, interactionId);
157
+ if (!existing)
158
+ throw notFound(interactionId);
159
+ return { approval: existing, alreadyResolved: true };
160
+ },
161
+ async findApproval({ tenantId, interactionId }) {
162
+ return readApproval(tenantId, interactionId);
163
+ },
164
+ async findDecidedApproval({ tenantId, runId }) {
165
+ const rows = await sql.query(`SELECT ${APPROVAL_COLUMNS} FROM interaction_approvals
166
+ WHERE tenant_id = $1 AND run_id = $2 AND decided_at IS NOT NULL AND consumed_at IS NULL
167
+ ORDER BY decided_at, id
168
+ LIMIT 1`, [tenantId, runId]);
169
+ const row = rows[0];
170
+ return row ? toApproval(row) : null;
171
+ },
172
+ async claimApproval({ tenantId, interactionId, at }) {
173
+ // The whole of `allow-once` is this WHERE clause. `consumed_at IS NULL` is what makes the claim
174
+ // exclusive under concurrency, and `decided_at IS NOT NULL` is what stops an undecided
175
+ // interaction from being claimable at all — an unwired dependency must never become permission.
176
+ const rows = await sql.query(`UPDATE interaction_approvals
177
+ SET consumed_at = $3::timestamptz
178
+ WHERE tenant_id = $1 AND id = $2 AND decided_at IS NOT NULL AND consumed_at IS NULL
179
+ RETURNING ${APPROVAL_COLUMNS}`, [tenantId, interactionId, at]);
180
+ const row = rows[0];
181
+ if (row)
182
+ return { approval: toApproval(row), claimed: true };
183
+ const existing = await readApproval(tenantId, interactionId);
184
+ if (!existing)
185
+ throw notFound(interactionId);
186
+ return { approval: existing, claimed: false };
187
+ },
188
+ };
189
+ };
190
+ const toGrant = (r) => ({
191
+ id: r.id,
192
+ tenantId: r.tenant_id,
193
+ scope: r.scope,
194
+ toolNameOrCategory: r.tool_name_or_category,
195
+ ...(r.conversation_id === null ? {} : { conversationId: r.conversation_id }),
196
+ grantedAt: iso(r.granted_at),
197
+ ...(isoOrUndefined(r.expires_at) === undefined ? {} : { expiresAt: iso(r.expires_at) }),
198
+ ...(isoOrUndefined(r.revoked_at) === undefined ? {} : { revokedAt: iso(r.revoked_at) }),
199
+ });
200
+ const GRANT_COLUMNS = `tenant_id, id, scope, tool_name_or_category, conversation_id,
201
+ granted_at, expires_at, revoked_at`;
202
+ export const createPostgresApprovalGrantStore = (sql) => ({
203
+ async grant({ tenantId, grant }) {
204
+ await sql.query(`INSERT INTO approval_grants
205
+ (tenant_id, id, scope, tool_name_or_category, conversation_id, granted_at, expires_at, revoked_at)
206
+ VALUES ($1, $2, $3, $4, $5, $6::timestamptz, $7::timestamptz, $8::timestamptz)
207
+ ON CONFLICT (tenant_id, id) DO UPDATE
208
+ SET scope = excluded.scope,
209
+ tool_name_or_category = excluded.tool_name_or_category,
210
+ conversation_id = excluded.conversation_id,
211
+ granted_at = excluded.granted_at,
212
+ expires_at = excluded.expires_at,
213
+ revoked_at = excluded.revoked_at`, [
214
+ tenantId,
215
+ grant.id,
216
+ grant.scope,
217
+ grant.toolNameOrCategory,
218
+ grant.conversationId ?? null,
219
+ grant.grantedAt,
220
+ grant.expiresAt ?? null,
221
+ grant.revokedAt ?? null,
222
+ ]);
223
+ },
224
+ async findActive({ tenantId, toolNameOrCategory, now, conversationId }) {
225
+ // The scope predicate is the safety-critical part. A conversation-scoped grant must match only
226
+ // its own conversation and must not match at all when no conversation is supplied — otherwise a
227
+ // one-conversation approval silently becomes a standing one. Expressed as SQL rather than
228
+ // filtered afterwards so the index can serve it and no code path can skip it.
229
+ const rows = await sql.query(`SELECT ${GRANT_COLUMNS} FROM approval_grants
230
+ WHERE tenant_id = $1
231
+ AND tool_name_or_category = $2
232
+ AND revoked_at IS NULL
233
+ AND (expires_at IS NULL OR expires_at > $3::timestamptz)
234
+ AND (scope <> 'conversation' OR ($4::text IS NOT NULL AND conversation_id = $4::text))
235
+ ORDER BY granted_at DESC, id
236
+ LIMIT 1`, [tenantId, toolNameOrCategory, now, conversationId ?? null]);
237
+ const row = rows[0];
238
+ return row ? toGrant(row) : null;
239
+ },
240
+ async revoke({ tenantId, grantId, at }) {
241
+ // Silent on a missing grant, matching the reference adapter: revoking something that is not there
242
+ // has already achieved its purpose, and throwing would make idempotent revocation impossible.
243
+ await sql.query(`UPDATE approval_grants SET revoked_at = $3::timestamptz
244
+ WHERE tenant_id = $1 AND id = $2 AND revoked_at IS NULL`, [tenantId, grantId, at]);
245
+ },
246
+ });
247
+ //# sourceMappingURL=hitl.js.map
@@ -0,0 +1,35 @@
1
+ /**
2
+ * PostgreSQL adapters — the production reference storage. Implements the storage ports over a
3
+ * `SqlExecutor`; verified by the shared conformance harness.
4
+ */
5
+ import type { AdapterCapability } from "../../persistence/index.js";
6
+ export * from "./sql.js";
7
+ export * from "./migrations.js";
8
+ export * from "./schema.js";
9
+ export * from "./conversation-store.js";
10
+ export * from "./run-store.js";
11
+ export * from "./run-event-log.js";
12
+ export * from "./checkpoint-store.js";
13
+ export * from "./message-store.js";
14
+ export * from "./session-state.js";
15
+ export * from "./transaction.js";
16
+ export * from "./run-coordinator.js";
17
+ export * from "./unit-of-work.js";
18
+ export * from "./hitl.js";
19
+ export * from "./usage.js";
20
+ export * from "./usage-limits.js";
21
+ export * from "./config.js";
22
+ export * from "./memory.js";
23
+ export * from "./pg-executor.js";
24
+ /** Capabilities a PostgreSQL deployment can advertise (docs/02 capability declarations). */
25
+ export declare const POSTGRES_CAPABILITIES: readonly AdapterCapability[];
26
+ export * from "./files.js";
27
+ export * from "./artifacts.js";
28
+ export * from "./artifact-exports.js";
29
+ export * from "./knowledge.js";
30
+ export * from "./rollups.js";
31
+ export * from "./evaluation.js";
32
+ export * from "./retention.js";
33
+ export * from "./file-content.js";
34
+ export * from "./flows.js";
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,35 @@
1
+ export * from "./sql.js";
2
+ export * from "./migrations.js";
3
+ export * from "./schema.js";
4
+ export * from "./conversation-store.js";
5
+ export * from "./run-store.js";
6
+ export * from "./run-event-log.js";
7
+ export * from "./checkpoint-store.js";
8
+ export * from "./message-store.js";
9
+ export * from "./session-state.js";
10
+ export * from "./transaction.js";
11
+ export * from "./run-coordinator.js";
12
+ export * from "./unit-of-work.js";
13
+ export * from "./hitl.js";
14
+ export * from "./usage.js";
15
+ export * from "./usage-limits.js";
16
+ export * from "./config.js";
17
+ export * from "./memory.js";
18
+ export * from "./pg-executor.js";
19
+ /** Capabilities a PostgreSQL deployment can advertise (docs/02 capability declarations). */
20
+ export const POSTGRES_CAPABILITIES = [
21
+ "transactions",
22
+ "row-level-security",
23
+ "full-text-search",
24
+ "distributed-locking",
25
+ ];
26
+ export * from "./files.js";
27
+ export * from "./artifacts.js";
28
+ export * from "./artifact-exports.js";
29
+ export * from "./knowledge.js";
30
+ export * from "./rollups.js";
31
+ export * from "./evaluation.js";
32
+ export * from "./retention.js";
33
+ export * from "./file-content.js";
34
+ export * from "./flows.js";
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * pgvector `KnowledgeStore` and `VectorIndex` (#135).
3
+ *
4
+ * One table backs both ports, which is the point of splitting them: a deployment on pgvector answers both from
5
+ * `knowledge_chunks`, and a deployment on a dedicated vector database answers them from two systems, with
6
+ * nothing above changing.
7
+ *
8
+ * **AC-3 is a `WHERE` clause, and it is the reason this adapter exists rather than a filter above it.** The
9
+ * permission predicate is in the same statement as the nearest-neighbour scan, so an unauthorised chunk is
10
+ * never a candidate. Filtering afterwards leaks through result counts — ask for ten, get three, and you have
11
+ * learned that seven exist you may not see. `EXPLAIN` shows the predicate inside the scan, which is what the
12
+ * test asserts.
13
+ *
14
+ * **`replaceSource` is one transaction-shaped pair of statements.** Delete-then-insert, in that order, so a
15
+ * changed document's old chunks are never searchable alongside its new ones. Appending would leave a stale
16
+ * chunk that cites text no longer in the document.
17
+ */
18
+ import type { EmbeddingModelRef, KeywordIndex, KnowledgeStore, VectorIndex } from "../../persistence/index.js";
19
+ import type { SqlExecutor } from "./sql.js";
20
+ /**
21
+ * pgvector's literal form: `[0.1,0.2,...]`.
22
+ *
23
+ * Built as a string rather than passed as an array, because node-postgres has no vector type and would send an
24
+ * array as `{...}` — which pgvector rejects. `Number.isFinite` is checked because a `NaN` in a vector makes
25
+ * every distance `NaN`, and the symptom is a search that returns nothing rather than an error.
26
+ */
27
+ export declare const toVectorLiteral: (embedding: readonly number[]) => string;
28
+ export declare const createPostgresKnowledgeStore: (sql: SqlExecutor) => KnowledgeStore;
29
+ export declare const createPostgresVectorIndex: (sql: SqlExecutor) => VectorIndex;
30
+ /** Re-exported so a caller comparing a stored chunk's model to the current one does it the same way. */
31
+ export declare const sameEmbeddingModel: (a: EmbeddingModelRef, b: EmbeddingModelRef) => boolean;
32
+ /**
33
+ * Postgres full-text `KeywordIndex` (#136).
34
+ *
35
+ * Over `knowledge_chunks.content_tsv`, the same rows the vector index searches, so a chunk cannot be visible to
36
+ * one signal and invisible to the other.
37
+ *
38
+ * **`websearch_to_tsquery`, not `to_tsquery`.** The latter throws on ordinary user input — an unbalanced quote,
39
+ * a bare `&`, a trailing operator — and a search box that errors on a stray character is a search box that
40
+ * errors. `websearch_to_tsquery` accepts anything and interprets quotes and `or` the way a person expects.
41
+ *
42
+ * **The score is normalised against the best hit in the result set**, not against an absolute. `ts_rank_cd`
43
+ * has no upper bound and its scale depends on the corpus, so an absolute threshold would mean different things
44
+ * in different tenants — and fusing an unbounded score with a bounded cosine similarity would let the
45
+ * unbounded one dominate whenever it happened to be larger.
46
+ */
47
+ export declare const createPostgresKeywordIndex: (sql: SqlExecutor) => KeywordIndex;
48
+ //# sourceMappingURL=knowledge.d.ts.map