@cursor/july 0.1.39 → 0.1.41

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 (259) hide show
  1. package/AGENTS.md +4 -3
  2. package/dist/bin/agent-serve.js +28 -9
  3. package/dist/channels/slack/api.d.ts.map +1 -1
  4. package/dist/channels/slack/api.js +18 -8
  5. package/dist/channels/slack/attachments.d.ts +82 -0
  6. package/dist/channels/slack/attachments.d.ts.map +1 -0
  7. package/dist/channels/slack/attachments.js +520 -0
  8. package/dist/channels/slack/cursor-account.d.ts +7 -1
  9. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  10. package/dist/channels/slack/cursor-account.js +2 -2
  11. package/dist/channels/slack/defaults.d.ts.map +1 -1
  12. package/dist/channels/slack/defaults.js +26 -17
  13. package/dist/channels/slack/dispatch.d.ts +4 -3
  14. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  15. package/dist/channels/slack/dispatch.js +84 -21
  16. package/dist/channels/slack/inbound.d.ts +6 -0
  17. package/dist/channels/slack/inbound.d.ts.map +1 -1
  18. package/dist/channels/slack/inbound.js +48 -2
  19. package/dist/channels/slack/index.d.ts +1 -0
  20. package/dist/channels/slack/index.d.ts.map +1 -1
  21. package/dist/channels/slack/index.js +1 -0
  22. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  23. package/dist/channels/slack/live-delivery.js +16 -4
  24. package/dist/channels/slack/manifest.d.ts.map +1 -1
  25. package/dist/channels/slack/manifest.js +1 -0
  26. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  27. package/dist/channels/slack/slack-channel.js +7 -4
  28. package/dist/channels/slack/types.d.ts +49 -1
  29. package/dist/channels/slack/types.d.ts.map +1 -1
  30. package/dist/docs/404.html +2 -2
  31. package/dist/docs/ab.html +6 -6
  32. package/dist/docs/assets/{ab.md.6cLOW7--.js → ab.md.hdxsvX5M.js} +2 -2
  33. package/dist/docs/assets/{app.BQ8Hihdf.js → app.mIw24pb1.js} +1 -1
  34. package/dist/docs/assets/{building-with-agents.md.txrcGU2B.js → building-with-agents.md.PeZaZA1P.js} +1 -1
  35. package/dist/docs/assets/chunks/@localSearchIndexroot.BA7V8dEJ.js +1 -0
  36. package/dist/docs/assets/chunks/{VPLocalSearchBox.BBCr8Yuy.js → VPLocalSearchBox.hOzpPwrG.js} +1 -1
  37. package/dist/docs/assets/chunks/{theme.CK_NiGC-.js → theme.BtFhUYmh.js} +2 -2
  38. package/dist/docs/assets/{deployment.md.CuK5SNjN.js → deployment.md.BHVjVqRa.js} +4 -4
  39. package/dist/docs/assets/{deployment.md.CuK5SNjN.lean.js → deployment.md.BHVjVqRa.lean.js} +1 -1
  40. package/dist/docs/assets/{evals.md.BQXI3rXy.js → evals.md.qeoGgPw0.js} +3 -3
  41. package/dist/docs/assets/example-agents_index.md.xmJ87d_3.js +2 -0
  42. package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.js → guides_webhooks.md.DB-r_er9.js} +47 -4
  43. package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.lean.js → guides_webhooks.md.DB-r_er9.lean.js} +1 -1
  44. package/dist/docs/assets/index.md.BKpbkCa6.js +24 -0
  45. package/dist/docs/assets/{index.md.CmhptOmN.lean.js → index.md.BKpbkCa6.lean.js} +1 -1
  46. package/dist/docs/assets/{quickstart.md.C_b6ESpD.js → quickstart.md.rIbfahJM.js} +4 -4
  47. package/dist/docs/assets/{reference_cli.md.Byvrg8eu.js → reference_cli.md.DqEqQpGn.js} +5 -5
  48. package/dist/docs/assets/{reference_cli.md.Byvrg8eu.lean.js → reference_cli.md.DqEqQpGn.lean.js} +1 -1
  49. package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.js → reference_hooks.md.BHeG-vjK.js} +2 -2
  50. package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.lean.js → reference_hooks.md.BHeG-vjK.lean.js} +1 -1
  51. package/dist/docs/assets/{storage.md.mQDtIULc.js → storage.md.DcGSnIxX.js} +10 -4
  52. package/dist/docs/assets/{storage.md.mQDtIULc.lean.js → storage.md.DcGSnIxX.lean.js} +1 -1
  53. package/dist/docs/assets/troubleshooting.md.CkgwmVI0.js +1 -0
  54. package/dist/docs/assets/{troubleshooting.md.B5RVX_tL.lean.js → troubleshooting.md.CkgwmVI0.lean.js} +1 -1
  55. package/dist/docs/building-with-agents.html +5 -5
  56. package/dist/docs/concepts.html +3 -3
  57. package/dist/docs/deployment.html +6 -6
  58. package/dist/docs/evals.html +7 -7
  59. package/dist/docs/example-agents/approval-buddy.html +3 -3
  60. package/dist/docs/example-agents/benny.html +3 -3
  61. package/dist/docs/example-agents/bugbot.html +3 -3
  62. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  63. package/dist/docs/example-agents/codeowners-review.html +3 -3
  64. package/dist/docs/example-agents/concierge.html +3 -3
  65. package/dist/docs/example-agents/fsd.html +3 -3
  66. package/dist/docs/example-agents/index.html +5 -5
  67. package/dist/docs/example-agents/knowledge-base.html +3 -3
  68. package/dist/docs/example-agents/oncall.html +3 -3
  69. package/dist/docs/example-agents/security-reviewer.html +3 -3
  70. package/dist/docs/example-agents/slack-agent.html +3 -3
  71. package/dist/docs/example-agents/weather-agent.html +3 -3
  72. package/dist/docs/guides/agent-to-agent.html +3 -3
  73. package/dist/docs/guides/cloud-runtime.html +3 -3
  74. package/dist/docs/guides/github.html +3 -3
  75. package/dist/docs/guides/human-in-the-loop.html +3 -3
  76. package/dist/docs/guides/mcp-oauth.html +3 -3
  77. package/dist/docs/guides/slack.html +3 -3
  78. package/dist/docs/guides/webhooks.html +49 -6
  79. package/dist/docs/hashmap.json +1 -1
  80. package/dist/docs/hillclimbing.html +3 -3
  81. package/dist/docs/index.html +7 -7
  82. package/dist/docs/quickstart.html +8 -8
  83. package/dist/docs/reference/agent-config.html +3 -3
  84. package/dist/docs/reference/artifacts.html +3 -3
  85. package/dist/docs/reference/channels.html +3 -3
  86. package/dist/docs/reference/cli.html +8 -8
  87. package/dist/docs/reference/connections.html +3 -3
  88. package/dist/docs/reference/hooks.html +5 -5
  89. package/dist/docs/reference/http-api.html +3 -3
  90. package/dist/docs/reference/instructions.html +3 -3
  91. package/dist/docs/reference/playground.html +3 -3
  92. package/dist/docs/reference/project-layout.html +3 -3
  93. package/dist/docs/reference/prompt.html +3 -3
  94. package/dist/docs/reference/schedules.html +3 -3
  95. package/dist/docs/reference/sessions.html +3 -3
  96. package/dist/docs/reference/skills.html +3 -3
  97. package/dist/docs/reference/subagents.html +3 -3
  98. package/dist/docs/reference/tools.html +3 -3
  99. package/dist/docs/scaffolding-agents.html +3 -3
  100. package/dist/docs/storage.html +14 -8
  101. package/dist/docs/troubleshooting.html +5 -5
  102. package/dist/index.d.ts +4 -2
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +3 -1
  105. package/dist/internal/cli-ax.d.ts.map +1 -1
  106. package/dist/internal/cli-ax.js +22 -2
  107. package/dist/internal/cli-deploy.d.ts +6 -0
  108. package/dist/internal/cli-deploy.d.ts.map +1 -1
  109. package/dist/internal/cli-deploy.js +14 -4
  110. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
  111. package/dist/internal/cli-mcp-oauth.js +3 -1
  112. package/dist/internal/cli-mcp.js +4 -4
  113. package/dist/internal/cursor-event-relay.d.ts +45 -0
  114. package/dist/internal/cursor-event-relay.d.ts.map +1 -1
  115. package/dist/internal/cursor-event-relay.js +96 -2
  116. package/dist/internal/deploy-client.js +1 -1
  117. package/dist/internal/discovery.d.ts.map +1 -1
  118. package/dist/internal/discovery.js +35 -7
  119. package/dist/internal/distribution.d.ts.map +1 -1
  120. package/dist/internal/distribution.js +3 -1
  121. package/dist/internal/durable-session-store.d.ts +48 -0
  122. package/dist/internal/durable-session-store.d.ts.map +1 -0
  123. package/dist/internal/durable-session-store.js +86 -0
  124. package/dist/internal/hosting.d.ts +1 -1
  125. package/dist/internal/hosting.js +2 -2
  126. package/dist/internal/init-project.d.ts +34 -0
  127. package/dist/internal/init-project.d.ts.map +1 -1
  128. package/dist/internal/init-project.js +121 -2
  129. package/dist/internal/ledger-serving.d.ts +101 -0
  130. package/dist/internal/ledger-serving.d.ts.map +1 -0
  131. package/dist/internal/ledger-serving.js +174 -0
  132. package/dist/internal/listen-port.d.ts +22 -0
  133. package/dist/internal/listen-port.d.ts.map +1 -0
  134. package/dist/internal/listen-port.js +77 -0
  135. package/dist/internal/mcp-oauth.d.ts +12 -1
  136. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  137. package/dist/internal/mcp-oauth.js +25 -3
  138. package/dist/internal/playground/static.d.ts +21 -4
  139. package/dist/internal/playground/static.d.ts.map +1 -1
  140. package/dist/internal/playground/static.js +82 -18
  141. package/dist/internal/sdk-runner.d.ts.map +1 -1
  142. package/dist/internal/sdk-runner.js +10 -1
  143. package/dist/internal/server.d.ts.map +1 -1
  144. package/dist/internal/server.js +67 -49
  145. package/dist/internal/session-engine.d.ts +57 -1
  146. package/dist/internal/session-engine.d.ts.map +1 -1
  147. package/dist/internal/session-engine.js +117 -28
  148. package/dist/internal/slack-provision-client.js +1 -1
  149. package/dist/internal/workspace.d.ts +6 -2
  150. package/dist/internal/workspace.d.ts.map +1 -1
  151. package/dist/internal/workspace.js +10 -2
  152. package/dist/kv/memory-kv.d.ts +23 -0
  153. package/dist/kv/memory-kv.d.ts.map +1 -0
  154. package/dist/kv/memory-kv.js +103 -0
  155. package/dist/kv.d.ts +22 -0
  156. package/dist/kv.d.ts.map +1 -0
  157. package/dist/kv.js +20 -0
  158. package/dist/ledger/session-ledger.d.ts +204 -0
  159. package/dist/ledger/session-ledger.d.ts.map +1 -0
  160. package/dist/ledger/session-ledger.js +382 -0
  161. package/dist/ledger.d.ts +11 -0
  162. package/dist/ledger.d.ts.map +1 -0
  163. package/dist/ledger.js +9 -0
  164. package/dist/playground/assets/index-B3HBneZZ.js +85 -0
  165. package/dist/playground/assets/index-Bqk9nplh.css +1 -0
  166. package/dist/playground/index.html +2 -2
  167. package/dist/storage-backends/cursor-hosted.d.ts +25 -3
  168. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  169. package/dist/storage-backends/cursor-hosted.js +50 -2
  170. package/dist/storage-backends/file-kv.d.ts +5 -2
  171. package/dist/storage-backends/file-kv.d.ts.map +1 -1
  172. package/dist/storage-backends/file-kv.js +107 -7
  173. package/dist/storage.d.ts +60 -5
  174. package/dist/storage.d.ts.map +1 -1
  175. package/dist/storage.js +28 -4
  176. package/dist/types.d.ts +123 -3
  177. package/dist/types.d.ts.map +1 -1
  178. package/dist/types.js +14 -0
  179. package/docs/README.md +10 -7
  180. package/docs/ab.md +2 -2
  181. package/docs/building-with-agents.md +1 -1
  182. package/docs/deployment.md +34 -11
  183. package/docs/evals.md +3 -3
  184. package/docs/example-agents/index.md +1 -1
  185. package/docs/guides/webhooks.md +87 -0
  186. package/docs/quickstart.md +7 -8
  187. package/docs/reference/cli.md +15 -6
  188. package/docs/reference/hooks.md +8 -2
  189. package/docs/storage.md +67 -7
  190. package/docs/troubleshooting.md +10 -2
  191. package/package.json +20 -7
  192. package/skills/create-agent/SKILL.md +1 -1
  193. package/src/bin/agent-serve.ts +27 -11
  194. package/src/channels/slack/api.ts +19 -14
  195. package/src/channels/slack/attachments.ts +635 -0
  196. package/src/channels/slack/cursor-account.ts +8 -0
  197. package/src/channels/slack/defaults.ts +34 -18
  198. package/src/channels/slack/dispatch.ts +121 -6
  199. package/src/channels/slack/inbound.ts +60 -0
  200. package/src/channels/slack/index.ts +1 -0
  201. package/src/channels/slack/live-delivery.ts +17 -3
  202. package/src/channels/slack/manifest.ts +1 -0
  203. package/src/channels/slack/slack-channel.ts +7 -0
  204. package/src/channels/slack/types.ts +47 -1
  205. package/src/index.ts +9 -0
  206. package/src/internal/cli-ax.ts +25 -1
  207. package/src/internal/cli-deploy.ts +22 -4
  208. package/src/internal/cli-mcp-oauth.ts +3 -1
  209. package/src/internal/cli-mcp.ts +4 -4
  210. package/src/internal/cursor-event-relay.ts +168 -0
  211. package/src/internal/deploy-client.ts +1 -1
  212. package/src/internal/discovery.ts +42 -5
  213. package/src/internal/distribution.ts +3 -1
  214. package/src/internal/durable-session-store.ts +95 -0
  215. package/src/internal/hosting.ts +2 -2
  216. package/src/internal/init-project.ts +151 -2
  217. package/src/internal/ledger-serving.ts +240 -0
  218. package/src/internal/listen-port.ts +85 -0
  219. package/src/internal/mcp-oauth.ts +29 -4
  220. package/src/internal/playground/static.ts +111 -20
  221. package/src/internal/sdk-runner.ts +11 -1
  222. package/src/internal/server.ts +76 -62
  223. package/src/internal/session-engine.ts +192 -16
  224. package/src/internal/slack-provision-client.ts +1 -1
  225. package/src/internal/workspace.ts +14 -3
  226. package/src/kv/memory-kv.ts +99 -0
  227. package/src/kv.ts +27 -0
  228. package/src/ledger/session-ledger.ts +535 -0
  229. package/src/ledger.ts +29 -0
  230. package/src/storage-backends/cursor-hosted.ts +108 -3
  231. package/src/storage-backends/file-kv.ts +128 -12
  232. package/src/storage.ts +90 -6
  233. package/src/types.ts +130 -4
  234. package/dist/channels/slack/post-update-delivery.d.ts +0 -85
  235. package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
  236. package/dist/docs/assets/chunks/@localSearchIndexroot.B-VTH4As.js +0 -1
  237. package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +0 -2
  238. package/dist/docs/assets/index.md.CmhptOmN.js +0 -24
  239. package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +0 -1
  240. package/dist/internal/json-dir-store.d.ts +0 -32
  241. package/dist/internal/json-dir-store.d.ts.map +0 -1
  242. package/dist/internal/persistence-coordinator.d.ts +0 -127
  243. package/dist/internal/persistence-coordinator.d.ts.map +0 -1
  244. package/dist/multi-tenant.d.ts +0 -80
  245. package/dist/multi-tenant.d.ts.map +0 -1
  246. package/dist/multi-tenant.js +0 -69
  247. package/dist/persistence.d.ts +0 -184
  248. package/dist/persistence.d.ts.map +0 -1
  249. package/dist/playground/assets/index-BRhBbnd4.css +0 -1
  250. package/dist/playground/assets/index-_2WKw9a-.js +0 -85
  251. package/dist/storage-backends/postgres-kv.d.ts +0 -82
  252. package/dist/storage-backends/postgres-kv.d.ts.map +0 -1
  253. package/dist/storage-backends/postgres-kv.js +0 -185
  254. package/src/storage-backends/postgres-kv.ts +0 -253
  255. /package/dist/docs/assets/{ab.md.6cLOW7--.lean.js → ab.md.hdxsvX5M.lean.js} +0 -0
  256. /package/dist/docs/assets/{building-with-agents.md.txrcGU2B.lean.js → building-with-agents.md.PeZaZA1P.lean.js} +0 -0
  257. /package/dist/docs/assets/{evals.md.BQXI3rXy.lean.js → evals.md.qeoGgPw0.lean.js} +0 -0
  258. /package/dist/docs/assets/{example-agents_index.md.DgGBwckv.lean.js → example-agents_index.md.xmJ87d_3.lean.js} +0 -0
  259. /package/dist/docs/assets/{quickstart.md.C_b6ESpD.lean.js → quickstart.md.rIbfahJM.lean.js} +0 -0
@@ -8,8 +8,8 @@
8
8
  />
9
9
  <meta name="viewport" content="width=device-width, initial-scale=1" />
10
10
  <title>agent-serve playground</title>
11
- <script type="module" crossorigin src="./assets/index-_2WKw9a-.js"></script>
12
- <link rel="stylesheet" crossorigin href="./assets/index-BRhBbnd4.css">
11
+ <script type="module" crossorigin src="./assets/index-B3HBneZZ.js"></script>
12
+ <link rel="stylesheet" crossorigin href="./assets/index-Bqk9nplh.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
@@ -10,8 +10,7 @@
10
10
  * On Cursor-managed hosting the start script pins `CURSOR_API_BASE_URL` to
11
11
  * `https://api.cursor.com` (where the proxy is mounted). Locally, point
12
12
  * `CURSOR_API_BASE_URL` at a backend that mounts Agent Serve routes and use
13
- * a deployment SA key, or use `@cursor/july/storage/postgres-kv` /
14
- * `file-kv` instead.
13
+ * a deployment SA key, or use `@cursor/july/storage/file-kv` instead.
15
14
  *
16
15
  * ```ts
17
16
  * import { defineStorage } from "@cursor/july/storage";
@@ -22,7 +21,8 @@
22
21
  * });
23
22
  * ```
24
23
  */
25
- import type { StorageABTable, StorageConfig, StorageEvalsTable } from "../storage.js";
24
+ import type { StorageABTable, StorageCasTable, StorageConfig, StorageEvalsTable } from "../storage.js";
25
+ import type { JsonValue } from "../types.js";
26
26
  /**
27
27
  * Reserved so user `secrets set` cannot smuggle a Bugbot DSN into the pod.
28
28
  * Not injected by Cursor hosting (storage is HTTP-proxied).
@@ -63,9 +63,31 @@ export declare const CURSOR_HOSTED_STORAGE: unique symbol;
63
63
  export declare function isCursorHostedStorage(value: unknown): boolean;
64
64
  type CursorHostedStorageMethods = Required<Pick<StorageConfig, "put" | "get" | "delete" | "list">> & {
65
65
  readonly [CURSOR_HOSTED_STORAGE]: true;
66
+ cas: StorageCasTable;
66
67
  evals: StorageEvalsTable;
67
68
  abs: StorageABTable;
68
69
  };
70
+ /** Wire shape of the `get-with-version` route. `null` ⇒ JSON `undefined`. */
71
+ export interface KvGetWithVersionResponse {
72
+ found: boolean;
73
+ value: JsonValue | null;
74
+ version: string | null;
75
+ }
76
+ /** Wire shape of the `put-if-absent` / `put-if-version` routes. */
77
+ export interface KvCasResponse {
78
+ ok: boolean;
79
+ /** New version on success, else `null`. */
80
+ version: string | null;
81
+ /** Entry observed on conflict; `null` when the key is absent. */
82
+ current: {
83
+ value: JsonValue | null;
84
+ version: string;
85
+ } | null;
86
+ }
87
+ /** Wire shape of the `list-keys` route. */
88
+ export interface KvListKeysResponse {
89
+ keys: string[];
90
+ }
69
91
  /**
70
92
  * Cursor-hosted `defineStorage` methods (control-plane storage proxy →
71
93
  * Bugbot `agent_serve_*` tables). Spread into `defineStorage({...})`.
@@ -1 +1 @@
1
- {"version":3,"file":"cursor-hosted.d.ts","sourceRoot":"","sources":["../../src/storage-backends/cursor-hosted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAYvB;;;GAGG;AACH,eAAO,MAAM,+CAA+C,EAC1D,cAAuB,CAAC;AAE1B;;;GAGG;AACH,eAAO,MAAM,iCAAiC,EAC5C,2BAAoC,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS;IACpD,OAAO,+CAA+C;IACtD,OAAO,iCAAiC;CAIzC,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,OAAO,MAE1C,CAAC;AAEF,4EAA4E;AAC5E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM7D;AAED,KAAK,0BAA0B,GAAG,QAAQ,CACxC,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,CACvD,GAAG;IACF,QAAQ,CAAC,CAAC,qBAAqB,CAAC,EAAE,IAAI,CAAC;IACvC,KAAK,EAAE,iBAAiB,CAAC;IACzB,GAAG,EAAE,cAAc,CAAC;CACrB,CAAC;AA8DF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,0BAA+B,GACvC,0BAA0B,CA2F5B"}
1
+ {"version":3,"file":"cursor-hosted.d.ts","sourceRoot":"","sources":["../../src/storage-backends/cursor-hosted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,aAAa,EAEb,iBAAiB,EAClB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,SAAS,EAAiC,MAAM,aAAa,CAAC;AAW5E;;;GAGG;AACH,eAAO,MAAM,+CAA+C,EAC1D,cAAuB,CAAC;AAE1B;;;GAGG;AACH,eAAO,MAAM,iCAAiC,EAC5C,2BAAoC,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS;IACpD,OAAO,+CAA+C;IACtD,OAAO,iCAAiC;CAIzC,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,OAAO,MAE1C,CAAC;AAEF,4EAA4E;AAC5E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM7D;AAED,KAAK,0BAA0B,GAAG,QAAQ,CACxC,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,CACvD,GAAG;IACF,QAAQ,CAAC,CAAC,qBAAqB,CAAC,EAAE,IAAI,CAAC;IACvC,GAAG,EAAE,eAAe,CAAC;IACrB,KAAK,EAAE,iBAAiB,CAAC;IACzB,GAAG,EAAE,cAAc,CAAC;CACrB,CAAC;AA0BF,6EAA6E;AAC7E,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,2CAA2C;IAC3C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,iEAAiE;IACjE,OAAO,EAAE;QAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9D;AAED,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAiFD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,0BAA+B,GACvC,0BAA0B,CAmI5B"}
@@ -10,8 +10,7 @@
10
10
  * On Cursor-managed hosting the start script pins `CURSOR_API_BASE_URL` to
11
11
  * `https://api.cursor.com` (where the proxy is mounted). Locally, point
12
12
  * `CURSOR_API_BASE_URL` at a backend that mounts Agent Serve routes and use
13
- * a deployment SA key, or use `@cursor/july/storage/postgres-kv` /
14
- * `file-kv` instead.
13
+ * a deployment SA key, or use `@cursor/july/storage/file-kv` instead.
15
14
  *
16
15
  * ```ts
17
16
  * import { defineStorage } from "@cursor/july/storage";
@@ -70,6 +69,22 @@ export function isCursorHostedStorage(value) {
70
69
  value !== null &&
71
70
  value[CURSOR_HOSTED_STORAGE] === true);
72
71
  }
72
+ function toCasResult(response) {
73
+ var _a;
74
+ if (response.ok) {
75
+ if (response.version === null) {
76
+ throw new Error("cursorHostedStorage: CAS success without a version token");
77
+ }
78
+ return { ok: true, version: response.version };
79
+ }
80
+ const current = response.current === null
81
+ ? undefined
82
+ : {
83
+ value: (_a = response.current.value) !== null && _a !== void 0 ? _a : null,
84
+ version: response.current.version,
85
+ };
86
+ return { ok: false, current };
87
+ }
73
88
  function resolveApiKey(options) {
74
89
  var _a;
75
90
  var _b;
@@ -159,6 +174,39 @@ export function cursorHostedStorage(options = {}) {
159
174
  return result.entries;
160
175
  });
161
176
  },
177
+ // Conditional writes over the same proxy (server routes: see the CAS
178
+ // wire-protocol block above). The proxy scopes rows from the service
179
+ // account, so ctx is not part of the wire contract.
180
+ cas: {
181
+ getWithVersion(key) {
182
+ return __awaiter(this, void 0, void 0, function* () {
183
+ var _a;
184
+ const result = yield storageRpc(options, "/internal/agent-serve/storage/kv/get-with-version", { key });
185
+ if (!result.found || result.version === null) {
186
+ return undefined;
187
+ }
188
+ return { value: (_a = result.value) !== null && _a !== void 0 ? _a : null, version: result.version };
189
+ });
190
+ },
191
+ putIfAbsent(key, value) {
192
+ return __awaiter(this, void 0, void 0, function* () {
193
+ const result = yield storageRpc(options, "/internal/agent-serve/storage/kv/put-if-absent", { key, value });
194
+ return toCasResult(result);
195
+ });
196
+ },
197
+ putIfVersion(key, value, expectedVersion) {
198
+ return __awaiter(this, void 0, void 0, function* () {
199
+ const result = yield storageRpc(options, "/internal/agent-serve/storage/kv/put-if-version", { key, value, expectedVersion });
200
+ return toCasResult(result);
201
+ });
202
+ },
203
+ listKeys(prefix) {
204
+ return __awaiter(this, void 0, void 0, function* () {
205
+ const result = yield storageRpc(options, "/internal/agent-serve/storage/kv/list-keys", { prefix });
206
+ return result.keys;
207
+ });
208
+ },
209
+ },
162
210
  evals: {
163
211
  put(run, ctx) {
164
212
  return __awaiter(this, void 0, void 0, function* () {
@@ -4,7 +4,9 @@
4
4
  *
5
5
  * Implements the whole `defineStorage` surface with zero external
6
6
  * dependencies: the four KV methods against a flat directory of JSON files
7
- * (one file per key, filename = URI-encoded key), eval runs as
7
+ * (one file per key, filename = URI-encoded key), the `cas`
8
+ * group (single-process conditional writes — see the `cas` member below),
9
+ * eval runs as
8
10
  * `eval-runs/<agent>/<runId>.json`, and A/B metrics as
9
11
  * `ab/<agent>/samples.ndjson` (append-only) plus `ab/<agent>/snapshot.json`
10
12
  * (latest aggregate). KV keys carry the agent name inside the framework
@@ -24,7 +26,7 @@
24
26
  * real failure (anything else throws) — on the lazy-restore path a
25
27
  * throw correctly fails the follow-up instead of forking the session.
26
28
  */
27
- import type { StorageABTable, StorageConfig, StorageEvalsTable } from "../storage.js";
29
+ import type { StorageABTable, StorageCasTable, StorageConfig, StorageEvalsTable } from "../storage.js";
28
30
  export interface FileKvOptions {
29
31
  /**
30
32
  * Directory holding the storage files, relative to the agent project root
@@ -33,6 +35,7 @@ export interface FileKvOptions {
33
35
  dir?: string;
34
36
  }
35
37
  type FileKvMethods = Required<Pick<StorageConfig, "put" | "get" | "delete" | "list">> & {
38
+ cas: StorageCasTable;
36
39
  evals: StorageEvalsTable;
37
40
  abs: StorageABTable;
38
41
  };
@@ -1 +1 @@
1
- {"version":3,"file":"file-kv.d.ts","sourceRoot":"","sources":["../../src/storage-backends/file-kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAeH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAGb,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAGvB,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,KAAK,aAAa,GAAG,QAAQ,CAC3B,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,CACvD,GAAG;IACF,KAAK,EAAE,iBAAiB,CAAC;IACzB,GAAG,EAAE,cAAc,CAAC;CACrB,CAAC;AAEF,wFAAwF;AACxF,wBAAgB,MAAM,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,CA+I7D"}
1
+ {"version":3,"file":"file-kv.d.ts","sourceRoot":"","sources":["../../src/storage-backends/file-kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAeH,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,aAAa,EAGb,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAGvB,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,KAAK,aAAa,GAAG,QAAQ,CAC3B,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,CACvD,GAAG;IACF,GAAG,EAAE,eAAe,CAAC;IACrB,KAAK,EAAE,iBAAiB,CAAC;IACzB,GAAG,EAAE,cAAc,CAAC;CACrB,CAAC;AAEF,wFAAwF;AACxF,wBAAgB,MAAM,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,CA6O7D"}
@@ -4,7 +4,9 @@
4
4
  *
5
5
  * Implements the whole `defineStorage` surface with zero external
6
6
  * dependencies: the four KV methods against a flat directory of JSON files
7
- * (one file per key, filename = URI-encoded key), eval runs as
7
+ * (one file per key, filename = URI-encoded key), the `cas`
8
+ * group (single-process conditional writes — see the `cas` member below),
9
+ * eval runs as
8
10
  * `eval-runs/<agent>/<runId>.json`, and A/B metrics as
9
11
  * `ab/<agent>/samples.ndjson` (append-only) plus `ab/<agent>/snapshot.json`
10
12
  * (latest aggregate). KV keys carry the agent name inside the framework
@@ -33,20 +35,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
33
35
  step((generator = generator.apply(thisArg, _arguments || [])).next());
34
36
  });
35
37
  };
36
- import { randomUUID } from "node:crypto";
38
+ import { createHash, randomUUID } from "node:crypto";
37
39
  import { appendFile, mkdir, readdir, readFile, rename, rm, writeFile, } from "node:fs/promises";
38
- import { join } from "node:path";
40
+ import { isAbsolute, join } from "node:path";
39
41
  /** File-backed `defineStorage` methods, ready to spread into `defineStorage({...})`. */
40
42
  export function fileKv(options) {
41
- const resolveDir = (ctx) => { var _a; return join(ctx.projectRoot, (_a = options === null || options === void 0 ? void 0 : options.dir) !== null && _a !== void 0 ? _a : ".agent-serve/kv"); };
43
+ const resolveDir = (ctx) => {
44
+ var _a;
45
+ const dir = (_a = options === null || options === void 0 ? void 0 : options.dir) !== null && _a !== void 0 ? _a : ".agent-serve/kv";
46
+ return isAbsolute(dir) ? dir : join(ctx.projectRoot, dir);
47
+ };
42
48
  // The evals/abs tables are scoped per agent (KV keys already carry the
43
49
  // agent name via the framework key scheme).
44
50
  const evalRunsDir = (ctx) => join(resolveDir(ctx), "eval-runs", encodeURIComponent(ctx.agentName));
45
51
  const abDir = (ctx) => join(resolveDir(ctx), "ab", encodeURIComponent(ctx.agentName));
46
52
  const filePath = (ctx, key) => join(resolveDir(ctx), `${encodeURIComponent(key)}.json`);
47
- const readKey = (ctx, key) => __awaiter(this, void 0, void 0, function* () {
53
+ const readRaw = (ctx, key) => __awaiter(this, void 0, void 0, function* () {
48
54
  try {
49
- return JSON.parse(yield readFile(filePath(ctx, key), "utf8"));
55
+ return yield readFile(filePath(ctx, key), "utf8");
50
56
  }
51
57
  catch (error) {
52
58
  if (error.code === "ENOENT") {
@@ -55,6 +61,27 @@ export function fileKv(options) {
55
61
  throw error; // real failure: let lazy restore fail the follow-up
56
62
  }
57
63
  });
64
+ const readKey = (ctx, key) => __awaiter(this, void 0, void 0, function* () {
65
+ const text = yield readRaw(ctx, key);
66
+ return text === undefined ? undefined : JSON.parse(text);
67
+ });
68
+ const readVersioned = (ctx, key) => __awaiter(this, void 0, void 0, function* () {
69
+ const text = yield readRaw(ctx, key);
70
+ if (text === undefined) {
71
+ return undefined;
72
+ }
73
+ return { value: JSON.parse(text), version: versionOf(text) };
74
+ });
75
+ // In-process mutex: CAS check-then-write pairs queue on one promise
76
+ // chain so they cannot interleave with each other. Plain `put` stays
77
+ // outside the chain on purpose — it is unconditional LWW and always
78
+ // wins the key, like a SQL upsert would win the row.
79
+ let casChain = Promise.resolve();
80
+ const locked = (task) => {
81
+ const result = casChain.then(task, task);
82
+ casChain = result.then(() => undefined, () => undefined);
83
+ return result;
84
+ };
58
85
  return {
59
86
  put(key, value, ctx) {
60
87
  return __awaiter(this, void 0, void 0, function* () {
@@ -100,6 +127,65 @@ export function fileKv(options) {
100
127
  return entries;
101
128
  });
102
129
  },
130
+ // Conditional writes over the same raw value files — no on-disk format
131
+ // change, so data written before the CAS group existed stays readable
132
+ // and plain `put` stays byte-identical. The version token is a content
133
+ // hash of the stored JSON text: it changes whenever the value does,
134
+ // and the in-process mutex makes read-check-write atomic, so a token
135
+ // can never go stale between the check and the rename. The one caveat
136
+ // of hash versions — ABA when a value returns to identical bytes — is
137
+ // moot for coordination values that carry a monotonic counter. CAS
138
+ // correctness is **single-process only**: two pods sharing this
139
+ // directory would race between read and rename, so a file store is
140
+ // only safe for single-instance deployments.
141
+ cas: {
142
+ getWithVersion: (key, ctx) => readVersioned(ctx, key),
143
+ putIfAbsent: (key, value, ctx) => locked(() => __awaiter(this, void 0, void 0, function* () {
144
+ const current = yield readVersioned(ctx, key);
145
+ if (current !== undefined) {
146
+ return { ok: false, current };
147
+ }
148
+ const text = JSON.stringify(value);
149
+ yield writeTextAtomic({
150
+ dir: resolveDir(ctx),
151
+ fileName: `${encodeURIComponent(key)}.json`,
152
+ text,
153
+ });
154
+ return { ok: true, version: versionOf(text) };
155
+ })),
156
+ putIfVersion: (key, value, expectedVersion, ctx) => locked(() => __awaiter(this, void 0, void 0, function* () {
157
+ const current = yield readVersioned(ctx, key);
158
+ if (current === undefined || current.version !== expectedVersion) {
159
+ return { ok: false, current };
160
+ }
161
+ const text = JSON.stringify(value);
162
+ yield writeTextAtomic({
163
+ dir: resolveDir(ctx),
164
+ fileName: `${encodeURIComponent(key)}.json`,
165
+ text,
166
+ });
167
+ return { ok: true, version: versionOf(text) };
168
+ })),
169
+ listKeys(prefix, ctx) {
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ let names;
172
+ try {
173
+ names = yield readdir(resolveDir(ctx));
174
+ }
175
+ catch (error) {
176
+ if (error.code === "ENOENT") {
177
+ return [];
178
+ }
179
+ throw error;
180
+ }
181
+ return names
182
+ .filter((name) => name.endsWith(".json"))
183
+ .map((name) => decodeURIComponent(name.slice(0, -".json".length)))
184
+ .filter((key) => key.startsWith(prefix))
185
+ .sort();
186
+ });
187
+ },
188
+ },
103
189
  // Playground eval batches: one JSON file per run under eval-runs/<agent>/.
104
190
  evals: {
105
191
  put(run, ctx) {
@@ -179,12 +265,26 @@ export function fileKv(options) {
179
265
  },
180
266
  };
181
267
  }
268
+ /** Content-hash version token for a stored JSON text. */
269
+ function versionOf(text) {
270
+ return `sha256:${createHash("sha256").update(text, "utf8").digest("hex")}`;
271
+ }
182
272
  /** tmp + rename write so concurrent readers never see a torn file. */
183
273
  function writeJsonAtomic(args) {
274
+ return __awaiter(this, void 0, void 0, function* () {
275
+ yield writeTextAtomic({
276
+ dir: args.dir,
277
+ fileName: args.fileName,
278
+ text: JSON.stringify(args.value),
279
+ });
280
+ });
281
+ }
282
+ /** tmp + rename write of exact text (CAS hashes the same bytes it wrote). */
283
+ function writeTextAtomic(args) {
184
284
  return __awaiter(this, void 0, void 0, function* () {
185
285
  yield mkdir(args.dir, { recursive: true });
186
286
  const tmp = join(args.dir, `.tmp-${randomUUID()}`);
187
- yield writeFile(tmp, JSON.stringify(args.value), "utf8");
287
+ yield writeFile(tmp, args.text, "utf8");
188
288
  yield rename(tmp, join(args.dir, args.fileName));
189
289
  });
190
290
  }
package/dist/storage.d.ts CHANGED
@@ -6,9 +6,12 @@
6
6
  * pipeline, …). Without it, state lives under `--state-root` on local disk
7
7
  * only, and eval/A/B history stays in process memory.
8
8
  *
9
- * The sink is a plain key-value store — four functions, no schema — plus
10
- * two optional dedicated tables ({@link StorageConfig.evals} and
11
- * {@link StorageConfig.abs}) for eval-run and A/B history:
9
+ * The sink is a plain key-value store — put/get/delete/list, no schema —
10
+ * plus a conditional-write group ({@link StorageConfig.cas}, the substrate
11
+ * for framework coordination; optional for plain storage, required by
12
+ * coordination features) and two optional dedicated tables
13
+ * ({@link StorageConfig.evals} and {@link StorageConfig.abs}) for
14
+ * eval-run and A/B history:
12
15
  *
13
16
  * ```ts
14
17
  * import { defineStorage } from "@anysphere/agent-serve/storage";
@@ -18,6 +21,7 @@
18
21
  * get: (key) => db.get(key),
19
22
  * delete: (key) => db.delete(key),
20
23
  * list: (prefix) => db.listByPrefix(prefix), // [{ key, value }] in key order
24
+ * cas: { getWithVersion: ..., putIfAbsent: ..., putIfVersion: ..., listKeys: ... },
21
25
  * evals: { put: ..., delete: ..., list: ... }, // eval-runs table
22
26
  * abs: { putSample: ... }, // A/B table
23
27
  * });
@@ -47,7 +51,7 @@
47
51
  import type { ABMetricSample } from "./ab.js";
48
52
  import type { EvalRunSnapshot } from "./evals.js";
49
53
  import type { ABSnapshot } from "./internal/ab-snapshot.js";
50
- import type { JsonValue } from "./types.js";
54
+ import type { JsonValue, KvCasResult, KvVersionedEntry } from "./types.js";
51
55
  /** One `{ key, value }` pair returned by {@link StorageConfig.list}. */
52
56
  export interface StorageEntry {
53
57
  key: string;
@@ -64,8 +68,10 @@ export interface StorageContext {
64
68
  * - `"policy"` — a flush trigger fired (turn end, debounce, change)
65
69
  * - `"shutdown"` — the serve process is draining; last chance to write
66
70
  * - `"restore"` — serve start or a lazy restore; reads rebuilding state
71
+ * - `"coordination"` — framework coordination driving
72
+ * {@link StorageCasTable} (conditional writes)
67
73
  */
68
- reason: "policy" | "shutdown" | "restore";
74
+ reason: "policy" | "shutdown" | "restore" | "coordination";
69
75
  }
70
76
  export interface StoragePolicy {
71
77
  /**
@@ -135,6 +141,37 @@ export interface StorageABTable {
135
141
  /** Latest saved aggregate snapshot (replacement-host backfill). Optional. */
136
142
  getSnapshot?(ctx: StorageContext): ABSnapshot | undefined | null | Promise<ABSnapshot | undefined | null>;
137
143
  }
144
+ /**
145
+ * Conditional writes (CAS) — the coordination tier of the storage backend
146
+ * contract. Plain storage works without it, so existing backends keep
147
+ * working across a platform upgrade; framework coordination (the upcoming
148
+ * session ledger — see `@cursor/july/kv` for the backend-agnostic
149
+ * interface) requires it and fails at startup, with an actionable
150
+ * message, when the backend lacks it. The built-in backends all include
151
+ * it, so implementing this group yourself only comes up for BYO storage.
152
+ *
153
+ * Grouped under {@link StorageConfig.cas} rather than as loose methods —
154
+ * matching the `evals` / `abs` table groups — so `defineStorage`
155
+ * validates the whole group at once: there is no meaningful
156
+ * half-implementation.
157
+ *
158
+ * Version tokens are opaque per-key strings that change on every
159
+ * successful write (counter, UUID, content hash — whatever is cheap for
160
+ * the backend). See {@link KvVersionedEntry} / {@link KvCasResult}.
161
+ */
162
+ export interface StorageCasTable {
163
+ /** Read one value with its version token. Miss → `undefined`. */
164
+ getWithVersion(key: string, ctx: StorageContext): Promise<KvVersionedEntry | undefined> | KvVersionedEntry | undefined;
165
+ /** Create the key only when absent. Conflict returns the existing entry. */
166
+ putIfAbsent(key: string, value: JsonValue, ctx: StorageContext): Promise<KvCasResult> | KvCasResult;
167
+ /**
168
+ * Replace the value only when the key still carries `expectedVersion`.
169
+ * Conflict (version moved, or key deleted) returns the current entry.
170
+ */
171
+ putIfVersion(key: string, value: JsonValue, expectedVersion: string, ctx: StorageContext): Promise<KvCasResult> | KvCasResult;
172
+ /** All keys under a prefix, in ascending key order. */
173
+ listKeys(prefix: string, ctx: StorageContext): Promise<string[]> | string[];
174
+ }
138
175
  export interface StorageConfig {
139
176
  /** Optional label surfaced on `GET /v1/info` diagnostics. */
140
177
  name?: string;
@@ -150,6 +187,14 @@ export interface StorageConfig {
150
187
  * (session event logs remain the assignment/fold source of truth).
151
188
  */
152
189
  abs?: StorageABTable;
190
+ /**
191
+ * Conditional writes (CAS). Optional for plain storage — existing
192
+ * backends keep working without it — but required by coordination
193
+ * features (the session ledger), which fail fast when it is absent.
194
+ * The built-in backends (`fileKv`, `cursorHostedStorage`) both include
195
+ * it. See {@link StorageCasTable}.
196
+ */
197
+ cas?: StorageCasTable;
153
198
  /**
154
199
  * Store one value under a key (upsert, last-write-wins). Called on the
155
200
  * framework's schedule — never concurrently, always in order. Keep it
@@ -231,6 +276,16 @@ export declare const storageKeys: {
231
276
  * replaced by their SHA-256 digest, keeping every minted key bounded.
232
277
  */
233
278
  export declare const MAX_KEY_SEGMENT_BYTES = 256;
279
+ /**
280
+ * URI-encode one caller-controlled key segment, substituting a `sha256:…`
281
+ * digest of the raw value when the encoding exceeds
282
+ * {@link MAX_KEY_SEGMENT_BYTES}. Deterministic, so key construction on the
283
+ * write path and the continuation-lookup path always agree.
284
+ *
285
+ * Exported for the session ledger, which builds its `session/` and
286
+ * `ledger/` keys with the same encoding rules.
287
+ */
288
+ export declare function keySegment(raw: string): string;
234
289
  export declare const STORAGE_DEFAULT_RESTORE_MAX_SESSIONS = 1000;
235
290
  export declare const STORAGE_DEFAULT_RESTORE_MAX_AGE_MS: number;
236
291
  export declare const STORAGE_DEFAULT_RESTORE_MAX_TOTAL_BYTES = 1073741824;
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
package/dist/storage.js CHANGED
@@ -6,9 +6,12 @@
6
6
  * pipeline, …). Without it, state lives under `--state-root` on local disk
7
7
  * only, and eval/A/B history stays in process memory.
8
8
  *
9
- * The sink is a plain key-value store — four functions, no schema — plus
10
- * two optional dedicated tables ({@link StorageConfig.evals} and
11
- * {@link StorageConfig.abs}) for eval-run and A/B history:
9
+ * The sink is a plain key-value store — put/get/delete/list, no schema —
10
+ * plus a conditional-write group ({@link StorageConfig.cas}, the substrate
11
+ * for framework coordination; optional for plain storage, required by
12
+ * coordination features) and two optional dedicated tables
13
+ * ({@link StorageConfig.evals} and {@link StorageConfig.abs}) for
14
+ * eval-run and A/B history:
12
15
  *
13
16
  * ```ts
14
17
  * import { defineStorage } from "@anysphere/agent-serve/storage";
@@ -18,6 +21,7 @@
18
21
  * get: (key) => db.get(key),
19
22
  * delete: (key) => db.delete(key),
20
23
  * list: (prefix) => db.listByPrefix(prefix), // [{ key, value }] in key order
24
+ * cas: { getWithVersion: ..., putIfAbsent: ..., putIfVersion: ..., listKeys: ... },
21
25
  * evals: { put: ..., delete: ..., list: ... }, // eval-runs table
22
26
  * abs: { putSample: ... }, // A/B table
23
27
  * });
@@ -67,6 +71,23 @@ export function defineStorage(config) {
67
71
  }
68
72
  }
69
73
  }
74
+ if (config.cas !== undefined) {
75
+ const casHooks = [
76
+ "getWithVersion",
77
+ "putIfAbsent",
78
+ "putIfVersion",
79
+ "listKeys",
80
+ ];
81
+ const cas = config.cas;
82
+ // A partial group is a bug, not a legacy config: half-implemented CAS
83
+ // would pass the capability probe and corrupt coordination.
84
+ const missingCasHooks = casHooks.filter((hook) => typeof cas[hook] !== "function");
85
+ if (missingCasHooks.length > 0) {
86
+ throw new Error(`defineStorage: ${missingCasHooks
87
+ .map((hook) => `cas.${hook}`)
88
+ .join(", ")} must be ${missingCasHooks.length === 1 ? "a function" : "functions"} when the cas group is set`);
89
+ }
90
+ }
70
91
  if (config.abs !== undefined) {
71
92
  if (typeof config.abs.putSample !== "function") {
72
93
  throw new Error("defineStorage: abs.putSample must be a function when the abs table is set");
@@ -137,8 +158,11 @@ export const MAX_KEY_SEGMENT_BYTES = 256;
137
158
  * digest of the raw value when the encoding exceeds
138
159
  * {@link MAX_KEY_SEGMENT_BYTES}. Deterministic, so key construction on the
139
160
  * write path and the continuation-lookup path always agree.
161
+ *
162
+ * Exported for the session ledger, which builds its `session/` and
163
+ * `ledger/` keys with the same encoding rules.
140
164
  */
141
- function keySegment(raw) {
165
+ export function keySegment(raw) {
142
166
  const encoded = encodeURIComponent(raw);
143
167
  if (Buffer.byteLength(encoded, "utf8") <= MAX_KEY_SEGMENT_BYTES) {
144
168
  return encoded;