@aexhq/sdk 0.13.7 → 0.13.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.
Files changed (51) hide show
  1. package/README.md +14 -14
  2. package/dist/_contracts/connection-ticket.d.ts +8 -7
  3. package/dist/_contracts/connection-ticket.js +20 -14
  4. package/dist/_contracts/event-envelope.d.ts +17 -18
  5. package/dist/_contracts/event-envelope.js +10 -11
  6. package/dist/_contracts/managed-key.d.ts +27 -1
  7. package/dist/_contracts/managed-key.js +75 -4
  8. package/dist/_contracts/operations.d.ts +9 -20
  9. package/dist/_contracts/operations.js +33 -82
  10. package/dist/_contracts/proxy-protocol.d.ts +35 -2
  11. package/dist/_contracts/proxy-protocol.js +34 -1
  12. package/dist/_contracts/run-artifacts.d.ts +12 -10
  13. package/dist/_contracts/run-artifacts.js +13 -11
  14. package/dist/_contracts/run-config.d.ts +7 -0
  15. package/dist/_contracts/run-config.js +93 -24
  16. package/dist/_contracts/run-custody.d.ts +3 -3
  17. package/dist/_contracts/run-custody.js +5 -5
  18. package/dist/_contracts/run-record.d.ts +5 -17
  19. package/dist/_contracts/run-record.js +4 -15
  20. package/dist/_contracts/run-retention.d.ts +2 -2
  21. package/dist/_contracts/run-retention.js +3 -3
  22. package/dist/_contracts/run-unit.d.ts +4 -5
  23. package/dist/_contracts/runner-event.d.ts +7 -8
  24. package/dist/_contracts/runner-event.js +7 -8
  25. package/dist/_contracts/side-effect-audit.d.ts +2 -2
  26. package/dist/_contracts/side-effect-audit.js +3 -3
  27. package/dist/_contracts/stable.d.ts +1 -1
  28. package/dist/_contracts/stable.js +1 -1
  29. package/dist/_contracts/submission.d.ts +5 -6
  30. package/dist/_contracts/submission.js +1 -1
  31. package/dist/cli.mjs +127 -127
  32. package/dist/cli.mjs.sha256 +1 -1
  33. package/dist/client.d.ts +7 -57
  34. package/dist/client.js +624 -167
  35. package/dist/client.js.map +1 -1
  36. package/dist/index.d.ts +3 -3
  37. package/dist/index.js +2 -2
  38. package/dist/index.js.map +1 -1
  39. package/dist/version.d.ts +1 -1
  40. package/dist/version.js +1 -1
  41. package/docs/cleanup.md +4 -4
  42. package/docs/credentials.md +5 -5
  43. package/docs/events.md +5 -5
  44. package/docs/outputs.md +23 -25
  45. package/docs/product-boundaries.md +5 -5
  46. package/docs/provider-runtime-capabilities.md +1 -1
  47. package/docs/quickstart.md +12 -12
  48. package/docs/run-config.md +1 -1
  49. package/docs/run-record.md +6 -9
  50. package/docs/skills.md +23 -25
  51. package/package.json +2 -2
package/README.md CHANGED
@@ -8,7 +8,7 @@ aex is a TypeScript-first SDK + CLI for running autonomous agent sessions across
8
8
 
9
9
  ```ts
10
10
  import {
11
- AexClient, // the only client class — submits durable runs to aex
11
+ AgentExecutor, // the only client class — submits durable runs to aex
12
12
  Skill, // workspace / provider / inline skill bundles
13
13
  McpServer, // MCP server declarations (headers split into secrets server-side)
14
14
  ProxyEndpoint, // per-run managed HTTP proxy endpoint
@@ -25,7 +25,7 @@ aex status <run-id> --api-token …
25
25
  aex wait <run-id> [--timeout 8m] [--interval 2s] --api-token …
26
26
  aex events <run-id> [--follow] [--timeout 8m] --api-token …
27
27
  aex outputs <run-id> --api-token …
28
- aex download <run-id> [--only outputs|logs|events|metadata] [--out path] --api-token …
28
+ aex download <run-id> [--only outputs|events|metadata] [--out path] --api-token …
29
29
  aex cancel <run-id> --api-token …
30
30
  aex delete <run-id> --api-token …
31
31
  aex whoami --api-token …
@@ -34,11 +34,11 @@ aex skills <upload|list|get|delete> [flags] --api-token …
34
34
 
35
35
  The SDK class and the CLI are backed by the same public `@aexhq/contracts` operations module — any read or write you can do through one, you can do through the other, against the same durable run records. The same npm package also ships the in-container `aex` CLI as its `bin` entry; managed runs mount that CLI inside the runner so skills can call `aex proxy …` against the per-run manifest. See [product capabilities and boundaries](docs/product-boundaries.md).
36
36
 
37
- The aex URL defaults to `https://api.aex.dev`. Set `--aex-url` on the CLI or `baseUrl` on `AexClient` for local, staging, or hosted aex API planes. This is not a supported self-host deployment claim. The workspace is derived server-side from your API token (1:1 binding), so there is no `--workspace` flag and no `workspaceId` option.
37
+ The aex URL defaults to `https://api.aex.dev`. Set `--aex-url` on the CLI or `baseUrl` on `AgentExecutor` for local, staging, or hosted aex API planes. This is not a supported self-host deployment claim. The workspace is derived server-side from your API token (1:1 binding), so there is no `--workspace` flag and no `workspaceId` option.
38
38
 
39
39
  ## Product boundaries
40
40
 
41
- - Multi-provider via Goose Managed. The published surface is the same
41
+ - Multi-provider via the managed runtime. The published surface is the same
42
42
  regardless of provider:
43
43
  - omit `runtime` or pass `runtime: "managed"`; every provider uses the
44
44
  managed runtime and BYOK provider-proxy.
@@ -54,31 +54,31 @@ The aex URL defaults to `https://api.aex.dev`. Set `--aex-url` on the CLI or `ba
54
54
  ## Quickstart (SDK)
55
55
 
56
56
  ```ts
57
- import { AexClient } from "@aexhq/sdk";
57
+ import { AgentExecutor } from "@aexhq/sdk";
58
58
 
59
- const client = new AexClient({
59
+ const aex = new AgentExecutor({
60
60
  apiToken: process.env.AEX_API_TOKEN!
61
61
  // baseUrl defaults to https://api.aex.dev - set it for local or staging planes.
62
62
  });
63
63
 
64
- const runId = await client.submitRun({
64
+ const runId = await aex.submitRun({
65
65
  model: "claude-haiku-4-5",
66
66
  system: "You are a concise automation agent.",
67
67
  prompt: "Write a short answer about agent-first SDK design.",
68
68
  secrets: { anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! } }
69
69
  });
70
70
 
71
- const run = await client.wait(runId);
71
+ const run = await aex.wait(runId);
72
72
  console.log(run.status);
73
73
 
74
- for (const output of await client.outputs(runId)) {
74
+ for (const output of await aex.outputs(runId)) {
75
75
  console.log(output.id, output.filename);
76
76
  }
77
77
 
78
- const report = await client.downloadOutput(runId, { path: "report.txt", match: "suffix" });
78
+ const report = await aex.downloadOutput(runId, { path: "report.txt", match: "suffix" });
79
79
  console.log(new TextDecoder().decode(report));
80
80
 
81
- await client.downloadOutputs(runId, { to: "./outputs.zip" });
81
+ await aex.downloadOutputs(runId, { to: "./outputs.zip" });
82
82
  ```
83
83
 
84
84
  Reusable, credential-free configs can be ordinary functions:
@@ -92,16 +92,16 @@ function summarise(topic: string) {
92
92
  };
93
93
  }
94
94
 
95
- const runId = await client.submitRun({
95
+ const runId = await aex.submitRun({
96
96
  ...summarise("agent-first SDK design"),
97
97
  secrets: { anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! } }
98
98
  });
99
99
  ```
100
100
 
101
- Stream events live with `client.stream(runId)`:
101
+ Stream events live with `aex.stream(runId)`:
102
102
 
103
103
  ```ts
104
- for await (const event of client.stream(runId)) {
104
+ for await (const event of aex.stream(runId)) {
105
105
  if (event.type === "agent.message") {
106
106
  // typed event helpers live under `aex`'s event guard exports.
107
107
  }
@@ -4,18 +4,19 @@
4
4
  * A browser/Node WebSocket handshake cannot carry an Authorization header,
5
5
  * so a subscriber first obtains a short-lived ticket from an authenticated
6
6
  * HTTP endpoint, then presents it as a `?ticket=` query parameter on the WS
7
- * upgrade. The ticket is an HMAC over `${runId}.${exp}` keyed by the
8
- * coordinator secret — it binds the grant to one run and one expiry and is
9
- * verified without any per-ticket storage.
7
+ * upgrade. The ticket is an HMAC over `${runId}.${channel}.${exp}` keyed by
8
+ * the coordinator secret — it binds the grant to one run, one stream channel,
9
+ * and one expiry and is verified without any per-ticket storage.
10
10
  *
11
11
  * This lives in shared so the coordinator (which verifies) and the API
12
12
  * hosted API's ticket broker (which mints, on behalf of a workspace token) use
13
13
  * ONE implementation. Pure Web Crypto — identical under Node and workerd.
14
14
  */
15
- /** Mint a `${exp}.${mac}` ticket valid for `ttlMs` from `nowMs`. */
16
- export declare function mintConnectionTicket(runId: string, secret: string, nowMs: number, ttlMs?: number): Promise<{
15
+ export type ConnectionTicketChannel = "event" | "log" | "all";
16
+ /** Mint a `${channel}.${exp}.${mac}` ticket valid for `ttlMs` from `nowMs`. */
17
+ export declare function mintConnectionTicket(runId: string, secret: string, nowMs: number, ttlMs?: number, channel?: ConnectionTicketChannel): Promise<{
17
18
  ticket: string;
18
19
  expiresAtMs: number;
19
20
  }>;
20
- /** Verify a ticket against `runId` + the current time. Constant-time MAC compare. */
21
- export declare function verifyConnectionTicket(ticket: string, runId: string, secret: string, nowMs: number): Promise<boolean>;
21
+ /** Verify a ticket against `runId`, channel, and current time. Constant-time MAC compare. */
22
+ export declare function verifyConnectionTicket(ticket: string, runId: string, secret: string, nowMs: number, channel?: ConnectionTicketChannel): Promise<boolean>;
@@ -4,9 +4,9 @@
4
4
  * A browser/Node WebSocket handshake cannot carry an Authorization header,
5
5
  * so a subscriber first obtains a short-lived ticket from an authenticated
6
6
  * HTTP endpoint, then presents it as a `?ticket=` query parameter on the WS
7
- * upgrade. The ticket is an HMAC over `${runId}.${exp}` keyed by the
8
- * coordinator secret — it binds the grant to one run and one expiry and is
9
- * verified without any per-ticket storage.
7
+ * upgrade. The ticket is an HMAC over `${runId}.${channel}.${exp}` keyed by
8
+ * the coordinator secret — it binds the grant to one run, one stream channel,
9
+ * and one expiry and is verified without any per-ticket storage.
10
10
  *
11
11
  * This lives in shared so the coordinator (which verifies) and the API
12
12
  * hosted API's ticket broker (which mints, on behalf of a workspace token) use
@@ -14,27 +14,33 @@
14
14
  */
15
15
  const DEFAULT_TICKET_TTL_MS = 60_000;
16
16
  const encoder = new TextEncoder();
17
+ function normalizeTicketChannel(channel) {
18
+ return channel === "log" || channel === "all" ? channel : "event";
19
+ }
17
20
  async function hmacHex(secret, message) {
18
21
  const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
19
22
  const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(message));
20
23
  return [...new Uint8Array(sig)].map((b) => b.toString(16).padStart(2, "0")).join("");
21
24
  }
22
- /** Mint a `${exp}.${mac}` ticket valid for `ttlMs` from `nowMs`. */
23
- export async function mintConnectionTicket(runId, secret, nowMs, ttlMs = DEFAULT_TICKET_TTL_MS) {
25
+ /** Mint a `${channel}.${exp}.${mac}` ticket valid for `ttlMs` from `nowMs`. */
26
+ export async function mintConnectionTicket(runId, secret, nowMs, ttlMs = DEFAULT_TICKET_TTL_MS, channel = "event") {
27
+ const boundChannel = normalizeTicketChannel(channel);
24
28
  const exp = nowMs + ttlMs;
25
- const mac = await hmacHex(secret, `${runId}.${exp}`);
26
- return { ticket: `${exp}.${mac}`, expiresAtMs: exp };
29
+ const mac = await hmacHex(secret, `${runId}.${boundChannel}.${exp}`);
30
+ return { ticket: `${boundChannel}.${exp}.${mac}`, expiresAtMs: exp };
27
31
  }
28
- /** Verify a ticket against `runId` + the current time. Constant-time MAC compare. */
29
- export async function verifyConnectionTicket(ticket, runId, secret, nowMs) {
30
- const dot = ticket.indexOf(".");
31
- if (dot < 0)
32
+ /** Verify a ticket against `runId`, channel, and current time. Constant-time MAC compare. */
33
+ export async function verifyConnectionTicket(ticket, runId, secret, nowMs, channel = "event") {
34
+ const [ticketChannel, expRaw, mac, ...rest] = ticket.split(".");
35
+ if (rest.length > 0 || !ticketChannel || !expRaw || !mac)
36
+ return false;
37
+ const boundChannel = normalizeTicketChannel(channel);
38
+ if (ticketChannel !== boundChannel)
32
39
  return false;
33
- const exp = Number(ticket.slice(0, dot));
34
- const mac = ticket.slice(dot + 1);
40
+ const exp = Number(expRaw);
35
41
  if (!Number.isFinite(exp) || exp < nowMs)
36
42
  return false;
37
- const expected = await hmacHex(secret, `${runId}.${exp}`);
43
+ const expected = await hmacHex(secret, `${runId}.${boundChannel}.${exp}`);
38
44
  return timingSafeEqual(mac, expected);
39
45
  }
40
46
  /** Length-then-constant-time comparison of two hex strings. */
@@ -17,7 +17,7 @@
17
17
  *
18
18
  * Unified observability spine:
19
19
  * the envelope additionally carries four ordering attributes so BOTH the typed
20
- * event stream and the high-volume hosted runtime log stream ride one per-run
20
+ * event stream and the high-volume hosted-platform log stream ride one per-run
21
21
  * coordinator:
22
22
  * - `channel` — "event" (the typed AG-UI stream) or "log" (a verbose log
23
23
  * line). The single axis a consumer splits the unified stream
@@ -52,24 +52,23 @@ export declare const AEX_EVENT_MAP_VERSION: 1;
52
52
  * Coarse origin classifier — the first axis a consumer filters on.
53
53
  * - `agent` — the model: text, reasoning, builtin tool calls/results.
54
54
  * - `worker` — the hosted aex edge itself.
55
- * - `runtime` — the execution runtime (Goose container / Anthropic session):
56
- * lifecycle, diagnostics, non-fatal stream errors.
55
+ * - `runtime` — the execution runtime: lifecycle, diagnostics, non-fatal
56
+ * stream errors.
57
57
  * - `mcp` — an MCP server (a tool call/result routed through MCP).
58
58
  * - `aex` — the platform: skills, files, and other aex-native events.
59
- * - `workflow`— the orchestration layer (Cloudflare Workflows trace).
60
- * - `machine` — the managed host the runtime executes on (machine-level host
61
- * logs). A forthcoming source; `runtime` stays the
62
- * Goose-container / Anthropic-session source, distinct from the
63
- * host machine that carries it.
59
+ * - `workflow`— the orchestration layer.
60
+ * - `host` — the managed host the runtime executes on; distinct from the
61
+ * runtime process itself.
64
62
  */
65
- export declare const AEX_EVENT_SOURCES: readonly ["agent", "worker", "runtime", "mcp", "aex", "workflow", "machine"];
63
+ export declare const AEX_EVENT_SOURCES: readonly ["agent", "worker", "runtime", "mcp", "aex", "workflow", "host"];
66
64
  export type AexEventSource = (typeof AEX_EVENT_SOURCES)[number];
67
65
  /**
68
66
  * The channel a record rides on the unified per-run stream:
69
67
  * - `event` — the typed, low-volume, fully-replayed AG-UI event stream.
70
68
  * - `log` — a high-volume verbose log line (level + message + fields). The
71
- * coordinator prunes flushed log rows after R2 archival (logs are
72
- * append-only, events are kept). Absent on the wire ⇒ `event`.
69
+ * coordinator prunes flushed log rows after evidence archival
70
+ * (logs are append-only, events are kept). Absent on the wire ⇒
71
+ * `event`.
73
72
  */
74
73
  export declare const AEX_EVENT_CHANNELS: readonly ["event", "log"];
75
74
  export type AexEventChannel = (typeof AEX_EVENT_CHANNELS)[number];
@@ -130,13 +129,13 @@ export interface AexEvent {
130
129
  * companion to `sequence` — distinct from `emittedAt` (the SOURCE's clock) and
131
130
  * `time` (the LOGICAL time = run base + relative tMs).
132
131
  *
133
- * NOTE: a Workers clock is coarsened/frozen-at-I/O (a side-channel
134
- * mitigation), so `receivedAt` is precisely "the DO's last-I/O wall-clock at
135
- * ingest" — that is fine as the authoritative receive marker. It does NOT need
136
- * to exceed `emittedAt`: the source runs on a different machine with an
137
- * independent clock, so cross-machine drift can leave `receivedAt < emittedAt`
138
- * and that is expected, not an error. Absent on records produced before this
139
- * field existed (back-compat with archived records).
132
+ * NOTE: some edge clocks are coarsened/frozen-at-I/O, so `receivedAt` is
133
+ * precisely "the coordinator's last-I/O wall-clock at ingest" — that is fine
134
+ * as the authoritative receive marker. It does NOT need to exceed `emittedAt`:
135
+ * the source runs on a different host with an independent clock, so cross-host
136
+ * drift can leave `receivedAt < emittedAt` and that is expected, not an error.
137
+ * Absent on records produced before this field existed (back-compat with
138
+ * archived records).
140
139
  */
141
140
  readonly receivedAt?: number;
142
141
  /**
@@ -17,7 +17,7 @@
17
17
  *
18
18
  * Unified observability spine:
19
19
  * the envelope additionally carries four ordering attributes so BOTH the typed
20
- * event stream and the high-volume hosted runtime log stream ride one per-run
20
+ * event stream and the high-volume hosted-platform log stream ride one per-run
21
21
  * coordinator:
22
22
  * - `channel` — "event" (the typed AG-UI stream) or "log" (a verbose log
23
23
  * line). The single axis a consumer splits the unified stream
@@ -50,23 +50,22 @@ export const AEX_EVENT_MAP_VERSION = 1;
50
50
  * Coarse origin classifier — the first axis a consumer filters on.
51
51
  * - `agent` — the model: text, reasoning, builtin tool calls/results.
52
52
  * - `worker` — the hosted aex edge itself.
53
- * - `runtime` — the execution runtime (Goose container / Anthropic session):
54
- * lifecycle, diagnostics, non-fatal stream errors.
53
+ * - `runtime` — the execution runtime: lifecycle, diagnostics, non-fatal
54
+ * stream errors.
55
55
  * - `mcp` — an MCP server (a tool call/result routed through MCP).
56
56
  * - `aex` — the platform: skills, files, and other aex-native events.
57
- * - `workflow`— the orchestration layer (Cloudflare Workflows trace).
58
- * - `machine` — the managed host the runtime executes on (machine-level host
59
- * logs). A forthcoming source; `runtime` stays the
60
- * Goose-container / Anthropic-session source, distinct from the
61
- * host machine that carries it.
57
+ * - `workflow`— the orchestration layer.
58
+ * - `host` — the managed host the runtime executes on; distinct from the
59
+ * runtime process itself.
62
60
  */
63
- export const AEX_EVENT_SOURCES = ["agent", "worker", "runtime", "mcp", "aex", "workflow", "machine"];
61
+ export const AEX_EVENT_SOURCES = ["agent", "worker", "runtime", "mcp", "aex", "workflow", "host"];
64
62
  /**
65
63
  * The channel a record rides on the unified per-run stream:
66
64
  * - `event` — the typed, low-volume, fully-replayed AG-UI event stream.
67
65
  * - `log` — a high-volume verbose log line (level + message + fields). The
68
- * coordinator prunes flushed log rows after R2 archival (logs are
69
- * append-only, events are kept). Absent on the wire ⇒ `event`.
66
+ * coordinator prunes flushed log rows after evidence archival
67
+ * (logs are append-only, events are kept). Absent on the wire ⇒
68
+ * `event`.
70
69
  */
71
70
  export const AEX_EVENT_CHANNELS = ["event", "log"];
72
71
  /**
@@ -3,10 +3,13 @@ export declare const CREDENTIAL_MODES: readonly ["byok", "managed"];
3
3
  export type CredentialMode = (typeof CREDENTIAL_MODES)[number];
4
4
  export declare const DEFAULT_CREDENTIAL_MODE: CredentialMode;
5
5
  export declare const MANAGED_KEY_POLICY_SCHEMA_VERSION = 1;
6
+ export declare const MANAGED_KEY_RESERVATION_SCHEMA_VERSION = 1;
6
7
  export declare const MANAGED_KEY_LAUNCH_STAGES: readonly ["blocked", "pilot", "ga"];
7
8
  export type ManagedKeyLaunchStage = (typeof MANAGED_KEY_LAUNCH_STAGES)[number];
8
9
  export declare const MANAGED_KEY_FEATURE_DECISIONS: readonly ["disabled", "allowed"];
9
10
  export type ManagedKeyFeatureDecision = (typeof MANAGED_KEY_FEATURE_DECISIONS)[number];
11
+ export declare const MANAGED_KEY_RESERVATION_STATUSES: readonly ["open", "settled", "released"];
12
+ export type ManagedKeyReservationStatus = (typeof MANAGED_KEY_RESERVATION_STATUSES)[number];
10
13
  export interface ManagedKeyFeaturePolicyV1 {
11
14
  readonly files: ManagedKeyFeatureDecision;
12
15
  readonly packages: ManagedKeyFeatureDecision;
@@ -24,13 +27,35 @@ export interface ManagedKeyPolicyV1 {
24
27
  readonly schemaVersion: typeof MANAGED_KEY_POLICY_SCHEMA_VERSION;
25
28
  readonly credentialMode: "managed";
26
29
  readonly launchStage: ManagedKeyLaunchStage;
27
- readonly serviceAvailable: boolean;
30
+ readonly privateImplementationAvailable: boolean;
28
31
  readonly billingRequired: true;
29
32
  readonly providers: readonly RunProvider[];
30
33
  readonly runtimes: readonly RuntimeKind[];
31
34
  readonly models?: readonly string[];
32
35
  readonly features: ManagedKeyFeaturePolicyV1;
33
36
  }
37
+ /**
38
+ * Public-safe reservation lifecycle summary. It intentionally carries only
39
+ * credit-unit invariants and public row identifiers; private key handles,
40
+ * account selection, rate cards, margins, and payment-provider references
41
+ * remain outside this contract.
42
+ */
43
+ export interface ManagedKeyReservationLifecycleV1 {
44
+ readonly schemaVersion: typeof MANAGED_KEY_RESERVATION_SCHEMA_VERSION;
45
+ readonly reservationId: string;
46
+ readonly workspaceId: string;
47
+ readonly runId: string;
48
+ readonly credentialMode: "managed";
49
+ readonly status: ManagedKeyReservationStatus;
50
+ readonly reservedCreditUnits: number;
51
+ readonly chargedCreditUnits: number;
52
+ readonly releasedCreditUnits: number;
53
+ readonly createdAt?: string;
54
+ readonly closedAt?: string;
55
+ }
56
+ export type ManagedKeyReservationLifecycleInput = Omit<ManagedKeyReservationLifecycleV1, "schemaVersion" | "credentialMode"> & {
57
+ readonly credentialMode?: "managed";
58
+ };
34
59
  export declare const BLOCKED_MANAGED_KEY_FEATURE_POLICY_V1: ManagedKeyFeaturePolicyV1;
35
60
  export declare const BLOCKED_MANAGED_KEY_POLICY_V1: ManagedKeyPolicyV1;
36
61
  export declare class ManagedKeyUnavailableError extends Error {
@@ -40,6 +65,7 @@ export declare class ManagedKeyUnavailableError extends Error {
40
65
  export declare function parseCredentialMode(input: unknown): CredentialMode;
41
66
  export declare function credentialModeOrDefault(input: CredentialMode | undefined): CredentialMode;
42
67
  export declare function isCredentialMode(input: unknown): input is CredentialMode;
68
+ export declare function buildManagedKeyReservationLifecycle(input: ManagedKeyReservationLifecycleInput): ManagedKeyReservationLifecycleV1;
43
69
  export declare function isManagedKeyGenerallyAvailable(policy: ManagedKeyPolicyV1): boolean;
44
70
  export declare function isManagedKeyAdmissionAllowed(policy: ManagedKeyPolicyV1): boolean;
45
71
  export declare function assertManagedKeyModeAvailable(policy?: ManagedKeyPolicyV1): void;
@@ -1,8 +1,10 @@
1
1
  export const CREDENTIAL_MODES = ["byok", "managed"];
2
2
  export const DEFAULT_CREDENTIAL_MODE = "byok";
3
3
  export const MANAGED_KEY_POLICY_SCHEMA_VERSION = 1;
4
+ export const MANAGED_KEY_RESERVATION_SCHEMA_VERSION = 1;
4
5
  export const MANAGED_KEY_LAUNCH_STAGES = ["blocked", "pilot", "ga"];
5
6
  export const MANAGED_KEY_FEATURE_DECISIONS = ["disabled", "allowed"];
7
+ export const MANAGED_KEY_RESERVATION_STATUSES = ["open", "settled", "released"];
6
8
  export const BLOCKED_MANAGED_KEY_FEATURE_POLICY_V1 = Object.freeze({
7
9
  files: "disabled",
8
10
  packages: "disabled",
@@ -15,7 +17,7 @@ export const BLOCKED_MANAGED_KEY_POLICY_V1 = Object.freeze({
15
17
  schemaVersion: MANAGED_KEY_POLICY_SCHEMA_VERSION,
16
18
  credentialMode: "managed",
17
19
  launchStage: "blocked",
18
- serviceAvailable: false,
20
+ privateImplementationAvailable: false,
19
21
  billingRequired: true,
20
22
  providers: Object.freeze([]),
21
23
  runtimes: Object.freeze([]),
@@ -23,7 +25,7 @@ export const BLOCKED_MANAGED_KEY_POLICY_V1 = Object.freeze({
23
25
  });
24
26
  export class ManagedKeyUnavailableError extends Error {
25
27
  code = "managed_key_unavailable";
26
- constructor(message = "credentialMode: \"managed\" is not available") {
28
+ constructor(message = "credentialMode: \"managed\" is not available without a private managed-key implementation") {
27
29
  super(message);
28
30
  this.name = "ManagedKeyUnavailableError";
29
31
  }
@@ -43,11 +45,58 @@ export function credentialModeOrDefault(input) {
43
45
  export function isCredentialMode(input) {
44
46
  return typeof input === "string" && CREDENTIAL_MODES.includes(input);
45
47
  }
48
+ export function buildManagedKeyReservationLifecycle(input) {
49
+ const status = normalizeManagedKeyReservationStatus(input.status);
50
+ const reservedCreditUnits = nonNegativeFinite(input.reservedCreditUnits, "reservedCreditUnits");
51
+ const chargedCreditUnits = nonNegativeFinite(input.chargedCreditUnits, "chargedCreditUnits");
52
+ const releasedCreditUnits = nonNegativeFinite(input.releasedCreditUnits, "releasedCreditUnits");
53
+ if (input.credentialMode !== undefined && input.credentialMode !== "managed") {
54
+ throw new Error("managed-key reservation credentialMode must be managed");
55
+ }
56
+ if (status === "open") {
57
+ if (input.closedAt !== undefined) {
58
+ throw new Error("managed-key open reservation must not have closedAt");
59
+ }
60
+ if (chargedCreditUnits !== 0 || releasedCreditUnits !== 0) {
61
+ throw new Error("managed-key open reservation cannot have charged or released credit units");
62
+ }
63
+ }
64
+ if (status === "settled") {
65
+ if (!input.closedAt) {
66
+ throw new Error("managed-key settled reservation requires closedAt");
67
+ }
68
+ const expectedReleased = Math.max(0, reservedCreditUnits - chargedCreditUnits);
69
+ if (!nearlyEqual(releasedCreditUnits, expectedReleased)) {
70
+ throw new Error("managed-key settlement releasedCreditUnits must equal max(reserved - charged, 0)");
71
+ }
72
+ }
73
+ if (status === "released") {
74
+ if (!input.closedAt) {
75
+ throw new Error("managed-key released reservation requires closedAt");
76
+ }
77
+ if (chargedCreditUnits !== 0 || !nearlyEqual(releasedCreditUnits, reservedCreditUnits)) {
78
+ throw new Error("managed-key released reservation must release all reserved credit units without charge");
79
+ }
80
+ }
81
+ return Object.freeze({
82
+ schemaVersion: MANAGED_KEY_RESERVATION_SCHEMA_VERSION,
83
+ reservationId: nonEmptyString(input.reservationId, "reservationId"),
84
+ workspaceId: nonEmptyString(input.workspaceId, "workspaceId"),
85
+ runId: nonEmptyString(input.runId, "runId"),
86
+ credentialMode: "managed",
87
+ status,
88
+ reservedCreditUnits,
89
+ chargedCreditUnits,
90
+ releasedCreditUnits,
91
+ ...(input.createdAt ? { createdAt: input.createdAt } : {}),
92
+ ...(input.closedAt ? { closedAt: input.closedAt } : {})
93
+ });
94
+ }
46
95
  export function isManagedKeyGenerallyAvailable(policy) {
47
- return policy.launchStage === "ga" && policy.serviceAvailable;
96
+ return policy.launchStage === "ga" && policy.privateImplementationAvailable;
48
97
  }
49
98
  export function isManagedKeyAdmissionAllowed(policy) {
50
- return policy.launchStage !== "blocked" && policy.serviceAvailable;
99
+ return policy.launchStage !== "blocked" && policy.privateImplementationAvailable;
51
100
  }
52
101
  export function assertManagedKeyModeAvailable(policy = BLOCKED_MANAGED_KEY_POLICY_V1) {
53
102
  if (!isManagedKeyGenerallyAvailable(policy)) {
@@ -107,4 +156,26 @@ function resolvePolicyDenial(input) {
107
156
  }
108
157
  return null;
109
158
  }
159
+ function normalizeManagedKeyReservationStatus(input) {
160
+ if (typeof input !== "string" ||
161
+ !MANAGED_KEY_RESERVATION_STATUSES.includes(input)) {
162
+ throw new Error(`managed-key reservation status ${String(input)} is not supported`);
163
+ }
164
+ return input;
165
+ }
166
+ function nonEmptyString(value, field) {
167
+ if (typeof value !== "string" || value.trim().length === 0) {
168
+ throw new Error(`managed-key reservation ${field} must be a non-empty string`);
169
+ }
170
+ return value;
171
+ }
172
+ function nonNegativeFinite(value, field) {
173
+ if (!Number.isFinite(value) || value < 0) {
174
+ throw new Error(`managed-key reservation ${field} must be a non-negative finite number`);
175
+ }
176
+ return value;
177
+ }
178
+ function nearlyEqual(left, right) {
179
+ return Math.abs(left - right) <= 1e-9;
180
+ }
110
181
  //# sourceMappingURL=managed-key.js.map
@@ -27,9 +27,13 @@ export declare function getRun(http: HttpClient, runId: string): Promise<Run>;
27
27
  * stays for callers that only need the loose record.
28
28
  */
29
29
  export declare function getRunUnit(http: HttpClient, runId: string): Promise<RunUnit>;
30
- export declare function listRunEvents(http: HttpClient, runId: string, options?: {
31
- readonly channel?: "event" | "log" | "all";
32
- }): Promise<readonly RunEvent[]>;
30
+ /**
31
+ * List a run's events. The read endpoint is PAGED (bounded per response so a
32
+ * long run can't return an unbounded body); this follows `nextCursor` across
33
+ * pages and returns the FULL accumulated list, preserving the prior single-call
34
+ * contract for callers (download/*, CLI, streamEvents polling).
35
+ */
36
+ export declare function listRunEvents(http: HttpClient, runId: string): Promise<readonly RunEvent[]>;
33
37
  /** A coordinator WS connection grant minted by the hosted API's ticket broker. */
34
38
  export interface CoordinatorTicket {
35
39
  readonly wsUrl: string;
@@ -44,11 +48,6 @@ export interface CoordinatorTicket {
44
48
  */
45
49
  export declare function getCoordinatorTicket(http: HttpClient, runId: string): Promise<CoordinatorTicket>;
46
50
  export declare function listOutputs(http: HttpClient, runId: string): Promise<readonly Output[]>;
47
- /**
48
- * List the run's platform diagnostics (the `logs` namespace). Legacy stored
49
- * filenames are normalized to canonical public namespaces.
50
- */
51
- export declare function listLogs(http: HttpClient, runId: string): Promise<readonly Output[]>;
52
51
  export declare function createOutputLink(http: HttpClient, runId: string, outputId: string): Promise<SignedOutputLink>;
53
52
  export declare function resolveOutputFileSelector(outputs: readonly Output[], selector: OutputFileSelector, runId?: string): Output;
54
53
  export declare function downloadOutput(http: HttpClient, runId: string, selector: OutputFileSelector): Promise<OutputFileDownload>;
@@ -63,15 +62,12 @@ export declare function deleteRun(http: HttpClient, runId: string): Promise<void
63
62
  export declare function deleteWorkspaceAsset(http: HttpClient, hash: string): Promise<void>;
64
63
  export declare function whoami(http: HttpClient): Promise<WhoAmI>;
65
64
  /**
66
- * Download EVERYTHING about a run as one zip, organised into the four
65
+ * Download EVERYTHING public about a run as one zip, organised into the three
67
66
  * namespace folders:
68
67
  *
69
68
  * metadata/run.json — the run record.
70
69
  * events/events.jsonl — typed event-channel records.
71
- * events/logs.jsonl — log-channel records, when the API serves them.
72
- * events/all.jsonl — full unified stream, when the API serves it.
73
70
  * outputs/<rel> — the run's deliverables.
74
- * logs/<rel> — platform diagnostics.
75
71
  * manifest.json — `RunRecordManifestV1`.
76
72
  */
77
73
  export declare function download(http: HttpClient, runId: string): Promise<Uint8Array>;
@@ -81,16 +77,9 @@ export declare function download(http: HttpClient, runId: string): Promise<Uint8
81
77
  * (`{ runId, namespace: "outputs", outputs[], errors[] }`).
82
78
  */
83
79
  export declare function downloadOutputs(http: HttpClient, runId: string): Promise<Uint8Array>;
84
- /**
85
- * Download only the platform diagnostics (the `logs` namespace). Zip
86
- * layout: `<rel>` per file plus a `manifest.json`
87
- * (`{ runId, namespace: "logs", logs[], errors[] }`).
88
- */
89
- export declare function downloadLogs(http: HttpClient, runId: string): Promise<Uint8Array>;
90
80
  /**
91
81
  * Download only the event archive (the `events` namespace). Always includes
92
- * typed `events.jsonl`; includes `logs.jsonl` / `all.jsonl` when the deployed
93
- * event API proves those channel exports are available.
82
+ * typed `events.jsonl`.
94
83
  */
95
84
  export declare function downloadEvents(http: HttpClient, runId: string): Promise<Uint8Array>;
96
85
  /**