@cursor/july 0.1.7 → 0.1.9
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/dist/bin/agent-serve.js +31 -2
- package/dist/channels/slack/channel-watch.d.ts +6 -1
- package/dist/channels/slack/channel-watch.d.ts.map +1 -1
- package/dist/channels/slack/channel-watch.js +22 -1
- package/dist/channels/slack/cursor-account.d.ts +4 -0
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +12 -2
- package/dist/channels/slack/defaults.d.ts +10 -5
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +39 -17
- package/dist/channels/slack/dispatch.d.ts +18 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +141 -38
- package/dist/channels/slack/inbound.d.ts +13 -3
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +17 -9
- package/dist/channels/slack/index.d.ts +4 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +4 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +1 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +3 -0
- package/dist/channels/slack/nudge-carrier.d.ts +19 -0
- package/dist/channels/slack/nudge-carrier.d.ts.map +1 -0
- package/dist/channels/slack/nudge-carrier.js +166 -0
- package/dist/channels/slack/nudge-store.d.ts +61 -0
- package/dist/channels/slack/nudge-store.d.ts.map +1 -0
- package/dist/channels/slack/nudge-store.js +266 -0
- package/dist/channels/slack/post-update-delivery.js +318 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +74 -25
- package/dist/channels/slack/stop.d.ts +14 -0
- package/dist/channels/slack/stop.d.ts.map +1 -0
- package/dist/channels/slack/stop.js +22 -0
- package/dist/channels/slack/thread-context.d.ts +81 -0
- package/dist/channels/slack/thread-context.d.ts.map +1 -0
- package/dist/channels/slack/thread-context.js +470 -0
- package/dist/channels/slack/types.d.ts +27 -0
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.COTN7wgo.js → app.Ciosf24M.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.D154Detj.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BW3TBdT0.js → VPLocalSearchBox.BcRDly7n.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BEJW0vE7.js → theme.CMpbjdfx.js} +2 -2
- package/dist/docs/assets/{deployment.md.BtfEsc9S.js → deployment.md.DC5-ImcM.js} +1 -1
- package/dist/docs/assets/{example-agents_approval-buddy.md.8R5phXb5.js → example-agents_approval-buddy.md.DFGBYLcc.js} +2 -2
- package/dist/docs/assets/{example-agents_approval-buddy.md.8R5phXb5.lean.js → example-agents_approval-buddy.md.DFGBYLcc.lean.js} +1 -1
- package/dist/docs/assets/example-agents_index.md.BPXjUtRB.js +2 -0
- package/dist/docs/assets/example-agents_index.md.BPXjUtRB.lean.js +1 -0
- package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.js +10 -0
- package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.lean.js +1 -0
- package/dist/docs/assets/{example-agents_security-reviewer.md.D2rtwDTO.js → example-agents_security-reviewer.md.CE9v-aKm.js} +2 -2
- package/dist/docs/assets/{example-agents_security-reviewer.md.D2rtwDTO.lean.js → example-agents_security-reviewer.md.CE9v-aKm.lean.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.CCwqHvSV.js → guides_slack.md.FWale6Ip.js} +4 -3
- package/dist/docs/assets/{guides_slack.md.CCwqHvSV.lean.js → guides_slack.md.FWale6Ip.lean.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.DdjWabnN.js → reference_sessions.md.DLd6mvbv.js} +2 -2
- package/dist/docs/assets/{reference_sessions.md.DdjWabnN.lean.js → reference_sessions.md.DLd6mvbv.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.CVnInNiN.js → storage.md.DRTdnFvd.js} +9 -2
- package/dist/docs/assets/{storage.md.CVnInNiN.lean.js → storage.md.DRTdnFvd.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +4 -4
- package/dist/docs/example-agents/approval-buddy.html +5 -5
- package/dist/docs/example-agents/benny.html +5 -5
- package/dist/docs/example-agents/bugbot.html +5 -5
- package/dist/docs/example-agents/codebase-wiki.html +4 -4
- package/dist/docs/example-agents/codeowners-review.html +4 -4
- package/dist/docs/example-agents/concierge.html +4 -4
- package/dist/docs/example-agents/fsd.html +4 -4
- package/dist/docs/example-agents/index.html +6 -6
- package/dist/docs/example-agents/knowledge-base.html +4 -4
- package/dist/docs/example-agents/oncall.html +34 -0
- package/dist/docs/example-agents/security-reviewer.html +6 -6
- package/dist/docs/example-agents/slack-agent.html +4 -4
- package/dist/docs/example-agents/weather-agent.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/slack.html +7 -6
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +4 -4
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +4 -4
- package/dist/docs/reference/connections.html +4 -4
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +4 -4
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/storage.html +13 -6
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +45 -18
- package/dist/internal/cli-mcp.d.ts +64 -0
- package/dist/internal/cli-mcp.d.ts.map +1 -0
- package/dist/internal/cli-mcp.js +570 -0
- package/dist/internal/deploy-client.d.ts +7 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +3 -0
- package/dist/internal/deploy-source.d.ts +3 -0
- package/dist/internal/deploy-source.d.ts.map +1 -1
- package/dist/internal/deploy-source.js +25 -7
- package/dist/internal/discovery.js +1 -1
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +3 -0
- package/dist/internal/host-kv.d.ts +17 -0
- package/dist/internal/host-kv.d.ts.map +1 -0
- package/dist/internal/host-kv.js +77 -0
- package/dist/internal/hosting.d.ts +12 -2
- package/dist/internal/hosting.d.ts.map +1 -1
- package/dist/internal/hosting.js +21 -4
- package/dist/internal/json-dir-store.js +100 -0
- package/dist/internal/logs-client.d.ts +16 -2
- package/dist/internal/logs-client.d.ts.map +1 -1
- package/dist/internal/logs-client.js +51 -16
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +8 -0
- package/dist/internal/session-engine.d.ts +42 -7
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +276 -66
- package/dist/internal/storage-coordinator.d.ts +18 -1
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +43 -0
- package/dist/internal/workspace.d.ts +19 -0
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +47 -13
- package/dist/playground/assets/{index-72vCOBWO.js → index-C0-QEG4O.js} +42 -42
- package/dist/playground/assets/index-z3JY9O2x.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +65 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -0
- package/dist/storage-backends/cursor-hosted.js +203 -0
- package/dist/storage-backends/file-kv.d.ts +42 -0
- package/dist/storage-backends/file-kv.d.ts.map +1 -0
- package/dist/storage-backends/file-kv.js +190 -0
- package/dist/storage-backends/postgres-kv.d.ts +82 -0
- package/dist/storage-backends/postgres-kv.d.ts.map +1 -0
- package/dist/storage-backends/postgres-kv.js +185 -0
- package/dist/storage.d.ts +10 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +10 -1
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/.vitepress/cache/deps/package.json +3 -0
- package/docs/deployment.md +7 -3
- package/docs/example-agents/approval-buddy.md +1 -1
- package/docs/example-agents/index.md +15 -10
- package/docs/example-agents/oncall.md +216 -0
- package/docs/example-agents/security-reviewer.md +5 -5
- package/docs/guides/slack.md +11 -2
- package/docs/reference/sessions.md +13 -4
- package/docs/storage.md +41 -0
- package/package.json +22 -1
- package/skills/framework-map/SKILL.md +6 -4
- package/src/bin/agent-serve.ts +32 -2
- package/src/channels/slack/channel-watch.ts +28 -1
- package/src/channels/slack/cursor-account.ts +20 -0
- package/src/channels/slack/defaults.ts +51 -20
- package/src/channels/slack/dispatch.ts +215 -40
- package/src/channels/slack/inbound.ts +30 -10
- package/src/channels/slack/index.ts +4 -0
- package/src/channels/slack/live-delivery.ts +1 -0
- package/src/channels/slack/manifest.ts +3 -0
- package/src/channels/slack/nudge-carrier.ts +182 -0
- package/src/channels/slack/nudge-store.ts +308 -0
- package/src/channels/slack/slack-channel.ts +106 -31
- package/src/channels/slack/stop.ts +25 -0
- package/src/channels/slack/thread-context.ts +572 -0
- package/src/channels/slack/types.ts +27 -0
- package/src/internal/cli-deploy.ts +58 -20
- package/src/internal/cli-mcp.ts +708 -0
- package/src/internal/deploy-client.ts +11 -0
- package/src/internal/deploy-source.ts +24 -6
- package/src/internal/discovery.ts +1 -1
- package/src/internal/distribution.ts +3 -0
- package/src/internal/host-kv.ts +85 -0
- package/src/internal/hosting.ts +24 -4
- package/src/internal/logs-client.ts +67 -21
- package/src/internal/server.ts +31 -0
- package/src/internal/session-engine.ts +379 -61
- package/src/internal/storage-coordinator.ts +41 -0
- package/src/internal/workspace.ts +48 -11
- package/src/storage-backends/cursor-hosted.ts +246 -0
- package/src/storage-backends/file-kv.ts +221 -0
- package/src/storage-backends/postgres-kv.ts +253 -0
- package/src/storage.ts +11 -1
- package/src/types.ts +83 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.B7UcKvIn.js +0 -1
- package/dist/docs/assets/example-agents_index.md.CRqJlnIf.js +0 -2
- package/dist/docs/assets/example-agents_index.md.CRqJlnIf.lean.js +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/index-BjnMwYoR.css +0 -1
- /package/dist/docs/assets/{deployment.md.BtfEsc9S.lean.js → deployment.md.DC5-ImcM.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-C0-QEG4O.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="./assets/index-z3JY9O2x.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor-managed durable storage for hosted agents.
|
|
3
|
+
*
|
|
4
|
+
* Talks to the control-plane storage proxy
|
|
5
|
+
* (`POST /internal/agent-serve/storage/*`) using the engine's pod
|
|
6
|
+
* `CURSOR_API_KEY`. The server resolves `deployment_id` from that service
|
|
7
|
+
* account — engines never receive a Bugbot DSN and cannot address another
|
|
8
|
+
* deployment's rows.
|
|
9
|
+
*
|
|
10
|
+
* On Cursor-managed hosting the start script pins `CURSOR_API_BASE_URL` to
|
|
11
|
+
* `https://api.cursor.com` (where the proxy is mounted). Locally, point
|
|
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.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { defineStorage } from "@cursor/july/storage";
|
|
18
|
+
* import { cursorHostedStorage } from "@cursor/july/storage/cursor-hosted";
|
|
19
|
+
*
|
|
20
|
+
* export default defineStorage({
|
|
21
|
+
* ...cursorHostedStorage(),
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import type { StorageABTable, StorageConfig, StorageEvalsTable } from "../storage.js";
|
|
26
|
+
/**
|
|
27
|
+
* Reserved so user `secrets set` cannot smuggle a Bugbot DSN into the pod.
|
|
28
|
+
* Not injected by Cursor hosting (storage is HTTP-proxied).
|
|
29
|
+
*/
|
|
30
|
+
export declare const AGENT_SERVE_HOSTED_STORAGE_DATABASE_URL_ENV_VAR: "BUGBOTDB_URL";
|
|
31
|
+
/**
|
|
32
|
+
* Diagnostic / self-host deployment id. Not the hosted-storage authz
|
|
33
|
+
* boundary — the proxy scopes rows from the authenticated service account.
|
|
34
|
+
*/
|
|
35
|
+
export declare const AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR: "AGENT_SERVE_DEPLOYMENT_ID";
|
|
36
|
+
/**
|
|
37
|
+
* Platform-managed secret / env names. User `secrets set` / DELETE cannot
|
|
38
|
+
* claim these.
|
|
39
|
+
*/
|
|
40
|
+
export declare const CURSOR_HOSTED_STORAGE_ENV_VARS: readonly [
|
|
41
|
+
typeof AGENT_SERVE_HOSTED_STORAGE_DATABASE_URL_ENV_VAR,
|
|
42
|
+
typeof AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR
|
|
43
|
+
];
|
|
44
|
+
export interface CursorHostedStorageOptions {
|
|
45
|
+
/**
|
|
46
|
+
* Control-plane base URL (default: `CURSOR_API_BASE_URL`, else
|
|
47
|
+
* `https://api.cursor.com`).
|
|
48
|
+
*/
|
|
49
|
+
baseUrl?: string;
|
|
50
|
+
/** Bearer credential (default: `CURSOR_API_KEY`). */
|
|
51
|
+
apiKey?: string;
|
|
52
|
+
/** Injected for tests. */
|
|
53
|
+
fetch?: typeof fetch;
|
|
54
|
+
}
|
|
55
|
+
type CursorHostedStorageMethods = Required<Pick<StorageConfig, "put" | "get" | "delete" | "list">> & {
|
|
56
|
+
evals: StorageEvalsTable;
|
|
57
|
+
abs: StorageABTable;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Cursor-hosted `defineStorage` methods (control-plane storage proxy →
|
|
61
|
+
* Bugbot `agent_serve_*` tables). Spread into `defineStorage({...})`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function cursorHostedStorage(options?: CursorHostedStorageOptions): CursorHostedStorageMethods;
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=cursor-hosted.d.ts.map
|
|
@@ -0,0 +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,KAAK,0BAA0B,GAAG,QAAQ,CACxC,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;AA8DF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,0BAA+B,GACvC,0BAA0B,CA0F5B"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor-managed durable storage for hosted agents.
|
|
3
|
+
*
|
|
4
|
+
* Talks to the control-plane storage proxy
|
|
5
|
+
* (`POST /internal/agent-serve/storage/*`) using the engine's pod
|
|
6
|
+
* `CURSOR_API_KEY`. The server resolves `deployment_id` from that service
|
|
7
|
+
* account — engines never receive a Bugbot DSN and cannot address another
|
|
8
|
+
* deployment's rows.
|
|
9
|
+
*
|
|
10
|
+
* On Cursor-managed hosting the start script pins `CURSOR_API_BASE_URL` to
|
|
11
|
+
* `https://api.cursor.com` (where the proxy is mounted). Locally, point
|
|
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.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { defineStorage } from "@cursor/july/storage";
|
|
18
|
+
* import { cursorHostedStorage } from "@cursor/july/storage/cursor-hosted";
|
|
19
|
+
*
|
|
20
|
+
* export default defineStorage({
|
|
21
|
+
* ...cursorHostedStorage(),
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Same default as {@link cursorExternalApiUrl} in the CLI credentials module,
|
|
36
|
+
* inlined here so this storage entrypoint does not import CLI/zod code.
|
|
37
|
+
* Hosted monorepo examples load this file from `packages/agent-serve/src`
|
|
38
|
+
* while `npm install` runs in the example package — a credentials import
|
|
39
|
+
* would resolve `zod` from the wrong `node_modules` tree and crash serve.
|
|
40
|
+
*/
|
|
41
|
+
const DEFAULT_CURSOR_EXTERNAL_API_URL = "https://api.cursor.com";
|
|
42
|
+
/**
|
|
43
|
+
* Reserved so user `secrets set` cannot smuggle a Bugbot DSN into the pod.
|
|
44
|
+
* Not injected by Cursor hosting (storage is HTTP-proxied).
|
|
45
|
+
*/
|
|
46
|
+
export const AGENT_SERVE_HOSTED_STORAGE_DATABASE_URL_ENV_VAR = "BUGBOTDB_URL";
|
|
47
|
+
/**
|
|
48
|
+
* Diagnostic / self-host deployment id. Not the hosted-storage authz
|
|
49
|
+
* boundary — the proxy scopes rows from the authenticated service account.
|
|
50
|
+
*/
|
|
51
|
+
export const AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR = "AGENT_SERVE_DEPLOYMENT_ID";
|
|
52
|
+
/**
|
|
53
|
+
* Platform-managed secret / env names. User `secrets set` / DELETE cannot
|
|
54
|
+
* claim these.
|
|
55
|
+
*/
|
|
56
|
+
export const CURSOR_HOSTED_STORAGE_ENV_VARS = [
|
|
57
|
+
AGENT_SERVE_HOSTED_STORAGE_DATABASE_URL_ENV_VAR,
|
|
58
|
+
AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR,
|
|
59
|
+
];
|
|
60
|
+
function resolveApiKey(options) {
|
|
61
|
+
var _a;
|
|
62
|
+
var _b;
|
|
63
|
+
const key = (_a = ((_b = options.apiKey) !== null && _b !== void 0 ? _b : process.env.CURSOR_API_KEY)) === null || _a === void 0 ? void 0 : _a.trim();
|
|
64
|
+
if (key === undefined || key === "") {
|
|
65
|
+
throw new Error("cursorHostedStorage requires CURSOR_API_KEY (deployment pod credential on Cursor hosting)");
|
|
66
|
+
}
|
|
67
|
+
return key;
|
|
68
|
+
}
|
|
69
|
+
function resolveBaseUrl(options) {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const raw = ((_b = (_a = options.baseUrl) !== null && _a !== void 0 ? _a : process.env.CURSOR_API_BASE_URL) !== null && _b !== void 0 ? _b : DEFAULT_CURSOR_EXTERNAL_API_URL).trim();
|
|
72
|
+
return raw.endsWith("/") ? raw.slice(0, -1) : raw;
|
|
73
|
+
}
|
|
74
|
+
function storageRpc(options, path, body) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
var _a;
|
|
77
|
+
const baseUrl = resolveBaseUrl(options);
|
|
78
|
+
const apiKey = resolveApiKey(options);
|
|
79
|
+
const fetchImpl = (_a = options.fetch) !== null && _a !== void 0 ? _a : globalThis.fetch;
|
|
80
|
+
if (typeof fetchImpl !== "function") {
|
|
81
|
+
throw new Error("cursorHostedStorage requires fetch");
|
|
82
|
+
}
|
|
83
|
+
const response = yield fetchImpl(`${baseUrl}${path}`, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: {
|
|
86
|
+
Authorization: `Bearer ${apiKey}`,
|
|
87
|
+
"Content-Type": "application/json",
|
|
88
|
+
},
|
|
89
|
+
body: JSON.stringify(body),
|
|
90
|
+
});
|
|
91
|
+
const text = yield response.text();
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = text.length === 0 ? {} : JSON.parse(text);
|
|
95
|
+
}
|
|
96
|
+
catch (_b) {
|
|
97
|
+
throw new Error(`cursorHostedStorage ${path} returned non-JSON (${response.status})`);
|
|
98
|
+
}
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
const error = parsed !== null &&
|
|
101
|
+
typeof parsed === "object" &&
|
|
102
|
+
"error" in parsed &&
|
|
103
|
+
typeof parsed.error === "string"
|
|
104
|
+
? parsed.error
|
|
105
|
+
: `HTTP ${response.status}`;
|
|
106
|
+
throw new Error(`cursorHostedStorage ${path}: ${error}`);
|
|
107
|
+
}
|
|
108
|
+
return parsed;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Cursor-hosted `defineStorage` methods (control-plane storage proxy →
|
|
113
|
+
* Bugbot `agent_serve_*` tables). Spread into `defineStorage({...})`.
|
|
114
|
+
*/
|
|
115
|
+
export function cursorHostedStorage(options = {}) {
|
|
116
|
+
return {
|
|
117
|
+
put(key, value) {
|
|
118
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
yield storageRpc(options, "/internal/agent-serve/storage/kv/put", {
|
|
120
|
+
key,
|
|
121
|
+
value,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
get(key) {
|
|
126
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
127
|
+
var _a;
|
|
128
|
+
const result = yield storageRpc(options, "/internal/agent-serve/storage/kv/get", { key });
|
|
129
|
+
if (!result.found) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
return (_a = result.value) !== null && _a !== void 0 ? _a : undefined;
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
delete(key) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
yield storageRpc(options, "/internal/agent-serve/storage/kv/delete", {
|
|
138
|
+
key,
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
list(prefix) {
|
|
143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
const result = yield storageRpc(options, "/internal/agent-serve/storage/kv/list", { prefix });
|
|
145
|
+
return result.entries;
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
evals: {
|
|
149
|
+
put(run, ctx) {
|
|
150
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
yield storageRpc(options, "/internal/agent-serve/storage/evals/put", {
|
|
152
|
+
agentName: ctx.agentName,
|
|
153
|
+
run,
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
delete(runId, ctx) {
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
yield storageRpc(options, "/internal/agent-serve/storage/evals/delete", {
|
|
160
|
+
agentName: ctx.agentName,
|
|
161
|
+
runId,
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
list(ctx) {
|
|
166
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
167
|
+
const result = yield storageRpc(options, "/internal/agent-serve/storage/evals/list", { agentName: ctx.agentName });
|
|
168
|
+
return result.runs;
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
abs: {
|
|
173
|
+
putSample(sample, ctx) {
|
|
174
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
175
|
+
yield storageRpc(options, "/internal/agent-serve/storage/abs/put-sample", {
|
|
176
|
+
agentName: ctx.agentName,
|
|
177
|
+
sample,
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
putSnapshot(snapshot, ctx) {
|
|
182
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
yield storageRpc(options, "/internal/agent-serve/storage/abs/put-snapshot", {
|
|
184
|
+
agentName: ctx.agentName,
|
|
185
|
+
snapshot,
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
},
|
|
189
|
+
getSnapshot(ctx) {
|
|
190
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
191
|
+
var _a;
|
|
192
|
+
const result = yield storageRpc(options, "/internal/agent-serve/storage/abs/get-snapshot", {
|
|
193
|
+
agentName: ctx.agentName,
|
|
194
|
+
});
|
|
195
|
+
if (!result.found) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
return (_a = result.snapshot) !== null && _a !== void 0 ? _a : undefined;
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed `defineStorage` helper: a file-per-key KV store plus
|
|
3
|
+
* file-backed `evals` / `abs` tables.
|
|
4
|
+
*
|
|
5
|
+
* Implements the whole `defineStorage` surface with zero external
|
|
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
|
|
8
|
+
* `eval-runs/<agent>/<runId>.json`, and A/B metrics as
|
|
9
|
+
* `ab/<agent>/samples.ndjson` (append-only) plus `ab/<agent>/snapshot.json`
|
|
10
|
+
* (latest aggregate). KV keys carry the agent name inside the framework
|
|
11
|
+
* key scheme, but the evals/abs tables have no such scheme — the agent
|
|
12
|
+
* subdirectory keeps agents sharing one storage `dir` from mixing or
|
|
13
|
+
* overwriting each other's history. Swap this for a real backend
|
|
14
|
+
* (Postgres, S3, …) in production; the contracts are identical.
|
|
15
|
+
*
|
|
16
|
+
* Layout notes:
|
|
17
|
+
* - KV filenames encode the full key (`encodeURIComponent(key) + ".json"`),
|
|
18
|
+
* so `list(prefix)` is a readdir + decode + filter, returned in key
|
|
19
|
+
* order as the contract requires.
|
|
20
|
+
* - `put` writes via tmp + rename: the framework serializes writes, but a
|
|
21
|
+
* restore-path `get`/`list` can run concurrently and must never see a
|
|
22
|
+
* torn file.
|
|
23
|
+
* - `get` distinguishes a definitive miss (ENOENT → `undefined`) from a
|
|
24
|
+
* real failure (anything else throws) — on the lazy-restore path a
|
|
25
|
+
* throw correctly fails the follow-up instead of forking the session.
|
|
26
|
+
*/
|
|
27
|
+
import type { StorageABTable, StorageConfig, StorageEvalsTable } from "../storage.js";
|
|
28
|
+
export interface FileKvOptions {
|
|
29
|
+
/**
|
|
30
|
+
* Directory holding the storage files, relative to the agent project root
|
|
31
|
+
* (default `".agent-serve/kv"`). Absolute paths are used as-is.
|
|
32
|
+
*/
|
|
33
|
+
dir?: string;
|
|
34
|
+
}
|
|
35
|
+
type FileKvMethods = Required<Pick<StorageConfig, "put" | "get" | "delete" | "list">> & {
|
|
36
|
+
evals: StorageEvalsTable;
|
|
37
|
+
abs: StorageABTable;
|
|
38
|
+
};
|
|
39
|
+
/** File-backed `defineStorage` methods, ready to spread into `defineStorage({...})`. */
|
|
40
|
+
export declare function fileKv(options?: FileKvOptions): FileKvMethods;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=file-kv.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed `defineStorage` helper: a file-per-key KV store plus
|
|
3
|
+
* file-backed `evals` / `abs` tables.
|
|
4
|
+
*
|
|
5
|
+
* Implements the whole `defineStorage` surface with zero external
|
|
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
|
|
8
|
+
* `eval-runs/<agent>/<runId>.json`, and A/B metrics as
|
|
9
|
+
* `ab/<agent>/samples.ndjson` (append-only) plus `ab/<agent>/snapshot.json`
|
|
10
|
+
* (latest aggregate). KV keys carry the agent name inside the framework
|
|
11
|
+
* key scheme, but the evals/abs tables have no such scheme — the agent
|
|
12
|
+
* subdirectory keeps agents sharing one storage `dir` from mixing or
|
|
13
|
+
* overwriting each other's history. Swap this for a real backend
|
|
14
|
+
* (Postgres, S3, …) in production; the contracts are identical.
|
|
15
|
+
*
|
|
16
|
+
* Layout notes:
|
|
17
|
+
* - KV filenames encode the full key (`encodeURIComponent(key) + ".json"`),
|
|
18
|
+
* so `list(prefix)` is a readdir + decode + filter, returned in key
|
|
19
|
+
* order as the contract requires.
|
|
20
|
+
* - `put` writes via tmp + rename: the framework serializes writes, but a
|
|
21
|
+
* restore-path `get`/`list` can run concurrently and must never see a
|
|
22
|
+
* torn file.
|
|
23
|
+
* - `get` distinguishes a definitive miss (ENOENT → `undefined`) from a
|
|
24
|
+
* real failure (anything else throws) — on the lazy-restore path a
|
|
25
|
+
* throw correctly fails the follow-up instead of forking the session.
|
|
26
|
+
*/
|
|
27
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
28
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
29
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
30
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
31
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
32
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
33
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
import { randomUUID } from "node:crypto";
|
|
37
|
+
import { appendFile, mkdir, readdir, readFile, rename, rm, writeFile, } from "node:fs/promises";
|
|
38
|
+
import { join } from "node:path";
|
|
39
|
+
/** File-backed `defineStorage` methods, ready to spread into `defineStorage({...})`. */
|
|
40
|
+
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"); };
|
|
42
|
+
// The evals/abs tables are scoped per agent (KV keys already carry the
|
|
43
|
+
// agent name via the framework key scheme).
|
|
44
|
+
const evalRunsDir = (ctx) => join(resolveDir(ctx), "eval-runs", encodeURIComponent(ctx.agentName));
|
|
45
|
+
const abDir = (ctx) => join(resolveDir(ctx), "ab", encodeURIComponent(ctx.agentName));
|
|
46
|
+
const filePath = (ctx, key) => join(resolveDir(ctx), `${encodeURIComponent(key)}.json`);
|
|
47
|
+
const readKey = (ctx, key) => __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(yield readFile(filePath(ctx, key), "utf8"));
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error.code === "ENOENT") {
|
|
53
|
+
return undefined; // definitive miss — key was never written
|
|
54
|
+
}
|
|
55
|
+
throw error; // real failure: let lazy restore fail the follow-up
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
put(key, value, ctx) {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
yield writeJsonAtomic({
|
|
62
|
+
dir: resolveDir(ctx),
|
|
63
|
+
fileName: `${encodeURIComponent(key)}.json`,
|
|
64
|
+
value,
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
get(key, ctx) {
|
|
69
|
+
return readKey(ctx, key);
|
|
70
|
+
},
|
|
71
|
+
delete(key, ctx) {
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
yield rm(filePath(ctx, key), { force: true });
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
list(prefix, ctx) {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
let names;
|
|
79
|
+
try {
|
|
80
|
+
names = yield readdir(resolveDir(ctx));
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error.code === "ENOENT") {
|
|
84
|
+
return []; // nothing stored yet
|
|
85
|
+
}
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
const keys = names
|
|
89
|
+
.filter((name) => name.endsWith(".json"))
|
|
90
|
+
.map((name) => decodeURIComponent(name.slice(0, -".json".length)))
|
|
91
|
+
.filter((key) => key.startsWith(prefix))
|
|
92
|
+
.sort();
|
|
93
|
+
const entries = [];
|
|
94
|
+
for (const key of keys) {
|
|
95
|
+
const value = yield readKey(ctx, key);
|
|
96
|
+
if (value !== undefined) {
|
|
97
|
+
entries.push({ key, value });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return entries;
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
// Playground eval batches: one JSON file per run under eval-runs/<agent>/.
|
|
104
|
+
evals: {
|
|
105
|
+
put(run, ctx) {
|
|
106
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
+
yield writeJsonAtomic({
|
|
108
|
+
dir: evalRunsDir(ctx),
|
|
109
|
+
fileName: `${encodeURIComponent(run.runId)}.json`,
|
|
110
|
+
value: run,
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
delete(runId, ctx) {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
yield rm(join(evalRunsDir(ctx), `${encodeURIComponent(runId)}.json`), {
|
|
117
|
+
force: true,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
list(ctx) {
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
const dir = evalRunsDir(ctx);
|
|
124
|
+
let names;
|
|
125
|
+
try {
|
|
126
|
+
names = yield readdir(dir);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error.code === "ENOENT") {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
const runs = [];
|
|
135
|
+
for (const name of names.filter((n) => n.endsWith(".json")).sort()) {
|
|
136
|
+
// One unreadable/corrupt file must not wipe the whole history:
|
|
137
|
+
// hydrate treats a throwing list() as "nothing saved".
|
|
138
|
+
try {
|
|
139
|
+
runs.push(JSON.parse(yield readFile(join(dir, name), "utf8")));
|
|
140
|
+
}
|
|
141
|
+
catch (_a) { }
|
|
142
|
+
}
|
|
143
|
+
return runs;
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
// A/B metrics: append-only sample log + latest aggregate snapshot,
|
|
148
|
+
// both under ab/<agent>/.
|
|
149
|
+
abs: {
|
|
150
|
+
putSample(sample, ctx) {
|
|
151
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
152
|
+
const dir = abDir(ctx);
|
|
153
|
+
yield mkdir(dir, { recursive: true });
|
|
154
|
+
yield appendFile(join(dir, "samples.ndjson"), `${JSON.stringify(sample)}\n`, "utf8");
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
putSnapshot(snapshot, ctx) {
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
yield writeJsonAtomic({
|
|
160
|
+
dir: abDir(ctx),
|
|
161
|
+
fileName: "snapshot.json",
|
|
162
|
+
value: snapshot,
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
getSnapshot(ctx) {
|
|
167
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
168
|
+
try {
|
|
169
|
+
return JSON.parse(yield readFile(join(abDir(ctx), "snapshot.json"), "utf8"));
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
if (error.code === "ENOENT") {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/** tmp + rename write so concurrent readers never see a torn file. */
|
|
183
|
+
function writeJsonAtomic(args) {
|
|
184
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
185
|
+
yield mkdir(args.dir, { recursive: true });
|
|
186
|
+
const tmp = join(args.dir, `.tmp-${randomUUID()}`);
|
|
187
|
+
yield writeFile(tmp, JSON.stringify(args.value), "utf8");
|
|
188
|
+
yield rename(tmp, join(args.dir, args.fileName));
|
|
189
|
+
});
|
|
190
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Postgres `defineStorage` helper on the agent-serve tables
|
|
3
|
+
* (backend/packages/prisma-bugbot):
|
|
4
|
+
*
|
|
5
|
+
* agent_serve_kv(deployment_id, key, value JSONB, updated_at)
|
|
6
|
+
* PRIMARY KEY (deployment_id, key)
|
|
7
|
+
* agent_serve_eval_runs(deployment_id, agent, run_id, run JSONB, updated_at)
|
|
8
|
+
* PRIMARY KEY (deployment_id, agent, run_id)
|
|
9
|
+
* agent_serve_ab(deployment_id, agent, kind, ref, value JSONB, updated_at)
|
|
10
|
+
* PRIMARY KEY (deployment_id, agent, kind, ref)
|
|
11
|
+
*
|
|
12
|
+
* For Cursor-managed hosting prefer `cursorHostedStorage` from
|
|
13
|
+
* `@cursor/july/storage/cursor-hosted` — same tables via a control-plane
|
|
14
|
+
* HTTP proxy (no pod-visible DSN). Use this helper when you supply
|
|
15
|
+
* `BUGBOTDB_URL` / `AGENT_SERVE_DEPLOYMENT_ID` yourself (self-host).
|
|
16
|
+
*
|
|
17
|
+
* `postgresStorage` implements the whole `defineStorage` surface as plain
|
|
18
|
+
* SQL: the four KV methods against the last-write-wins `agent_serve_kv`
|
|
19
|
+
* table (sessions, event chunks, continuations, reminders), the `evals`
|
|
20
|
+
* table against `agent_serve_eval_runs` (one row per playground eval
|
|
21
|
+
* batch), and the `abs` table against `agent_serve_ab` (`kind = 'sample'`
|
|
22
|
+
* rows per metric sample plus one `kind = 'snapshot'` row holding the
|
|
23
|
+
* latest aggregate).
|
|
24
|
+
*
|
|
25
|
+
* - KV `put` upserts on the primary key (LWW matches the framework contract).
|
|
26
|
+
* - KV `list` is a prefix range scan on the PK btree (`key >= p AND key < p||…`
|
|
27
|
+
* spelled as LIKE with escaped wildcards, ordered by key).
|
|
28
|
+
* - `get` returning no row is a definitive miss (`undefined`); a connection
|
|
29
|
+
* error throws, so lazy restore fails the follow-up instead of forking
|
|
30
|
+
* the session.
|
|
31
|
+
*
|
|
32
|
+
* Connection comes from `BUGBOTDB_URL` — the repo-wide convention for the
|
|
33
|
+
* bugbot Postgres database, whose Prisma package owns these tables' schema
|
|
34
|
+
* and migrations; locally it falls back to the dev bugbot DB. Non-local
|
|
35
|
+
* URLs enable TLS (`ssl.rejectUnauthorized`) because PlanetScale requires
|
|
36
|
+
* SSL even when the vault URL omits `sslmode`.
|
|
37
|
+
* `deploymentId` scopes rows per deployment (`AGENT_SERVE_DEPLOYMENT_ID`);
|
|
38
|
+
* the local default keeps dev runs of different checkouts from colliding
|
|
39
|
+
* only by agent name.
|
|
40
|
+
*
|
|
41
|
+
* Callers must pass `Pool` from their own `import { Pool } from "pg"`.
|
|
42
|
+
* This module must not import `pg` itself: Node resolves modules from
|
|
43
|
+
* *this* file's directory tree, so a `pg` dep declared only on the
|
|
44
|
+
* consuming agent package would never be found after a hosted install.
|
|
45
|
+
*/
|
|
46
|
+
import type { StorageABTable, StorageConfig, StorageEvalsTable } from "../storage.js";
|
|
47
|
+
/** Minimal `pg.Pool` surface used here (avoids importing `pg` from this path). */
|
|
48
|
+
export interface PostgresQueryable {
|
|
49
|
+
query<T extends Record<string, unknown> = Record<string, unknown>>(text: string, values?: readonly unknown[]): Promise<{
|
|
50
|
+
rows: T[];
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
/** `pg.Pool` constructor supplied by the consuming example package. */
|
|
54
|
+
export type PostgresPoolConstructor = new (config?: {
|
|
55
|
+
connectionString?: string;
|
|
56
|
+
max?: number;
|
|
57
|
+
ssl?: boolean | {
|
|
58
|
+
rejectUnauthorized?: boolean;
|
|
59
|
+
};
|
|
60
|
+
}) => PostgresQueryable;
|
|
61
|
+
export interface PostgresStorageOptions {
|
|
62
|
+
/**
|
|
63
|
+
* Pass `Pool` from `import { Pool } from "pg"` in the example that declares
|
|
64
|
+
* the `pg` dependency (hosted installs put it in that package's
|
|
65
|
+
* `node_modules` only).
|
|
66
|
+
*/
|
|
67
|
+
Pool: PostgresPoolConstructor;
|
|
68
|
+
/** Postgres connection string (default: env, then local bugbot dev DB). */
|
|
69
|
+
databaseUrl?: string;
|
|
70
|
+
/** Value for the tables' deployment_id column (default: env or "local-dev"). */
|
|
71
|
+
deploymentId?: string;
|
|
72
|
+
}
|
|
73
|
+
type PostgresStorageMethods = Required<Pick<StorageConfig, "put" | "get" | "delete" | "list">> & {
|
|
74
|
+
evals: StorageEvalsTable;
|
|
75
|
+
abs: StorageABTable;
|
|
76
|
+
};
|
|
77
|
+
/** True for local bugbot/dev URLs that do not speak TLS. */
|
|
78
|
+
export declare function isLocalPostgresUrl(connectionString: string): boolean;
|
|
79
|
+
/** Postgres-backed `defineStorage` methods, ready to spread into `defineStorage({...})`. */
|
|
80
|
+
export declare function postgresStorage(options: PostgresStorageOptions): PostgresStorageMethods;
|
|
81
|
+
export {};
|
|
82
|
+
//# sourceMappingURL=postgres-kv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-kv.d.ts","sourceRoot":"","sources":["../../src/storage-backends/postgres-kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAIH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAGvB,kFAAkF;AAClF,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/D,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAC1B,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC,CAAC;CAC3B;AAED,uEAAuE;AACvE,MAAM,MAAM,uBAAuB,GAAG,KAAK,MAAM,CAAC,EAAE;IAClD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,GAAG;QAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAClD,KAAK,iBAAiB,CAAC;AAExB,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,IAAI,EAAE,uBAAuB,CAAC;IAC9B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,sBAAsB,GAAG,QAAQ,CACpC,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,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAYpE;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,GAC9B,sBAAsB,CA4HxB"}
|