@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.
- package/AGENTS.md +4 -3
- package/dist/bin/agent-serve.js +28 -9
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +18 -8
- package/dist/channels/slack/attachments.d.ts +82 -0
- package/dist/channels/slack/attachments.d.ts.map +1 -0
- package/dist/channels/slack/attachments.js +520 -0
- package/dist/channels/slack/cursor-account.d.ts +7 -1
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +2 -2
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +26 -17
- package/dist/channels/slack/dispatch.d.ts +4 -3
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +84 -21
- package/dist/channels/slack/inbound.d.ts +6 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +48 -2
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +16 -4
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +1 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +7 -4
- package/dist/channels/slack/types.d.ts +49 -1
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +6 -6
- package/dist/docs/assets/{ab.md.6cLOW7--.js → ab.md.hdxsvX5M.js} +2 -2
- package/dist/docs/assets/{app.BQ8Hihdf.js → app.mIw24pb1.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.txrcGU2B.js → building-with-agents.md.PeZaZA1P.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BA7V8dEJ.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BBCr8Yuy.js → VPLocalSearchBox.hOzpPwrG.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CK_NiGC-.js → theme.BtFhUYmh.js} +2 -2
- package/dist/docs/assets/{deployment.md.CuK5SNjN.js → deployment.md.BHVjVqRa.js} +4 -4
- package/dist/docs/assets/{deployment.md.CuK5SNjN.lean.js → deployment.md.BHVjVqRa.lean.js} +1 -1
- package/dist/docs/assets/{evals.md.BQXI3rXy.js → evals.md.qeoGgPw0.js} +3 -3
- package/dist/docs/assets/example-agents_index.md.xmJ87d_3.js +2 -0
- package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.js → guides_webhooks.md.DB-r_er9.js} +47 -4
- package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.lean.js → guides_webhooks.md.DB-r_er9.lean.js} +1 -1
- package/dist/docs/assets/index.md.BKpbkCa6.js +24 -0
- package/dist/docs/assets/{index.md.CmhptOmN.lean.js → index.md.BKpbkCa6.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.C_b6ESpD.js → quickstart.md.rIbfahJM.js} +4 -4
- package/dist/docs/assets/{reference_cli.md.Byvrg8eu.js → reference_cli.md.DqEqQpGn.js} +5 -5
- package/dist/docs/assets/{reference_cli.md.Byvrg8eu.lean.js → reference_cli.md.DqEqQpGn.lean.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.js → reference_hooks.md.BHeG-vjK.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.lean.js → reference_hooks.md.BHeG-vjK.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.mQDtIULc.js → storage.md.DcGSnIxX.js} +10 -4
- package/dist/docs/assets/{storage.md.mQDtIULc.lean.js → storage.md.DcGSnIxX.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.CkgwmVI0.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.B5RVX_tL.lean.js → troubleshooting.md.CkgwmVI0.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +5 -5
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +7 -7
- package/dist/docs/example-agents/approval-buddy.html +3 -3
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +5 -5
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +3 -3
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +49 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +7 -7
- package/dist/docs/quickstart.html +8 -8
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/artifacts.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +8 -8
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +5 -5
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/prompt.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +14 -8
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +22 -2
- package/dist/internal/cli-deploy.d.ts +6 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +14 -4
- package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
- package/dist/internal/cli-mcp-oauth.js +3 -1
- package/dist/internal/cli-mcp.js +4 -4
- package/dist/internal/cursor-event-relay.d.ts +45 -0
- package/dist/internal/cursor-event-relay.d.ts.map +1 -1
- package/dist/internal/cursor-event-relay.js +96 -2
- package/dist/internal/deploy-client.js +1 -1
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +35 -7
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +3 -1
- package/dist/internal/durable-session-store.d.ts +48 -0
- package/dist/internal/durable-session-store.d.ts.map +1 -0
- package/dist/internal/durable-session-store.js +86 -0
- package/dist/internal/hosting.d.ts +1 -1
- package/dist/internal/hosting.js +2 -2
- package/dist/internal/init-project.d.ts +34 -0
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +121 -2
- package/dist/internal/ledger-serving.d.ts +101 -0
- package/dist/internal/ledger-serving.d.ts.map +1 -0
- package/dist/internal/ledger-serving.js +174 -0
- package/dist/internal/listen-port.d.ts +22 -0
- package/dist/internal/listen-port.d.ts.map +1 -0
- package/dist/internal/listen-port.js +77 -0
- package/dist/internal/mcp-oauth.d.ts +12 -1
- package/dist/internal/mcp-oauth.d.ts.map +1 -1
- package/dist/internal/mcp-oauth.js +25 -3
- package/dist/internal/playground/static.d.ts +21 -4
- package/dist/internal/playground/static.d.ts.map +1 -1
- package/dist/internal/playground/static.js +82 -18
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +10 -1
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +67 -49
- package/dist/internal/session-engine.d.ts +57 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +117 -28
- package/dist/internal/slack-provision-client.js +1 -1
- package/dist/internal/workspace.d.ts +6 -2
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +10 -2
- package/dist/kv/memory-kv.d.ts +23 -0
- package/dist/kv/memory-kv.d.ts.map +1 -0
- package/dist/kv/memory-kv.js +103 -0
- package/dist/kv.d.ts +22 -0
- package/dist/kv.d.ts.map +1 -0
- package/dist/kv.js +20 -0
- package/dist/ledger/session-ledger.d.ts +204 -0
- package/dist/ledger/session-ledger.d.ts.map +1 -0
- package/dist/ledger/session-ledger.js +382 -0
- package/dist/ledger.d.ts +11 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +9 -0
- package/dist/playground/assets/index-B3HBneZZ.js +85 -0
- package/dist/playground/assets/index-Bqk9nplh.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +25 -3
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +50 -2
- package/dist/storage-backends/file-kv.d.ts +5 -2
- package/dist/storage-backends/file-kv.d.ts.map +1 -1
- package/dist/storage-backends/file-kv.js +107 -7
- package/dist/storage.d.ts +60 -5
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +28 -4
- package/dist/types.d.ts +123 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +14 -0
- package/docs/README.md +10 -7
- package/docs/ab.md +2 -2
- package/docs/building-with-agents.md +1 -1
- package/docs/deployment.md +34 -11
- package/docs/evals.md +3 -3
- package/docs/example-agents/index.md +1 -1
- package/docs/guides/webhooks.md +87 -0
- package/docs/quickstart.md +7 -8
- package/docs/reference/cli.md +15 -6
- package/docs/reference/hooks.md +8 -2
- package/docs/storage.md +67 -7
- package/docs/troubleshooting.md +10 -2
- package/package.json +20 -7
- package/skills/create-agent/SKILL.md +1 -1
- package/src/bin/agent-serve.ts +27 -11
- package/src/channels/slack/api.ts +19 -14
- package/src/channels/slack/attachments.ts +635 -0
- package/src/channels/slack/cursor-account.ts +8 -0
- package/src/channels/slack/defaults.ts +34 -18
- package/src/channels/slack/dispatch.ts +121 -6
- package/src/channels/slack/inbound.ts +60 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/live-delivery.ts +17 -3
- package/src/channels/slack/manifest.ts +1 -0
- package/src/channels/slack/slack-channel.ts +7 -0
- package/src/channels/slack/types.ts +47 -1
- package/src/index.ts +9 -0
- package/src/internal/cli-ax.ts +25 -1
- package/src/internal/cli-deploy.ts +22 -4
- package/src/internal/cli-mcp-oauth.ts +3 -1
- package/src/internal/cli-mcp.ts +4 -4
- package/src/internal/cursor-event-relay.ts +168 -0
- package/src/internal/deploy-client.ts +1 -1
- package/src/internal/discovery.ts +42 -5
- package/src/internal/distribution.ts +3 -1
- package/src/internal/durable-session-store.ts +95 -0
- package/src/internal/hosting.ts +2 -2
- package/src/internal/init-project.ts +151 -2
- package/src/internal/ledger-serving.ts +240 -0
- package/src/internal/listen-port.ts +85 -0
- package/src/internal/mcp-oauth.ts +29 -4
- package/src/internal/playground/static.ts +111 -20
- package/src/internal/sdk-runner.ts +11 -1
- package/src/internal/server.ts +76 -62
- package/src/internal/session-engine.ts +192 -16
- package/src/internal/slack-provision-client.ts +1 -1
- package/src/internal/workspace.ts +14 -3
- package/src/kv/memory-kv.ts +99 -0
- package/src/kv.ts +27 -0
- package/src/ledger/session-ledger.ts +535 -0
- package/src/ledger.ts +29 -0
- package/src/storage-backends/cursor-hosted.ts +108 -3
- package/src/storage-backends/file-kv.ts +128 -12
- package/src/storage.ts +90 -6
- package/src/types.ts +130 -4
- package/dist/channels/slack/post-update-delivery.d.ts +0 -85
- package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.B-VTH4As.js +0 -1
- package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +0 -2
- package/dist/docs/assets/index.md.CmhptOmN.js +0 -24
- package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +0 -1
- package/dist/internal/json-dir-store.d.ts +0 -32
- package/dist/internal/json-dir-store.d.ts.map +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/multi-tenant.d.ts +0 -80
- package/dist/multi-tenant.d.ts.map +0 -1
- package/dist/multi-tenant.js +0 -69
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/index-BRhBbnd4.css +0 -1
- package/dist/playground/assets/index-_2WKw9a-.js +0 -85
- package/dist/storage-backends/postgres-kv.d.ts +0 -82
- package/dist/storage-backends/postgres-kv.d.ts.map +0 -1
- package/dist/storage-backends/postgres-kv.js +0 -185
- package/src/storage-backends/postgres-kv.ts +0 -253
- /package/dist/docs/assets/{ab.md.6cLOW7--.lean.js → ab.md.hdxsvX5M.lean.js} +0 -0
- /package/dist/docs/assets/{building-with-agents.md.txrcGU2B.lean.js → building-with-agents.md.PeZaZA1P.lean.js} +0 -0
- /package/dist/docs/assets/{evals.md.BQXI3rXy.lean.js → evals.md.qeoGgPw0.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_index.md.DgGBwckv.lean.js → example-agents_index.md.xmJ87d_3.lean.js} +0 -0
- /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-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
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/
|
|
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
|
|
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/
|
|
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),
|
|
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
|
|
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),
|
|
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) => {
|
|
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
|
|
53
|
+
const readRaw = (ctx, key) => __awaiter(this, void 0, void 0, function* () {
|
|
48
54
|
try {
|
|
49
|
-
return
|
|
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,
|
|
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 —
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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;
|
package/dist/storage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA
|
|
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 —
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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;
|