@cursor/july 0.1.43 → 0.1.46
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 +5 -3
- package/README.md +3 -1
- package/dist/channels/github/api.d.ts +25 -0
- package/dist/channels/github/api.d.ts.map +1 -1
- package/dist/channels/github/api.js +48 -0
- package/dist/channels/github/cursor-account.d.ts +7 -0
- package/dist/channels/github/cursor-account.d.ts.map +1 -1
- package/dist/channels/github/cursor-account.js +18 -0
- package/dist/channels/github/defaults.d.ts +1 -1
- package/dist/channels/github/defaults.js +1 -1
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +15 -7
- package/dist/channels/github/progress.d.ts +6 -5
- package/dist/channels/github/progress.d.ts.map +1 -1
- package/dist/channels/github/progress.js +58 -16
- package/dist/channels/github/state.d.ts +11 -0
- package/dist/channels/github/state.d.ts.map +1 -1
- package/dist/channels/github/state.js +1 -1
- package/dist/channels/github/types.d.ts +11 -3
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels.d.ts +17 -0
- package/dist/channels.d.ts.map +1 -1
- package/dist/channels.js +31 -0
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.DsTLo2j1.js → app.C2NFTb-h.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.B-FxvuoI.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.DoVfutcV.js → VPLocalSearchBox.o1_FJGip.js} +1 -1
- package/dist/docs/assets/chunks/{theme.DtuVtKkc.js → theme.BcGduE7g.js} +2 -2
- package/dist/docs/assets/{guides_github.md.DSg0j9qj.js → guides_github.md.B8QKtIpw.js} +7 -6
- package/dist/docs/assets/{guides_github.md.DSg0j9qj.lean.js → guides_github.md.B8QKtIpw.lean.js} +1 -1
- package/dist/docs/assets/guides_opentelemetry.md.Csn7ZI25.js +27 -0
- package/dist/docs/assets/guides_opentelemetry.md.Csn7ZI25.lean.js +1 -0
- package/dist/docs/assets/index.md.COeoSkcF.js +5 -0
- package/dist/docs/assets/index.md.COeoSkcF.lean.js +1 -0
- package/dist/docs/assets/{quickstart.md.rIbfahJM.js → quickstart.md.DZxBu44y.js} +18 -49
- package/dist/docs/assets/quickstart.md.DZxBu44y.lean.js +1 -0
- package/dist/docs/assets/{reference_agent-config.md.CRmkoxd6.js → reference_agent-config.md.DHkkvcEZ.js} +9 -4
- package/dist/docs/assets/{reference_agent-config.md.CRmkoxd6.lean.js → reference_agent-config.md.DHkkvcEZ.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.DqEqQpGn.js → reference_cli.md.BDmjPPAm.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.4cbRRIIu.js → reference_hooks.md.DJE5DXcT.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.lSrsTxYJ.js → reference_tools.md.kJfJAP2m.js} +1 -1
- package/dist/docs/assets/{storage.md.DcGSnIxX.js → storage.md.CJYd5YmN.js} +2 -2
- package/dist/docs/assets/{storage.md.DcGSnIxX.lean.js → storage.md.CJYd5YmN.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- 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 +3 -3
- 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 +10 -9
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +3 -3
- package/dist/docs/guides/opentelemetry.html +12 -5
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +8 -28
- package/dist/docs/quickstart.html +24 -55
- package/dist/docs/reference/agent-config.html +11 -6
- package/dist/docs/reference/artifacts.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +6 -6
- 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 +5 -5
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +5 -5
- package/dist/docs/templates/triage.html +3 -3
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/internal/auth.d.ts +4 -0
- package/dist/internal/auth.d.ts.map +1 -1
- package/dist/internal/auth.js +7 -0
- package/dist/internal/cli-ax.js +2 -2
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +38 -7
- package/dist/internal/deploy-client.d.ts +8 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +5 -2
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +46 -9
- package/dist/internal/durable-session-store.d.ts +35 -23
- package/dist/internal/durable-session-store.d.ts.map +1 -1
- package/dist/internal/durable-session-store.js +71 -26
- package/dist/internal/host-otel.d.ts +25 -0
- package/dist/internal/host-otel.d.ts.map +1 -0
- package/dist/internal/host-otel.js +162 -0
- package/dist/internal/init-project.js +10 -10
- package/dist/internal/ledger-serving.d.ts +135 -67
- package/dist/internal/ledger-serving.d.ts.map +1 -1
- package/dist/internal/ledger-serving.js +326 -107
- package/dist/internal/otel/collector.d.ts +5 -0
- package/dist/internal/otel/collector.d.ts.map +1 -1
- package/dist/internal/otel/collector.js +68 -27
- package/dist/internal/sdk-runner.d.ts +1 -1
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +1 -1
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +3 -2
- package/dist/internal/session-engine.d.ts +23 -18
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +83 -32
- package/dist/kv/memory-kv.d.ts +8 -0
- package/dist/kv/memory-kv.d.ts.map +1 -1
- package/dist/kv/memory-kv.js +8 -0
- package/dist/ledger/janitor.d.ts +60 -0
- package/dist/ledger/janitor.d.ts.map +1 -0
- package/dist/ledger/janitor.js +137 -0
- package/dist/ledger/session-ledger.d.ts +132 -43
- package/dist/ledger/session-ledger.d.ts.map +1 -1
- package/dist/ledger/session-ledger.js +282 -50
- package/dist/ledger.d.ts +9 -8
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +7 -7
- package/dist/playground/assets/{index-D-DIYQzw.js → index-6wW6SAc4.js} +19 -19
- package/dist/playground/assets/index-CSRYDAFw.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +5 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +6 -0
- package/dist/types.d.ts +100 -10
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +33 -106
- package/docs/guides/github.md +23 -18
- package/docs/guides/opentelemetry.md +30 -0
- package/docs/quickstart.md +89 -227
- package/docs/reference/agent-config.md +47 -0
- package/docs/reference/cli.md +2 -2
- package/docs/reference/hooks.md +1 -1
- package/docs/reference/tools.md +5 -4
- package/docs/storage.md +26 -9
- package/package.json +2 -2
- package/skills/otel/SKILL.md +20 -2
- package/src/channels/github/api.ts +122 -0
- package/src/channels/github/cursor-account.ts +23 -0
- package/src/channels/github/defaults.ts +1 -1
- package/src/channels/github/github-channel.ts +14 -1
- package/src/channels/github/progress.ts +84 -19
- package/src/channels/github/state.ts +14 -0
- package/src/channels/github/types.ts +7 -3
- package/src/channels.ts +38 -0
- package/src/index.ts +2 -0
- package/src/internal/auth.ts +10 -0
- package/src/internal/cli-ax.ts +2 -2
- package/src/internal/cli-deploy.ts +58 -3
- package/src/internal/deploy-client.ts +11 -0
- package/src/internal/discovery.ts +49 -0
- package/src/internal/durable-session-store.ts +66 -27
- package/src/internal/host-otel.ts +252 -0
- package/src/internal/init-project.ts +10 -10
- package/src/internal/ledger-serving.ts +439 -148
- package/src/internal/otel/collector.ts +135 -50
- package/src/internal/sdk-runner.ts +6 -0
- package/src/internal/server.ts +7 -2
- package/src/internal/session-engine.ts +127 -39
- package/src/kv/memory-kv.ts +8 -0
- package/src/ledger/janitor.ts +193 -0
- package/src/ledger/session-ledger.ts +372 -68
- package/src/ledger.ts +21 -6
- package/src/storage-backends/cursor-hosted.ts +17 -2
- package/src/types.ts +108 -10
- package/dist/docs/assets/chunks/@localSearchIndexroot.BZx4pmZL.js +0 -1
- package/dist/docs/assets/guides_opentelemetry.md.DmyUwC5R.js +0 -20
- package/dist/docs/assets/guides_opentelemetry.md.DmyUwC5R.lean.js +0 -1
- package/dist/docs/assets/index.md.CMc5FP7E.js +0 -25
- package/dist/docs/assets/index.md.CMc5FP7E.lean.js +0 -1
- package/dist/docs/assets/quickstart.md.rIbfahJM.lean.js +0 -1
- package/dist/playground/assets/index-DQTH622f.css +0 -1
- /package/dist/docs/assets/{reference_cli.md.DqEqQpGn.lean.js → reference_cli.md.BDmjPPAm.lean.js} +0 -0
- /package/dist/docs/assets/{reference_hooks.md.4cbRRIIu.lean.js → reference_hooks.md.DJE5DXcT.lean.js} +0 -0
- /package/dist/docs/assets/{reference_tools.md.lSrsTxYJ.lean.js → reference_tools.md.kJfJAP2m.lean.js} +0 -0
|
@@ -275,6 +275,13 @@ function loadAgent(ctx, agentDir, options) {
|
|
|
275
275
|
message: "builtinTools is not supported on subagents; ignoring.",
|
|
276
276
|
});
|
|
277
277
|
}
|
|
278
|
+
if ((config === null || config === void 0 ? void 0 : config.tools) !== undefined) {
|
|
279
|
+
ctx.diagnostics.push({
|
|
280
|
+
severity: "warning",
|
|
281
|
+
path: displayPath(ctx, join(agentDir, "agent.ts")),
|
|
282
|
+
message: "tools is not supported on subagents (they keep the harness task-tool toolset); ignoring.",
|
|
283
|
+
});
|
|
284
|
+
}
|
|
278
285
|
const artifactsPath = yield findModuleFile(agentDir, "artifacts");
|
|
279
286
|
if (artifactsPath !== undefined) {
|
|
280
287
|
ctx.diagnostics.push({
|
|
@@ -299,6 +306,41 @@ function loadAgent(ctx, agentDir, options) {
|
|
|
299
306
|
const localCwd = resolveAgentCwd(ctx, (_a = config === null || config === void 0 ? void 0 : config.local) === null || _a === void 0 ? void 0 : _a.cwd);
|
|
300
307
|
const localWorkspaceDir = resolveAgentCwd(ctx, (_b = config === null || config === void 0 ? void 0 : config.local) === null || _b === void 0 ? void 0 : _b.workspaceDir);
|
|
301
308
|
const localSandbox = ((_c = config === null || config === void 0 ? void 0 : config.local) === null || _c === void 0 ? void 0 : _c.sandbox) === true;
|
|
309
|
+
// Built-in tool allowlist (top-level `tools`). `[]` is meaningful (no
|
|
310
|
+
// native built-in tools), so presence is keyed on the field, not on
|
|
311
|
+
// emptiness. "mcp" is always granted alongside a configured allowlist:
|
|
312
|
+
// it is transport, not capability — this kit's own server tools ride the
|
|
313
|
+
// SDK custom-tool MCP path, so omitting it silently breaks
|
|
314
|
+
// `agent/tools/`, and what MCP actually exposes stays controlled by the
|
|
315
|
+
// second layer (authored tools, mcp-connections, the harness cwd's
|
|
316
|
+
// ambient config).
|
|
317
|
+
const authoredAllowlist = config === null || config === void 0 ? void 0 : config.tools;
|
|
318
|
+
const allowedTools = authoredAllowlist === undefined || authoredAllowlist.includes("mcp")
|
|
319
|
+
? authoredAllowlist
|
|
320
|
+
: [...authoredAllowlist, "mcp"];
|
|
321
|
+
// The allowlist states runtime-agnostic intent, but the SDK cannot
|
|
322
|
+
// enforce tool restrictions on cloud agents yet — a cloud-runtime agent
|
|
323
|
+
// that declares one must fail at serve start, never run unrestricted.
|
|
324
|
+
// (Hybrid per-send cloud sessions fail closed in the session engine.)
|
|
325
|
+
if (allowedTools !== undefined && runtime === "cloud") {
|
|
326
|
+
ctx.diagnostics.push({
|
|
327
|
+
severity: "error",
|
|
328
|
+
path: displayPath(ctx, join(agentDir, "agent.ts")),
|
|
329
|
+
message: 'tools cannot be enforced on runtime: "cloud" yet (the Cursor SDK rejects tool restrictions on cloud agents). Remove `tools` or run the agent on the local runtime.',
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// `execution: "agent"` tool scripts run through the shell tool. Shell is
|
|
333
|
+
// a real capability, so it is never injected — but an allowlist that
|
|
334
|
+
// strands authored scripts deserves a loud diagnostic, not silence.
|
|
335
|
+
if (allowedTools !== undefined &&
|
|
336
|
+
!allowedTools.includes("shell") &&
|
|
337
|
+
tools.some((tool) => tool.execution === "agent")) {
|
|
338
|
+
ctx.diagnostics.push({
|
|
339
|
+
severity: "warning",
|
|
340
|
+
path: displayPath(ctx, join(agentDir, "agent.ts")),
|
|
341
|
+
message: '`tools` omits "shell" but this agent has execution: "agent" tools, which run as shell scripts; the model will not be able to run them.',
|
|
342
|
+
});
|
|
343
|
+
}
|
|
302
344
|
if (localCwd !== undefined && localWorkspaceDir !== undefined) {
|
|
303
345
|
ctx.diagnostics.push({
|
|
304
346
|
severity: "warning",
|
|
@@ -325,24 +367,19 @@ function loadAgent(ctx, agentDir, options) {
|
|
|
325
367
|
});
|
|
326
368
|
}
|
|
327
369
|
appendBuiltinTools(ctx, agentDir, tools, config === null || config === void 0 ? void 0 : config.builtinTools);
|
|
328
|
-
return {
|
|
329
|
-
name,
|
|
330
|
-
description: config === null || config === void 0 ? void 0 : config.description,
|
|
370
|
+
return Object.assign(Object.assign({ name, description: config === null || config === void 0 ? void 0 : config.description,
|
|
331
371
|
// Root agents always get a concrete model: authored value or DEFAULT_MODEL.
|
|
332
|
-
model: isValidModelSetting(config === null || config === void 0 ? void 0 : config.model) ? config.model : DEFAULT_MODEL,
|
|
333
|
-
instructions,
|
|
372
|
+
model: isValidModelSetting(config === null || config === void 0 ? void 0 : config.model) ? config.model : DEFAULT_MODEL, instructions,
|
|
334
373
|
runtime,
|
|
335
374
|
cloud,
|
|
336
|
-
local,
|
|
337
|
-
hosting,
|
|
375
|
+
local }, (allowedTools === undefined ? {} : { allowedTools })), { hosting,
|
|
338
376
|
concurrency,
|
|
339
377
|
serving,
|
|
340
378
|
tools,
|
|
341
379
|
skills,
|
|
342
380
|
connections,
|
|
343
381
|
subagents,
|
|
344
|
-
seedFiles
|
|
345
|
-
};
|
|
382
|
+
seedFiles });
|
|
346
383
|
});
|
|
347
384
|
}
|
|
348
385
|
/**
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Two APIs, one backend: `defineStorage` is the **storage API** (agent
|
|
5
5
|
* state — session records, event chunks, author KV), and the session
|
|
6
|
-
* ledger is the **durable session API** (session identity,
|
|
7
|
-
* fenced commits). The ledger consumes {@link SessionLedgerKv} —
|
|
8
|
-
* the
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* ledger is the **durable session API** (session identity, mailboxes,
|
|
7
|
+
* leases, fenced commits). The ledger consumes {@link SessionLedgerKv} —
|
|
8
|
+
* the full CAS-capable KV surface, since the inbox reads/sweeps mailbox
|
|
9
|
+
* payload blobs (`get`/`put`/`delete`) and scans by prefix (`listKeys`)
|
|
10
|
+
* on top of the CAS trio; this module adapts a storage backend's methods
|
|
11
|
+
* into that interface, so a deployment's one authored backend serves
|
|
12
|
+
* both APIs by default.
|
|
11
13
|
*
|
|
12
14
|
* Calls go straight at the config's methods — NOT through the
|
|
13
15
|
* StorageCoordinator: the coordinator's queue is bounded, serialized, and
|
|
@@ -21,28 +23,38 @@ export interface StorageCasKvArgs {
|
|
|
21
23
|
projectRoot: string;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* The one place the ledger's physical namespace is minted: the per-agent
|
|
27
|
+
* prefix for ledger state, following the {@link storageKeys} convention
|
|
28
|
+
* (`<root>/<agent>/<family>/…`) so a store shared by several ledger-mode
|
|
29
|
+
* agents (one fileKv dir, one hosted deployment) never mixes their
|
|
30
|
+
* sessions, leases, or mailboxes — and so each agent's janitor
|
|
31
|
+
* prefix-scan only ever sees its own ledgers. The extra
|
|
32
|
+
* `durable-session` segment keeps the ledger's `session/` family out of
|
|
33
|
+
* `storageKeys.sessionPrefix` scans (storage restore lists
|
|
34
|
+
* `<root>/<agent>/session/`). The ledger itself never sees this string:
|
|
35
|
+
* it speaks bare `session/…` / `ledger/…` / `mailbox/…` keys against a
|
|
36
|
+
* handle that {@link namespacedKv} has already scoped.
|
|
28
37
|
*/
|
|
29
|
-
export declare function
|
|
38
|
+
export declare function ledgerKeyPrefix(agentName: string): string;
|
|
30
39
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* {@link
|
|
40
|
+
* Adapt a storage backend into the ledger's KV interface. Throws when
|
|
41
|
+
* the backend does not implement the `cas` group, or omits `get` /
|
|
42
|
+
* `delete` (optional for resident-only sinks, but the ledger reads and
|
|
43
|
+
* sweeps mailbox payload blobs through the same store) — the caller
|
|
44
|
+
* turns that into the fail-fast startup error for `serving: "ledger"`.
|
|
45
|
+
* Every call carries a `reason: "coordination"` {@link StorageContext}.
|
|
37
46
|
*/
|
|
38
|
-
export declare function
|
|
47
|
+
export declare function storageCasKv(config: StorageConfig, args: StorageCasKvArgs): SessionLedgerKv;
|
|
39
48
|
/**
|
|
40
|
-
* Scope a raw store handle under a namespace
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
49
|
+
* Scope a raw store handle under a namespace: every key going in gets it
|
|
50
|
+
* prepended, and `listKeys` results come back with it **stripped**, so a
|
|
51
|
+
* caller that lists and then reads/deletes the returned keys stays fully
|
|
52
|
+
* prefix-free (the janitor scan and the orphan sweep do exactly that).
|
|
53
|
+
* Applied exactly once, where the engine constructs the ledger's store
|
|
54
|
+
* handle — the same conceptual boundary where `host.kv` gets its agent
|
|
55
|
+
* scoping. Internal: not part of the public kv interface, and callers
|
|
56
|
+
* (including the explicit `durableSessionStore` override) always supply
|
|
57
|
+
* the raw store — they never write prefixes.
|
|
46
58
|
*/
|
|
47
59
|
export declare function namespacedKv(store: SessionLedgerKv, namespace: string): SessionLedgerKv;
|
|
48
60
|
//# sourceMappingURL=durable-session-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"durable-session-store.d.ts","sourceRoot":"","sources":["../../src/internal/durable-session-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"durable-session-store.d.ts","sourceRoot":"","sources":["../../src/internal/durable-session-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,eAAe,CAAC;AAGvB,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,GACrB,eAAe,CA0CjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,MAAM,GAChB,eAAe,CAcjB"}
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Two APIs, one backend: `defineStorage` is the **storage API** (agent
|
|
5
5
|
* state — session records, event chunks, author KV), and the session
|
|
6
|
-
* ledger is the **durable session API** (session identity,
|
|
7
|
-
* fenced commits). The ledger consumes {@link SessionLedgerKv} —
|
|
8
|
-
* the
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* ledger is the **durable session API** (session identity, mailboxes,
|
|
7
|
+
* leases, fenced commits). The ledger consumes {@link SessionLedgerKv} —
|
|
8
|
+
* the full CAS-capable KV surface, since the inbox reads/sweeps mailbox
|
|
9
|
+
* payload blobs (`get`/`put`/`delete`) and scans by prefix (`listKeys`)
|
|
10
|
+
* on top of the CAS trio; this module adapts a storage backend's methods
|
|
11
|
+
* into that interface, so a deployment's one authored backend serves
|
|
12
|
+
* both APIs by default.
|
|
11
13
|
*
|
|
12
14
|
* Calls go straight at the config's methods — NOT through the
|
|
13
15
|
* StorageCoordinator: the coordinator's queue is bounded, serialized, and
|
|
@@ -25,10 +27,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
25
27
|
};
|
|
26
28
|
import { keySegment, STORAGE_KEY_ROOT, } from "../storage.js";
|
|
27
29
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
30
|
+
* The one place the ledger's physical namespace is minted: the per-agent
|
|
31
|
+
* prefix for ledger state, following the {@link storageKeys} convention
|
|
32
|
+
* (`<root>/<agent>/<family>/…`) so a store shared by several ledger-mode
|
|
33
|
+
* agents (one fileKv dir, one hosted deployment) never mixes their
|
|
34
|
+
* sessions, leases, or mailboxes — and so each agent's janitor
|
|
35
|
+
* prefix-scan only ever sees its own ledgers. The extra
|
|
36
|
+
* `durable-session` segment keeps the ledger's `session/` family out of
|
|
37
|
+
* `storageKeys.sessionPrefix` scans (storage restore lists
|
|
38
|
+
* `<root>/<agent>/session/`). The ledger itself never sees this string:
|
|
39
|
+
* it speaks bare `session/…` / `ledger/…` / `mailbox/…` keys against a
|
|
40
|
+
* handle that {@link namespacedKv} has already scoped.
|
|
41
|
+
*/
|
|
42
|
+
export function ledgerKeyPrefix(agentName) {
|
|
43
|
+
return `${STORAGE_KEY_ROOT}/${keySegment(agentName)}/durable-session/`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Adapt a storage backend into the ledger's KV interface. Throws when
|
|
47
|
+
* the backend does not implement the `cas` group, or omits `get` /
|
|
48
|
+
* `delete` (optional for resident-only sinks, but the ledger reads and
|
|
49
|
+
* sweeps mailbox payload blobs through the same store) — the caller
|
|
50
|
+
* turns that into the fail-fast startup error for `serving: "ledger"`.
|
|
51
|
+
* Every call carries a `reason: "coordination"` {@link StorageContext}.
|
|
32
52
|
*/
|
|
33
53
|
export function storageCasKv(config, args) {
|
|
34
54
|
const ctx = {
|
|
@@ -40,7 +60,28 @@ export function storageCasKv(config, args) {
|
|
|
40
60
|
if (cas === undefined) {
|
|
41
61
|
throw new Error("storageCasKv: the storage backend does not implement the cas group (conditional writes)");
|
|
42
62
|
}
|
|
63
|
+
const get = config.get;
|
|
64
|
+
const remove = config.delete;
|
|
65
|
+
if (get === undefined || remove === undefined) {
|
|
66
|
+
throw new Error("storageCasKv: the storage backend must implement get and delete (the session ledger reads and sweeps payload blobs through the same store)");
|
|
67
|
+
}
|
|
43
68
|
return {
|
|
69
|
+
get(key) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
var _a;
|
|
72
|
+
return (_a = (yield get(key, ctx))) !== null && _a !== void 0 ? _a : undefined;
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
put(key, value) {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
yield config.put(key, value, ctx);
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
delete(key) {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
yield remove(key, ctx);
|
|
83
|
+
});
|
|
84
|
+
},
|
|
44
85
|
getWithVersion(key) {
|
|
45
86
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
87
|
return yield cas.getWithVersion(key, ctx);
|
|
@@ -56,31 +97,35 @@ export function storageCasKv(config, args) {
|
|
|
56
97
|
return yield cas.putIfVersion(key, value, expectedVersion, ctx);
|
|
57
98
|
});
|
|
58
99
|
},
|
|
100
|
+
listKeys(prefix) {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
return yield cas.listKeys(prefix, ctx);
|
|
103
|
+
});
|
|
104
|
+
},
|
|
59
105
|
};
|
|
60
106
|
}
|
|
61
107
|
/**
|
|
62
|
-
*
|
|
63
|
-
* `
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Scope a raw store handle under a namespace, prepending it to every
|
|
74
|
-
* key on the way in. Applied exactly once, where the engine constructs
|
|
75
|
-
* the ledger's store handle — the same conceptual boundary where
|
|
76
|
-
* `host.kv` gets its agent scoping. Internal: not part of the public kv
|
|
77
|
-
* interface, and callers (including the explicit `durableSessionStore`
|
|
78
|
-
* override) always supply the raw store — they never write prefixes.
|
|
108
|
+
* Scope a raw store handle under a namespace: every key going in gets it
|
|
109
|
+
* prepended, and `listKeys` results come back with it **stripped**, so a
|
|
110
|
+
* caller that lists and then reads/deletes the returned keys stays fully
|
|
111
|
+
* prefix-free (the janitor scan and the orphan sweep do exactly that).
|
|
112
|
+
* Applied exactly once, where the engine constructs the ledger's store
|
|
113
|
+
* handle — the same conceptual boundary where `host.kv` gets its agent
|
|
114
|
+
* scoping. Internal: not part of the public kv interface, and callers
|
|
115
|
+
* (including the explicit `durableSessionStore` override) always supply
|
|
116
|
+
* the raw store — they never write prefixes.
|
|
79
117
|
*/
|
|
80
118
|
export function namespacedKv(store, namespace) {
|
|
81
119
|
return {
|
|
120
|
+
get: (key) => store.get(namespace + key),
|
|
121
|
+
put: (key, value) => store.put(namespace + key, value),
|
|
122
|
+
delete: (key) => store.delete(namespace + key),
|
|
82
123
|
getWithVersion: (key) => store.getWithVersion(namespace + key),
|
|
83
124
|
putIfAbsent: (key, value) => store.putIfAbsent(namespace + key, value),
|
|
84
125
|
putIfVersion: (key, value, expectedVersion) => store.putIfVersion(namespace + key, value, expectedVersion),
|
|
126
|
+
listKeys: (prefix) => __awaiter(this, void 0, void 0, function* () {
|
|
127
|
+
const keys = yield store.listKeys(namespace + prefix);
|
|
128
|
+
return keys.map((key) => key.slice(namespace.length));
|
|
129
|
+
}),
|
|
85
130
|
};
|
|
86
131
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Author-facing OpenTelemetry surface for {@link HostContext.otel}.
|
|
3
|
+
*
|
|
4
|
+
* Always present on `ctx.host`. Counters and histograms no-op when no meter
|
|
5
|
+
* is running. `setAttributes` still tags the open session when a collector
|
|
6
|
+
* is attached. `forSession` is engine-only so a tool cannot retarget another
|
|
7
|
+
* conversation's tags.
|
|
8
|
+
*/
|
|
9
|
+
import type { Meter } from "@opentelemetry/api";
|
|
10
|
+
import type { HostOtelApi } from "../types.js";
|
|
11
|
+
import type { OtelCollector } from "./otel/collector.js";
|
|
12
|
+
export interface CreateHostOtelApiOptions {
|
|
13
|
+
agentName: string;
|
|
14
|
+
meter?: Meter;
|
|
15
|
+
collector?: OtelCollector;
|
|
16
|
+
/** Session bound for join tags; prefer {@link HostOtelSessionApi.forSession}. */
|
|
17
|
+
sessionId?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Engine-only binding. Not part of the public {@link HostOtelApi}. */
|
|
20
|
+
export interface HostOtelSessionApi extends HostOtelApi {
|
|
21
|
+
forSession(sessionId: string): HostOtelSessionApi;
|
|
22
|
+
}
|
|
23
|
+
/** Build the host OpenTelemetry API for one agent process. */
|
|
24
|
+
export declare function createHostOtelApi(options: CreateHostOtelApiOptions): HostOtelSessionApi;
|
|
25
|
+
//# sourceMappingURL=host-otel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-otel.d.ts","sourceRoot":"","sources":["../../src/internal/host-otel.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAsB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,aAAa,CAAC;AAGnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAqBzD,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,uEAAuE;AACvE,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAAC;CACnD;AAsBD,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,wBAAwB,GAChC,kBAAkB,CAYpB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Author-facing OpenTelemetry surface for {@link HostContext.otel}.
|
|
3
|
+
*
|
|
4
|
+
* Always present on `ctx.host`. Counters and histograms no-op when no meter
|
|
5
|
+
* is running. `setAttributes` still tags the open session when a collector
|
|
6
|
+
* is attached. `forSession` is engine-only so a tool cannot retarget another
|
|
7
|
+
* conversation's tags.
|
|
8
|
+
*/
|
|
9
|
+
import { attrs } from "./otel/attrs.js";
|
|
10
|
+
const METRIC_NAME = /^[A-Za-z][A-Za-z0-9_./-]*$/;
|
|
11
|
+
const RESERVED_METRICS = new Set([
|
|
12
|
+
"cursor.token.usage",
|
|
13
|
+
"cursor.tool.calls",
|
|
14
|
+
"cursor.cost.usage",
|
|
15
|
+
"agent_sdk.session.count",
|
|
16
|
+
"agent_sdk.turn.count",
|
|
17
|
+
"agent_sdk.subagent.count",
|
|
18
|
+
"agent_sdk.http.duration",
|
|
19
|
+
]);
|
|
20
|
+
const RESERVED_ATTRIBUTES = new Set([
|
|
21
|
+
"cursor.conversation.id",
|
|
22
|
+
"agent_sdk.agent",
|
|
23
|
+
"agent_sdk.turn_id",
|
|
24
|
+
"agent_sdk.framework",
|
|
25
|
+
]);
|
|
26
|
+
/** Build the host OpenTelemetry API for one agent process. */
|
|
27
|
+
export function createHostOtelApi(options) {
|
|
28
|
+
return createBoundHostOtelApi({
|
|
29
|
+
shared: {
|
|
30
|
+
agentName: options.agentName,
|
|
31
|
+
meter: options.meter,
|
|
32
|
+
collector: options.collector,
|
|
33
|
+
instruments: new Map(),
|
|
34
|
+
sessionTags: new Map(),
|
|
35
|
+
},
|
|
36
|
+
sessionId: options.sessionId,
|
|
37
|
+
localTags: {},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function createBoundHostOtelApi(state) {
|
|
41
|
+
const api = {
|
|
42
|
+
get enabled() {
|
|
43
|
+
return state.shared.meter !== undefined;
|
|
44
|
+
},
|
|
45
|
+
setAttributes(attributes) {
|
|
46
|
+
var _a;
|
|
47
|
+
const cleaned = validateAttributes(attributes);
|
|
48
|
+
if (state.sessionId === undefined) {
|
|
49
|
+
Object.assign(state.localTags, cleaned);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
mergeSessionTags(state, state.sessionId, cleaned);
|
|
53
|
+
(_a = state.shared.collector) === null || _a === void 0 ? void 0 : _a.setSessionAttributes(state.sessionId, cleaned);
|
|
54
|
+
},
|
|
55
|
+
increment(name, valueOrAttributes, maybeAttributes) {
|
|
56
|
+
var _a;
|
|
57
|
+
const value = typeof valueOrAttributes === "number" ? valueOrAttributes : 1;
|
|
58
|
+
const attributes = typeof valueOrAttributes === "number"
|
|
59
|
+
? maybeAttributes
|
|
60
|
+
: valueOrAttributes;
|
|
61
|
+
(_a = counter(state.shared, name)) === null || _a === void 0 ? void 0 : _a.add(value, emitAttributes(state, attributes));
|
|
62
|
+
},
|
|
63
|
+
record(name, value, attributes) {
|
|
64
|
+
var _a;
|
|
65
|
+
(_a = histogram(state.shared, name)) === null || _a === void 0 ? void 0 : _a.record(value, emitAttributes(state, attributes));
|
|
66
|
+
},
|
|
67
|
+
forSession(sessionId) {
|
|
68
|
+
const trimmed = sessionId.trim();
|
|
69
|
+
if (trimmed === "") {
|
|
70
|
+
throw new Error("host.otel.forSession requires a non-empty session id");
|
|
71
|
+
}
|
|
72
|
+
return createBoundHostOtelApi({
|
|
73
|
+
shared: state.shared,
|
|
74
|
+
sessionId: trimmed,
|
|
75
|
+
localTags: {},
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
return api;
|
|
80
|
+
}
|
|
81
|
+
function mergeSessionTags(state, sessionId, incoming) {
|
|
82
|
+
var _a;
|
|
83
|
+
const bag = (_a = state.shared.sessionTags.get(sessionId)) !== null && _a !== void 0 ? _a : {};
|
|
84
|
+
Object.assign(bag, incoming);
|
|
85
|
+
state.shared.sessionTags.set(sessionId, bag);
|
|
86
|
+
}
|
|
87
|
+
function emitAttributes(state, callSite) {
|
|
88
|
+
return attrs(Object.assign(Object.assign(Object.assign(Object.assign({}, sessionBag(state)), validateAttributes(callSite)), { "agent_sdk.agent": state.shared.agentName }), (state.sessionId === undefined
|
|
89
|
+
? {}
|
|
90
|
+
: { "cursor.conversation.id": state.sessionId })));
|
|
91
|
+
}
|
|
92
|
+
function sessionBag(state) {
|
|
93
|
+
var _a;
|
|
94
|
+
var _b;
|
|
95
|
+
if (state.sessionId === undefined) {
|
|
96
|
+
return state.localTags;
|
|
97
|
+
}
|
|
98
|
+
const fromCollector = (_a = state.shared.collector) === null || _a === void 0 ? void 0 : _a.getSessionAttributes(state.sessionId);
|
|
99
|
+
const fromShared = (_b = state.shared.sessionTags.get(state.sessionId)) !== null && _b !== void 0 ? _b : {};
|
|
100
|
+
return Object.assign(Object.assign(Object.assign({}, fromShared), (fromCollector !== null && fromCollector !== void 0 ? fromCollector : {})), state.localTags);
|
|
101
|
+
}
|
|
102
|
+
function counter(shared, name) {
|
|
103
|
+
validateMetricName(name);
|
|
104
|
+
if (shared.meter === undefined) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const existing = shared.instruments.get(name);
|
|
108
|
+
if (existing !== undefined) {
|
|
109
|
+
if (existing.kind !== "counter") {
|
|
110
|
+
throw new Error(`host.otel metric "${name}" is already a histogram`);
|
|
111
|
+
}
|
|
112
|
+
return existing.instrument;
|
|
113
|
+
}
|
|
114
|
+
const instrument = shared.meter.createCounter(name);
|
|
115
|
+
shared.instruments.set(name, { kind: "counter", instrument });
|
|
116
|
+
return instrument;
|
|
117
|
+
}
|
|
118
|
+
function histogram(shared, name) {
|
|
119
|
+
validateMetricName(name);
|
|
120
|
+
if (shared.meter === undefined) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const existing = shared.instruments.get(name);
|
|
124
|
+
if (existing !== undefined) {
|
|
125
|
+
if (existing.kind !== "histogram") {
|
|
126
|
+
throw new Error(`host.otel metric "${name}" is already a counter`);
|
|
127
|
+
}
|
|
128
|
+
return existing.instrument;
|
|
129
|
+
}
|
|
130
|
+
const instrument = shared.meter.createHistogram(name);
|
|
131
|
+
shared.instruments.set(name, { kind: "histogram", instrument });
|
|
132
|
+
return instrument;
|
|
133
|
+
}
|
|
134
|
+
function validateMetricName(name) {
|
|
135
|
+
if (!METRIC_NAME.test(name)) {
|
|
136
|
+
throw new Error(`host.otel metric name "${name}" must match [A-Za-z][A-Za-z0-9_./-]*`);
|
|
137
|
+
}
|
|
138
|
+
if (RESERVED_METRICS.has(name)) {
|
|
139
|
+
throw new Error(`host.otel metric name "${name}" is reserved`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function validateAttributes(attributes) {
|
|
143
|
+
if (attributes === undefined) {
|
|
144
|
+
return {};
|
|
145
|
+
}
|
|
146
|
+
const out = {};
|
|
147
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
148
|
+
if (value === undefined) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (RESERVED_ATTRIBUTES.has(key)) {
|
|
152
|
+
throw new Error(`host.otel attribute "${key}" is reserved; the runtime always sets it`);
|
|
153
|
+
}
|
|
154
|
+
if (typeof value !== "string" &&
|
|
155
|
+
typeof value !== "number" &&
|
|
156
|
+
typeof value !== "boolean") {
|
|
157
|
+
throw new Error(`host.otel attribute "${key}" must be a string, number, or boolean`);
|
|
158
|
+
}
|
|
159
|
+
out[key] = value;
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
@@ -517,20 +517,20 @@ function initNextStepEntries(options) {
|
|
|
517
517
|
if (cd !== undefined) {
|
|
518
518
|
steps.push({ command: cd });
|
|
519
519
|
}
|
|
520
|
-
if (!options.cliOnPath) {
|
|
521
|
-
steps.push({
|
|
522
|
-
command: 'export PATH="$PWD/node_modules/.bin:$PATH"',
|
|
523
|
-
note: "use the project-local agent-sdk bin",
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
520
|
if (!options.signedIn) {
|
|
521
|
+
const login = options.cliOnPath
|
|
522
|
+
? `${CLI_COMMAND_NAME} login`
|
|
523
|
+
: `npx ${PACKAGE_NAME} login`;
|
|
527
524
|
steps.push({
|
|
528
|
-
command:
|
|
525
|
+
command: login,
|
|
529
526
|
note: "connect your Cursor account (powers model turns)",
|
|
530
527
|
});
|
|
531
528
|
}
|
|
529
|
+
const dev = options.cliOnPath
|
|
530
|
+
? `${CLI_COMMAND_NAME} dev`
|
|
531
|
+
: `npx ${PACKAGE_NAME} dev`;
|
|
532
532
|
steps.push({
|
|
533
|
-
command:
|
|
533
|
+
command: dev,
|
|
534
534
|
note: "start the local playground",
|
|
535
535
|
});
|
|
536
536
|
return steps;
|
|
@@ -550,9 +550,9 @@ export function printInitGuide() {
|
|
|
550
550
|
process.stdout.write(`${CLI_COMMAND_NAME} — coding agent setup
|
|
551
551
|
|
|
552
552
|
Scaffold a project, then open the playground:
|
|
553
|
-
npx ${PACKAGE_NAME} init ./my-agent # installs deps +
|
|
553
|
+
npx ${PACKAGE_NAME} init ./my-agent # installs deps + links agent-sdk onto PATH
|
|
554
554
|
npx ${PACKAGE_NAME} init ./my-triage --template triage # start from a template (agent-sdk templates: triage)
|
|
555
|
-
cd ./my-agent && ${
|
|
555
|
+
cd ./my-agent && agent-sdk dev # or: npx ${PACKAGE_NAME} dev
|
|
556
556
|
|
|
557
557
|
Recommended loop once the project exists (from the project directory):
|
|
558
558
|
1. Edit agent/ + tools under agent/tools/
|