@cursor/july 0.1.47 → 0.1.49

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 (127) hide show
  1. package/dist/bin/agent-serve.js +30 -35
  2. package/dist/docs/404.html +2 -2
  3. package/dist/docs/ab.html +5 -5
  4. package/dist/docs/assets/{ab.md.hdxsvX5M.js → ab.md.DYjwREAP.js} +2 -2
  5. package/dist/docs/assets/{ab.md.hdxsvX5M.lean.js → ab.md.DYjwREAP.lean.js} +1 -1
  6. package/dist/docs/assets/{app.IEXEim5m.js → app.BpWAgjaR.js} +1 -1
  7. package/dist/docs/assets/chunks/@localSearchIndexroot.D00d772K.js +1 -0
  8. package/dist/docs/assets/chunks/{VPLocalSearchBox.78s6nqsH.js → VPLocalSearchBox.CnAktZtG.js} +1 -1
  9. package/dist/docs/assets/chunks/{theme.DroGdz_Q.js → theme.B5IvUxOB.js} +2 -2
  10. package/dist/docs/assets/{evals.md.qeoGgPw0.js → evals.md.CVe_O75-.js} +3 -3
  11. package/dist/docs/assets/{evals.md.qeoGgPw0.lean.js → evals.md.CVe_O75-.lean.js} +1 -1
  12. package/dist/docs/assets/{reference_http-api.md.DGrw_wOu.js → reference_http-api.md.DMbdFGVQ.js} +1 -1
  13. package/dist/docs/assets/{storage.md.CJYd5YmN.js → storage.md.D8NQ389l.js} +3 -3
  14. package/dist/docs/assets/storage.md.D8NQ389l.lean.js +1 -0
  15. package/dist/docs/building-with-agents.html +3 -3
  16. package/dist/docs/concepts.html +3 -3
  17. package/dist/docs/deployment.html +3 -3
  18. package/dist/docs/evals.html +6 -6
  19. package/dist/docs/example-agents/approval-buddy.html +3 -3
  20. package/dist/docs/example-agents/benny.html +3 -3
  21. package/dist/docs/example-agents/bugbot.html +3 -3
  22. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  23. package/dist/docs/example-agents/codeowners-review.html +3 -3
  24. package/dist/docs/example-agents/concierge.html +3 -3
  25. package/dist/docs/example-agents/fsd.html +3 -3
  26. package/dist/docs/example-agents/index.html +3 -3
  27. package/dist/docs/example-agents/knowledge-base.html +3 -3
  28. package/dist/docs/example-agents/oncall.html +3 -3
  29. package/dist/docs/example-agents/security-reviewer.html +3 -3
  30. package/dist/docs/example-agents/slack-agent.html +3 -3
  31. package/dist/docs/example-agents/weather-agent.html +3 -3
  32. package/dist/docs/guides/agent-to-agent.html +3 -3
  33. package/dist/docs/guides/cloud-runtime.html +3 -3
  34. package/dist/docs/guides/github.html +3 -3
  35. package/dist/docs/guides/human-in-the-loop.html +3 -3
  36. package/dist/docs/guides/mcp-oauth.html +3 -3
  37. package/dist/docs/guides/opentelemetry.html +3 -3
  38. package/dist/docs/guides/slack.html +3 -3
  39. package/dist/docs/guides/webhooks.html +3 -3
  40. package/dist/docs/hashmap.json +1 -1
  41. package/dist/docs/hillclimbing.html +3 -3
  42. package/dist/docs/index.html +3 -3
  43. package/dist/docs/quickstart.html +3 -3
  44. package/dist/docs/reference/agent-config.html +3 -3
  45. package/dist/docs/reference/artifacts.html +3 -3
  46. package/dist/docs/reference/channels.html +3 -3
  47. package/dist/docs/reference/cli.html +3 -3
  48. package/dist/docs/reference/connections.html +3 -3
  49. package/dist/docs/reference/hooks.html +3 -3
  50. package/dist/docs/reference/http-api.html +5 -5
  51. package/dist/docs/reference/instructions.html +3 -3
  52. package/dist/docs/reference/playground.html +3 -3
  53. package/dist/docs/reference/project-layout.html +3 -3
  54. package/dist/docs/reference/prompt.html +3 -3
  55. package/dist/docs/reference/schedules.html +3 -3
  56. package/dist/docs/reference/sessions.html +3 -3
  57. package/dist/docs/reference/skills.html +3 -3
  58. package/dist/docs/reference/subagents.html +3 -3
  59. package/dist/docs/reference/tools.html +3 -3
  60. package/dist/docs/scaffolding-agents.html +3 -3
  61. package/dist/docs/storage.html +5 -5
  62. package/dist/docs/templates/triage.html +3 -3
  63. package/dist/docs/troubleshooting.html +3 -3
  64. package/dist/internal/authored-loaders.d.ts +19 -0
  65. package/dist/internal/authored-loaders.d.ts.map +1 -1
  66. package/dist/internal/authored-loaders.js +39 -0
  67. package/dist/internal/cli-deploy.d.ts +2 -1
  68. package/dist/internal/cli-deploy.d.ts.map +1 -1
  69. package/dist/internal/cli-deploy.js +97 -1
  70. package/dist/internal/cli-slack.js +0 -3
  71. package/dist/internal/deploy-client.d.ts +7 -2
  72. package/dist/internal/deploy-client.d.ts.map +1 -1
  73. package/dist/internal/deploy-client.js +12 -0
  74. package/dist/internal/discovery.d.ts.map +1 -1
  75. package/dist/internal/discovery.js +2 -8
  76. package/dist/internal/eval-runner.d.ts.map +1 -1
  77. package/dist/internal/eval-runner.js +3 -8
  78. package/dist/internal/event-log.d.ts +17 -0
  79. package/dist/internal/event-log.d.ts.map +1 -1
  80. package/dist/internal/event-log.js +32 -2
  81. package/dist/internal/logs-client.d.ts +1 -1
  82. package/dist/internal/logs-client.d.ts.map +1 -1
  83. package/dist/internal/logs-client.js +3 -0
  84. package/dist/internal/process-memory-telemetry.d.ts +90 -0
  85. package/dist/internal/process-memory-telemetry.d.ts.map +1 -0
  86. package/dist/internal/process-memory-telemetry.js +259 -0
  87. package/dist/internal/serve-restart.d.ts +42 -0
  88. package/dist/internal/serve-restart.d.ts.map +1 -0
  89. package/dist/internal/serve-restart.js +85 -0
  90. package/dist/internal/server.d.ts.map +1 -1
  91. package/dist/internal/server.js +9 -10
  92. package/dist/internal/session-engine.d.ts +4 -0
  93. package/dist/internal/session-engine.d.ts.map +1 -1
  94. package/dist/internal/session-engine.js +19 -5
  95. package/dist/internal/slack-provision-client.d.ts +4 -4
  96. package/dist/internal/slack-provision-client.js +7 -7
  97. package/dist/playground/assets/index-Dox74yWJ.css +1 -0
  98. package/dist/playground/assets/{index-BgUHfe3L.js → index-Dq_HqyU-.js} +46 -46
  99. package/dist/playground/index.html +2 -2
  100. package/dist/storage.d.ts +36 -10
  101. package/dist/storage.d.ts.map +1 -1
  102. package/dist/storage.js +82 -6
  103. package/docs/ab.md +4 -3
  104. package/docs/evals.md +10 -7
  105. package/docs/reference/http-api.md +4 -3
  106. package/docs/storage.md +38 -22
  107. package/package.json +1 -1
  108. package/skills/setup-slack/SKILL.md +1 -1
  109. package/src/bin/agent-serve.ts +39 -38
  110. package/src/internal/authored-loaders.ts +45 -0
  111. package/src/internal/cli-deploy.ts +103 -1
  112. package/src/internal/cli-slack.ts +0 -5
  113. package/src/internal/deploy-client.ts +19 -1
  114. package/src/internal/discovery.ts +5 -12
  115. package/src/internal/eval-runner.ts +3 -12
  116. package/src/internal/event-log.ts +45 -7
  117. package/src/internal/logs-client.ts +4 -0
  118. package/src/internal/process-memory-telemetry.ts +373 -0
  119. package/src/internal/serve-restart.ts +120 -0
  120. package/src/internal/server.ts +13 -0
  121. package/src/internal/session-engine.ts +20 -1
  122. package/src/internal/slack-provision-client.ts +7 -7
  123. package/src/storage.ts +130 -11
  124. package/dist/docs/assets/chunks/@localSearchIndexroot.D7w61u6Y.js +0 -1
  125. package/dist/docs/assets/storage.md.CJYd5YmN.lean.js +0 -1
  126. package/dist/playground/assets/index-uFaeqVZS.css +0 -1
  127. /package/dist/docs/assets/{reference_http-api.md.DGrw_wOu.lean.js → reference_http-api.md.DMbdFGVQ.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-BgUHfe3L.js"></script>
12
- <link rel="stylesheet" crossorigin href="./assets/index-uFaeqVZS.css">
11
+ <script type="module" crossorigin src="./assets/index-Dq_HqyU-.js"></script>
12
+ <link rel="stylesheet" crossorigin href="./assets/index-Dox74yWJ.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
package/dist/storage.d.ts CHANGED
@@ -9,9 +9,12 @@
9
9
  * The sink is a plain key-value store — put/get/delete/list, no schema —
10
10
  * plus a conditional-write group ({@link StorageConfig.cas}, the substrate
11
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
+ * coordination features). Implementing that small KV core is enough for
13
+ * FULL functionality: eval-run and A/B history are derived over the core
14
+ * when the optional dedicated tables ({@link StorageConfig.evals} and
15
+ * {@link StorageConfig.abs}) are not authored — those groups exist as
16
+ * backend-native optimizations (a real table, an analytics pipeline),
17
+ * not as required-or-lose-history hooks:
15
18
  *
16
19
  * ```ts
17
20
  * import { defineStorage } from "@anysphere/agent-serve/storage";
@@ -178,13 +181,20 @@ export interface StorageConfig {
178
181
  /** Timing knobs; see {@link StoragePolicy}. */
179
182
  policy?: StoragePolicy;
180
183
  /**
181
- * Dedicated eval-runs table. Omit it and playground eval history stays
182
- * in process memory (lost on restart).
184
+ * Dedicated eval-runs table a backend-native optimization, not a
185
+ * requirement. When omitted, `defineStorage` derives the table over the
186
+ * KV core (one key per run under `agentkit/v1/{agent}/eval-runs/`),
187
+ * which needs core `put`, `delete`, and `list`; only when the core
188
+ * lacks `delete` or `list` does playground eval history stay in process
189
+ * memory (lost on restart).
183
190
  */
184
191
  evals?: StorageEvalsTable;
185
192
  /**
186
- * Dedicated A/B table. Omit it and metric samples are not exported
187
- * (session event logs remain the assignment/fold source of truth).
193
+ * Dedicated A/B table a backend-native optimization, not a
194
+ * requirement. When omitted, `defineStorage` derives it over the KV
195
+ * core: `putSample` and `putSnapshot` need only core `put` (always
196
+ * present), `getSnapshot` additionally needs core `get`. Session event
197
+ * logs remain the assignment/fold source of truth either way.
188
198
  */
189
199
  abs?: StorageABTable;
190
200
  /**
@@ -217,7 +227,8 @@ export interface StorageConfig {
217
227
  /**
218
228
  * All entries under a key prefix, in ascending key order. Optional —
219
229
  * required for the **startup bulk restore** (sessions + event streams)
220
- * and playground eval history.
230
+ * and, together with `delete`, for the derived eval-runs table
231
+ * (playground eval history).
221
232
  */
222
233
  list?(prefix: string, ctx: StorageContext): StorageEntry[] | Promise<StorageEntry[]>;
223
234
  }
@@ -252,9 +263,14 @@ export declare const STORAGE_KEY_ROOT: "agentkit/v1";
252
263
  * | `agentkit/v1/{agent}/session-events/{sessionId}/{index}` | `SessionEvent[]` chunk (index = first event's index, zero-padded) |
253
264
  * | `agentkit/v1/{agent}/continuation/{channelId}/{token}` | `{ sessionId }` |
254
265
  * | `agentkit/v1/{agent}/kv/{key}` | Author JSON via {@link HostContext.kv} |
266
+ * | `agentkit/v1/{agent}/eval-runs/{runId}` | `EvalRunSnapshot` (derived `evals` table) |
267
+ * | `agentkit/v1/{agent}/ab-samples/{experiment}/{sessionId}/{at}` | `ABMetricSample` (derived `abs` table, append-only) |
268
+ * | `agentkit/v1/{agent}/ab-snapshot` | `ABSnapshot` (derived `abs` table, LWW) |
255
269
  *
256
- * Eval-run and A/B history do not flow through this KV scheme — they have
257
- * dedicated tables ({@link StorageConfig.evals} / {@link StorageConfig.abs}).
270
+ * The `eval-runs` / `ab-samples` / `ab-snapshot` families are minted only
271
+ * by the tables `defineStorage` derives over the KV core; a backend that
272
+ * authors dedicated {@link StorageConfig.evals} / {@link StorageConfig.abs}
273
+ * groups never sees them.
258
274
  */
259
275
  export declare const storageKeys: {
260
276
  readonly session: (agent: string, sessionId: string) => string;
@@ -268,6 +284,16 @@ export declare const storageKeys: {
268
284
  */
269
285
  readonly kv: (agent: string, key: string) => string;
270
286
  readonly kvPrefix: (agent: string) => string;
287
+ /** One playground eval-run snapshot (derived `evals` table). */
288
+ readonly evalRun: (agent: string, runId: string) => string;
289
+ readonly evalRunsPrefix: (agent: string) => string;
290
+ /**
291
+ * One A/B metric sample (derived `abs` table); the segments mirror the
292
+ * dedicated table's row identity (experiment + sessionId + at).
293
+ */
294
+ readonly abSample: (agent: string, experiment: string, sessionId: string, at: string) => string;
295
+ /** Latest aggregate A/B snapshot (derived `abs` table, LWW). */
296
+ readonly abSnapshot: (agent: string) => string;
271
297
  };
272
298
  /**
273
299
  * Max bytes a caller-controlled key segment may occupy after URI-encoding.
@@ -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
@@ -9,9 +9,12 @@
9
9
  * The sink is a plain key-value store — put/get/delete/list, no schema —
10
10
  * plus a conditional-write group ({@link StorageConfig.cas}, the substrate
11
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
+ * coordination features). Implementing that small KV core is enough for
13
+ * FULL functionality: eval-run and A/B history are derived over the core
14
+ * when the optional dedicated tables ({@link StorageConfig.evals} and
15
+ * {@link StorageConfig.abs}) are not authored — those groups exist as
16
+ * backend-native optimizations (a real table, an analytics pipeline),
17
+ * not as required-or-lose-history hooks:
15
18
  *
16
19
  * ```ts
17
20
  * import { defineStorage } from "@anysphere/agent-serve/storage";
@@ -48,6 +51,15 @@
48
51
  * event log under `--state-root` remains the live source of truth; this
49
52
  * interface is the durable mirror.
50
53
  */
54
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
55
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
56
+ return new (P || (P = Promise))(function (resolve, reject) {
57
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
58
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
59
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
60
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
61
+ });
62
+ };
51
63
  import { createHash } from "node:crypto";
52
64
  import { brandDefinition } from "./internal/brand.js";
53
65
  /**
@@ -101,7 +113,56 @@ export function defineStorage(config) {
101
113
  }
102
114
  // Validate eagerly so a bad policy fails at discovery, not first flush.
103
115
  resolveStoragePolicy(config.policy);
104
- return brandDefinition("storage", config);
116
+ // A backend that implements only the KV core gets full functionality:
117
+ // the dedicated tables are backend-native optimizations, derived over
118
+ // the core when absent. Authored groups always win.
119
+ const derivedEvals = config.evals === undefined ? deriveEvalsTable(config) : undefined;
120
+ const derivedAbs = config.abs === undefined ? deriveAbsTable(config) : undefined;
121
+ return brandDefinition("storage", Object.assign(Object.assign(Object.assign({}, config), (derivedEvals === undefined ? {} : { evals: derivedEvals })), (derivedAbs === undefined ? {} : { abs: derivedAbs })));
122
+ }
123
+ /**
124
+ * Eval-runs table over the KV core: one key per run under
125
+ * {@link storageKeys.evalRun}, hydrate via prefix `list`, prune via
126
+ * `delete`. Requires core `put` + `delete` + `list`; without `delete` or
127
+ * `list` there is no derivation (pruning or hydration would silently not
128
+ * work) and eval history stays in process memory.
129
+ */
130
+ function deriveEvalsTable(config) {
131
+ if (config.delete === undefined || config.list === undefined) {
132
+ return undefined;
133
+ }
134
+ return {
135
+ put: (run, ctx) => config.put(storageKeys.evalRun(ctx.agentName, run.runId), run, ctx),
136
+ delete: (runId, ctx) => { var _a; return (_a = config.delete) === null || _a === void 0 ? void 0 : _a.call(config, storageKeys.evalRun(ctx.agentName, runId), ctx); },
137
+ list: (ctx) => __awaiter(this, void 0, void 0, function* () {
138
+ var _a;
139
+ var _b;
140
+ const entries = (_b = (yield (_a = config.list) === null || _a === void 0 ? void 0 : _a.call(config, storageKeys.evalRunsPrefix(ctx.agentName), ctx))) !== null && _b !== void 0 ? _b : [];
141
+ return entries.map((entry) => entry.value);
142
+ }),
143
+ };
144
+ }
145
+ /**
146
+ * A/B table over the KV core. Each sample lands as its own key (identity
147
+ * = experiment + sessionId + at, matching the dedicated table's row
148
+ * uniqueness): appending to one array value would need read-modify-write
149
+ * — lost updates under concurrent writers without CAS, and unbounded
150
+ * value growth — while a key per sample keeps `putSample` a blind put
151
+ * with real append-only semantics. The aggregate snapshot lives at one
152
+ * fixed key via plain `put` (last-write-wins is correct for "latest").
153
+ * Requires only core `put`; `getSnapshot` is included when core `get`
154
+ * exists.
155
+ */
156
+ function deriveAbsTable(config) {
157
+ const get = config.get;
158
+ return Object.assign({ putSample: (sample, ctx) => config.put(storageKeys.abSample(ctx.agentName, sample.experiment, sample.sessionId, sample.at), sample, ctx), putSnapshot: (snapshot, ctx) => config.put(storageKeys.abSnapshot(ctx.agentName), snapshot, ctx) }, (get === undefined
159
+ ? {}
160
+ : {
161
+ getSnapshot: (ctx) => __awaiter(this, void 0, void 0, function* () {
162
+ const value = yield get(storageKeys.abSnapshot(ctx.agentName), ctx);
163
+ return (value !== null && value !== void 0 ? value : undefined);
164
+ }),
165
+ }));
105
166
  }
106
167
  // ============================================================================
107
168
  // Key scheme
@@ -129,9 +190,14 @@ export const STORAGE_KEY_ROOT = "agentkit/v1";
129
190
  * | `agentkit/v1/{agent}/session-events/{sessionId}/{index}` | `SessionEvent[]` chunk (index = first event's index, zero-padded) |
130
191
  * | `agentkit/v1/{agent}/continuation/{channelId}/{token}` | `{ sessionId }` |
131
192
  * | `agentkit/v1/{agent}/kv/{key}` | Author JSON via {@link HostContext.kv} |
193
+ * | `agentkit/v1/{agent}/eval-runs/{runId}` | `EvalRunSnapshot` (derived `evals` table) |
194
+ * | `agentkit/v1/{agent}/ab-samples/{experiment}/{sessionId}/{at}` | `ABMetricSample` (derived `abs` table, append-only) |
195
+ * | `agentkit/v1/{agent}/ab-snapshot` | `ABSnapshot` (derived `abs` table, LWW) |
132
196
  *
133
- * Eval-run and A/B history do not flow through this KV scheme — they have
134
- * dedicated tables ({@link StorageConfig.evals} / {@link StorageConfig.abs}).
197
+ * The `eval-runs` / `ab-samples` / `ab-snapshot` families are minted only
198
+ * by the tables `defineStorage` derives over the KV core; a backend that
199
+ * authors dedicated {@link StorageConfig.evals} / {@link StorageConfig.abs}
200
+ * groups never sees them.
135
201
  */
136
202
  export const storageKeys = {
137
203
  session: (agent, sessionId) => `${STORAGE_KEY_ROOT}/${agent}/session/${sessionId}`,
@@ -145,6 +211,16 @@ export const storageKeys = {
145
211
  */
146
212
  kv: (agent, key) => `${STORAGE_KEY_ROOT}/${agent}/kv/${keySegment(key)}`,
147
213
  kvPrefix: (agent) => `${STORAGE_KEY_ROOT}/${agent}/kv/`,
214
+ /** One playground eval-run snapshot (derived `evals` table). */
215
+ evalRun: (agent, runId) => `${STORAGE_KEY_ROOT}/${agent}/eval-runs/${keySegment(runId)}`,
216
+ evalRunsPrefix: (agent) => `${STORAGE_KEY_ROOT}/${agent}/eval-runs/`,
217
+ /**
218
+ * One A/B metric sample (derived `abs` table); the segments mirror the
219
+ * dedicated table's row identity (experiment + sessionId + at).
220
+ */
221
+ abSample: (agent, experiment, sessionId, at) => `${STORAGE_KEY_ROOT}/${agent}/ab-samples/${keySegment(experiment)}/${keySegment(sessionId)}/${keySegment(at)}`,
222
+ /** Latest aggregate A/B snapshot (derived `abs` table, LWW). */
223
+ abSnapshot: (agent) => `${STORAGE_KEY_ROOT}/${agent}/ab-snapshot`,
148
224
  };
149
225
  /**
150
226
  * Max bytes a caller-controlled key segment may occupy after URI-encoding.
package/docs/ab.md CHANGED
@@ -255,9 +255,10 @@ too. This include-all behavior can still apply to `GET /v1/abs` in dev
255
255
  when bearer or custom auth keeps `GET /v1/sessions` owner-scoped.
256
256
 
257
257
  Session `events.ndjson` is the source of truth for assignment + fold.
258
- `GET /v1/abs` recomputes aggregates from those logs. For durable
259
- sample and snapshot export, declare an `abs` table in
260
- `agent/storage.ts` same idea as the eval-runs table. See
258
+ `GET /v1/abs` recomputes aggregates from those logs. Any
259
+ `agent/storage.ts` exports samples and snapshots durably: an authored
260
+ `abs` table when the backend has a native shape for it, or the table
261
+ derived over the KV core otherwise. See
261
262
  [Storage](./storage.md#eval-and-a-b-tables).
262
263
 
263
264
  ## Configure the playground fold window
package/docs/evals.md CHANGED
@@ -147,10 +147,12 @@ JUnit XML file for CI, `Artifacts` writes per-case files, and
147
147
  the XML for a custom destination). A file or case can add its own
148
148
  `reporters` on top of the config list.
149
149
 
150
- Playground batches live in process memory and disappear when `serve`
151
- exits. Navigating away and back still works while the process is up.
152
- To keep batches across restarts, declare an `evals` table in
153
- `agent/storage.ts`; see [Storage](./storage.md#eval-and-a-b-tables).
150
+ Playground batches survive restarts whenever `agent/storage.ts` exists
151
+ with an `evals` table or a KV core providing `delete` and `list` (the
152
+ table is derived over the core); see
153
+ [Storage](./storage.md#eval-and-a-b-tables). Without storage they live
154
+ in process memory and disappear when `serve` exits — navigating away
155
+ and back still works while the process is up.
154
156
 
155
157
  ## Drive and assert with `t`
156
158
 
@@ -360,9 +362,10 @@ agent-sdk serve --dir . --dev
360
362
 
361
363
  Playground runs target the live server instead of an ephemeral one.
362
364
  Their sessions appear in the session list. One eval batch can run at a
363
- time. By default those batches are **in-memory only** (capped by
364
- `maxPlaygroundRuns`); declare an `evals` table in `agent/storage.ts` if
365
- you need them after a serve restart see
365
+ time. Batches persist across restarts whenever `agent/storage.ts`
366
+ provides an `evals` table or a KV core with `delete` and `list` (the
367
+ table is derived over the core); without storage they are **in-memory
368
+ only** (capped by `maxPlaygroundRuns`) — see
366
369
  [Storage](./storage.md#eval-and-a-b-tables).
367
370
 
368
371
  The UI uses the playground eval routes (available without `--dev`):
@@ -208,9 +208,10 @@ Eval runs are asynchronous. Poll the run route for case progress and
208
208
  the final `completed` or `failed` status. Batch errors appear on the
209
209
  snapshot returned by the poll. Entries within `filterIds` and `tags`
210
210
  use OR semantics. When both fields are present, a case must match one
211
- entry from each field. Without a storage `evals` table in
212
- `agent/storage.ts` (see [Storage](../storage.md)), listed runs are
213
- process-memory only (capped by `maxPlaygroundRuns`).
211
+ entry from each field. Listed runs persist across restarts whenever
212
+ `agent/storage.ts` provides an `evals` table or a KV core with `delete`
213
+ and `list` (the table is derived — see [Storage](../storage.md));
214
+ otherwise they are process-memory only (capped by `maxPlaygroundRuns`).
214
215
 
215
216
  ## Dev-mode routes
216
217
 
package/docs/storage.md CHANGED
@@ -52,17 +52,22 @@ export default defineStorage({
52
52
 
53
53
  ## Which fields to provide
54
54
 
55
+ Implement the small KV core — `put`/`get`/`delete`/`list` plus the `cas`
56
+ group — and you get **full functionality**: eval-run and A/B history are
57
+ derived over the core automatically. The dedicated `evals` / `abs` groups
58
+ are backend-native optimizations, not required-or-lose-history hooks.
59
+
55
60
  | Field | Required | Role |
56
61
  | --- | --- | --- |
57
62
  | `put` | Yes | Write or update a value |
58
63
  | `cas` | For coordination | Conditional writes; see [Conditional writes](#conditional-writes-the-cas-group) |
59
- | `get` | For restore | Look up one key |
60
- | `list` | For restore | Return entries under a prefix, in key order |
61
- | `delete` | For cleanup | Remove a key |
64
+ | `get` | For restore | Look up one key (also: derived A/B snapshot backfill) |
65
+ | `list` | For restore | Return entries under a prefix, in key order (also: derived eval-runs hydrate) |
66
+ | `delete` | For cleanup | Remove a key (also: derived eval-runs pruning) |
62
67
  | `name` | No | Label surfaced on `GET /v1/info` diagnostics |
63
68
  | `policy` | No | Timing knobs; see [Policy](#policy) |
64
- | `evals` | No | Dedicated eval-runs table; see [Eval and A/B tables](#eval-and-a-b-tables) |
65
- | `abs` | No | Dedicated A/B metrics table; see [Eval and A/B tables](#eval-and-a-b-tables) |
69
+ | `evals` | No | Backend-native eval-runs table; derived over the core when omitted — see [Eval and A/B tables](#eval-and-a-b-tables) |
70
+ | `abs` | No | Backend-native A/B metrics table; derived over the core when omitted — see [Eval and A/B tables](#eval-and-a-b-tables) |
66
71
 
67
72
  A throwing `put` is logged and dropped. It never fails a turn. When
68
73
  resolving a missing continuation token, a throwing `get` fails the
@@ -71,23 +76,34 @@ follow-up so a store outage does not open a new session. Return
71
76
 
72
77
  ## Eval and A/B tables
73
78
 
74
- Two dedicated tables carry structured rows instead of opaque KV values.
75
- Both are optional and independent of `put` / `get` / `list`.
76
-
77
- `evals` keeps playground eval batches across restarts. Provide `put`,
78
- `delete`, and `list` over run snapshots keyed by `runId`. The Agent SDK
79
- upserts a snapshot as a batch starts, progresses, and finishes, prunes
80
- runs past the playground history window, and lists everything back at
81
- serve start. Without this table, eval history lives in process memory
82
- and a restart clears it. See [Evals](./evals.md#configure-eval-runs).
83
-
84
- `abs` exports live A/B metrics. Provide `putSample` to append one
85
- cumulative metric sample per enrolled experiment on each completed or
86
- failed turn. Optional `putSnapshot` and `getSnapshot` store and serve
87
- back the latest aggregate snapshot, so a replacement host with no local
88
- sessions can still serve the A/Bs surface. Without this table, samples
89
- only go where each experiment's `onSample` sends them; session event
90
- logs remain the assignment source of truth. See
79
+ Two dedicated table groups carry structured rows instead of opaque KV
80
+ values. Both are **optional optimizations**: when a group is not
81
+ authored, `defineStorage` derives it over the KV core, so a backend that
82
+ implements only the core loses nothing. Author a group only when the
83
+ backend has a better native shape (a real database table, an analytics
84
+ pipeline) the built-in `fileKv` and `cursorHostedStorage` both do.
85
+
86
+ `evals` keeps playground eval batches across restarts (`put`, `delete`,
87
+ `list` over run snapshots keyed by `runId`). The Agent SDK upserts a
88
+ snapshot as a batch starts, progresses, and finishes, prunes runs past
89
+ the playground history window, and lists everything back at serve start.
90
+ **Derived form**: one key per run under
91
+ `agentkit/v1/{agent}/eval-runs/{runId}` needs core `put` + `delete` +
92
+ `list`. Only a core missing `delete` or `list` leaves eval history in
93
+ process memory (cleared on restart). See
94
+ [Evals](./evals.md#configure-eval-runs).
95
+
96
+ `abs` exports live A/B metrics: `putSample` appends one cumulative
97
+ metric sample per enrolled experiment on each completed or failed turn;
98
+ optional `putSnapshot` / `getSnapshot` store and serve back the latest
99
+ aggregate so a replacement host with no local sessions can still serve
100
+ the A/Bs surface. **Derived form**: each sample lands as its own key
101
+ (`agentkit/v1/{agent}/ab-samples/{experiment}/{sessionId}/{at}` — a
102
+ blind append-only put, never a read-modify-write of one growing array)
103
+ and the snapshot lives at the fixed `agentkit/v1/{agent}/ab-snapshot`
104
+ key (last-write-wins is correct for "latest aggregate"). `putSample` and
105
+ `putSnapshot` need only core `put`; `getSnapshot` needs core `get`.
106
+ Session event logs remain the assignment source of truth either way. See
91
107
  [Live A/B metrics](./ab.md).
92
108
 
93
109
  ## Policy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cursor/july",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
4
4
  "description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {
@@ -270,7 +270,7 @@ a mention), opt in explicitly:
270
270
  export default slackChannel({
271
271
  engagement: {
272
272
  channelPosts: {
273
- allow: ["#issues-glass"], // explicit allowlist; no wildcard exists
273
+ allow: ["#issues-cursor-desktop"], // explicit allowlist; no wildcard exists
274
274
  posts: "top-level", // default — thread replies never dispatch
275
275
  debounceMs: 15_000, // optional: edits settle, deletes cancel
276
276
  },
@@ -16,6 +16,7 @@
16
16
  * agent-serve slack <subcommand>
17
17
  */
18
18
 
19
+ import { spawn } from "node:child_process";
19
20
  import { readFile } from "node:fs/promises";
20
21
  import { resolve } from "node:path";
21
22
  import { parseArgs } from "node:util";
@@ -44,6 +45,7 @@ import {
44
45
  cmdTrajectory,
45
46
  } from "../internal/cli-ax.js";
46
47
  import {
48
+ cmdDelete,
47
49
  cmdDeploy,
48
50
  cmdDeploymentStatus,
49
51
  cmdDeployments,
@@ -61,6 +63,11 @@ import {
61
63
  packageVersion,
62
64
  } from "../internal/distribution.js";
63
65
  import { loadAgentLocalEnv } from "../internal/local-env.js";
66
+ import {
67
+ ENTER_RESTART_EXIT_CODE,
68
+ isServeRestartWorker,
69
+ runEnterRestartSupervisor,
70
+ } from "../internal/serve-restart.js";
64
71
  import { clearTerminal, stdoutPalette } from "../internal/terminal-style.js";
65
72
  import { cmdUpdate, warnIfOutdated } from "../internal/update-check.js";
66
73
  import type { AgentProject, AgentServeHandle } from "../types.js";
@@ -134,6 +141,7 @@ Usage:
134
141
  ${CLI} deployments [--team <id>] [--json]
135
142
  ${CLI} deployment <slug> [--team <id>] [--json]
136
143
  ${CLI} stop <slug> [--team <id>] [--json] [--no-wait]
144
+ ${CLI} delete <slug> [--team <id>] [--json] [--no-wait]
137
145
  ${CLI} rotate-token <slug> [--team <id>]
138
146
  ${CLI} rotate-pod-credential <slug> [--team <id>]
139
147
  ${CLI} secrets set <slug> NAME... | list <slug> | unset <slug> NAME
@@ -143,7 +151,8 @@ Usage:
143
151
 
144
152
  Commands:
145
153
  serve Serve agents under /<slug>/... (index at /). On a TTY, press
146
- Enter to restart (reloads agent code + Vite HMR child).
154
+ Enter to restart (re-executes this process so agent code, evals,
155
+ and Vite reload).
147
156
  dev Local development: same as \`${CLI} serve --dev\` (manual
148
157
  schedule/reminder dispatch, unsigned GitHub loopback, Vite HMR).
149
158
  chat Interactive REPL against a running server (follow-ups keep the
@@ -252,6 +261,8 @@ Commands:
252
261
  deployments List the team's deployments (slug, status, generation, kind).
253
262
  deployment Show one deployment in full (status, lastError, engine info).
254
263
  stop Stop a deployment and wait until it reports stopped.
264
+ delete Delete a deployment (teardown + purge the record) and wait
265
+ until GET 404s. The slug is then free to redeploy.
255
266
  rotate-token Mint a new alias token for a deployment (shown once); the old
256
267
  token stops working immediately.
257
268
  rotate-pod-credential
@@ -555,7 +566,12 @@ async function main(argv: string[]): Promise<number> {
555
566
  // Best-effort, cached, and silent on failure. `update` does its own fresh
556
567
  // lookup, --json runs stay quiet for machine consumers, and `mcp` skips it
557
568
  // so MCP client spawns stay fast (stdout there is the protocol wire).
558
- if (command !== "update" && command !== "mcp" && values.json !== true) {
569
+ if (
570
+ command !== "update" &&
571
+ command !== "mcp" &&
572
+ values.json !== true &&
573
+ !isServeRestartWorker()
574
+ ) {
559
575
  await warnIfOutdated();
560
576
  }
561
577
 
@@ -731,6 +747,10 @@ async function main(argv: string[]): Promise<number> {
731
747
  return cmdStop(positionals[0], deployOptionsFromValues(values));
732
748
  }
733
749
 
750
+ case "delete": {
751
+ return cmdDelete(positionals[0], deployOptionsFromValues(values));
752
+ }
753
+
734
754
  case "rotate-token": {
735
755
  return cmdRotateToken(positionals[0], deployOptionsFromValues(values));
736
756
  }
@@ -1227,6 +1247,16 @@ async function main(argv: string[]): Promise<number> {
1227
1247
  },
1228
1248
  };
1229
1249
  const enterToRestart = process.stdin.isTTY === true;
1250
+ if (enterToRestart && !isServeRestartWorker()) {
1251
+ return runEnterRestartSupervisor({
1252
+ spawn: (command, args, spawnOptions) =>
1253
+ spawn(command, args, spawnOptions),
1254
+ onRestart: () => {
1255
+ clearTerminal();
1256
+ },
1257
+ });
1258
+ }
1259
+
1230
1260
  const bannerOpts = {
1231
1261
  noPlayground: values["no-playground"] === true,
1232
1262
  dev,
@@ -1244,9 +1274,9 @@ async function main(argv: string[]): Promise<number> {
1244
1274
  return next;
1245
1275
  };
1246
1276
 
1247
- let handle = await start();
1277
+ const handle = await start();
1248
1278
  let closing = false;
1249
- let restarting = false;
1279
+ let restartRequested = false;
1250
1280
 
1251
1281
  await new Promise<void>((resolve) => {
1252
1282
  const shutdown = (): void => {
@@ -1268,40 +1298,17 @@ async function main(argv: string[]): Promise<number> {
1268
1298
  process.stdin.on("data", (chunk: string | Buffer) => {
1269
1299
  const text =
1270
1300
  typeof chunk === "string" ? chunk : chunk.toString("utf8");
1271
- if (!isEnterOnly(text) || closing || restarting) {
1301
+ if (!isEnterOnly(text) || closing) {
1272
1302
  return;
1273
1303
  }
1274
- restarting = true;
1275
- // Close + re-serve reloads authored agent modules and respawns Vite.
1276
- // Hold the "restarting…" frame briefly so a fast close doesn't look
1277
- // like Enter did nothing.
1304
+ closing = true;
1305
+ restartRequested = true;
1278
1306
  clearTerminal();
1279
1307
  process.stdout.write(style.dim("restarting…\n"));
1280
- void Promise.all([handle.close(), sleep(450)])
1281
- .then(() => {
1282
- clearTerminal();
1283
- return start();
1284
- })
1285
- .then((next) => {
1286
- handle = next;
1287
- })
1288
- .catch((error: unknown) => {
1289
- process.stderr.write(
1290
- `[agent-sdk] restart failed: ${
1291
- error instanceof Error
1292
- ? (error.stack ?? error.message)
1293
- : String(error)
1294
- }\n`
1295
- );
1296
- closing = true;
1297
- resolve();
1298
- })
1299
- .finally(() => {
1300
- restarting = false;
1301
- });
1308
+ void handle.close().finally(resolve);
1302
1309
  });
1303
1310
  });
1304
- return 0;
1311
+ return restartRequested ? ENTER_RESTART_EXIT_CODE : 0;
1305
1312
  }
1306
1313
 
1307
1314
  default: {
@@ -1437,12 +1444,6 @@ function isEnterOnly(text: string): boolean {
1437
1444
  return text.length > 0 && [...text].every((ch) => ch === "\n" || ch === "\r");
1438
1445
  }
1439
1446
 
1440
- function sleep(ms: number): Promise<void> {
1441
- return new Promise((resolve) => {
1442
- setTimeout(resolve, ms);
1443
- });
1444
- }
1445
-
1446
1447
  /**
1447
1448
  * `dev [path]` takes a positional project root; `serve` keeps `--dir` only.
1448
1449
  * Reject mixing a positional with an explicit `--dir`, and extra args on `dev`.
@@ -16,6 +16,7 @@
16
16
  * them.
17
17
  */
18
18
 
19
+ import { stat } from "node:fs/promises";
19
20
  import { register as registerModuleHooks } from "node:module";
20
21
  import { join } from "node:path";
21
22
  import { pathToFileURL } from "node:url";
@@ -38,6 +39,50 @@ import {
38
39
  const TSX_REGISTERED_KEY = Symbol.for("cursor.agentkit.tsxRegistered");
39
40
  const ALIASES_REGISTERED_KEY = Symbol.for("cursor.agentkit.aliasesRegistered");
40
41
 
42
+ /**
43
+ * ESM specifier for an authored agent/eval file.
44
+ *
45
+ * Node caches `import()` by URL for the life of the process, so a long-lived
46
+ * `agent-sdk dev` would otherwise keep serving the first load of eval files
47
+ * and agent modules. The mtime query string is ignored by the filesystem
48
+ * resolver and is the cache key.
49
+ *
50
+ * Truncate to an integer: vitest/esbuild treat the substring after the last
51
+ * `.` as a loader id, so `?mtime=1700000000000.4949` fails with
52
+ * `Invalid loader value: "4949"`. Named `mtime` rather than `t` so Vite does
53
+ * not treat it as its HMR timestamp and collapse the specifier to the path.
54
+ */
55
+ export function authoredModuleSpecifier(
56
+ absolutePath: string,
57
+ mtimeMs: number
58
+ ): string {
59
+ const url = pathToFileURL(absolutePath);
60
+ url.searchParams.set("mtime", String(Math.trunc(mtimeMs)));
61
+ return url.href;
62
+ }
63
+
64
+ /**
65
+ * Dynamically import an authored TypeScript/JavaScript module, re-reading it
66
+ * from disk when the file's mtime has changed since the last import.
67
+ */
68
+ export async function importAuthoredModule(
69
+ absolutePath: string
70
+ ): Promise<Record<string, unknown>> {
71
+ let mtimeMs = 0;
72
+ try {
73
+ mtimeMs = (await stat(absolutePath)).mtimeMs;
74
+ } catch {
75
+ // import() reports the real missing-file error.
76
+ }
77
+ const loaded: unknown = await import(
78
+ authoredModuleSpecifier(absolutePath, mtimeMs)
79
+ );
80
+ if (typeof loaded !== "object" || loaded === null) {
81
+ throw new Error(`authored module is not an object: ${absolutePath}`);
82
+ }
83
+ return loaded as Record<string, unknown>;
84
+ }
85
+
41
86
  let registration: Promise<void> | undefined;
42
87
 
43
88
  /**