@aexhq/sdk 0.29.0 → 0.31.0

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 (90) hide show
  1. package/README.md +95 -8
  2. package/dist/_contracts/connection-ticket.d.ts +1 -1
  3. package/dist/_contracts/connection-ticket.js +1 -1
  4. package/dist/_contracts/event-envelope.d.ts +5 -8
  5. package/dist/_contracts/event-envelope.js +5 -6
  6. package/dist/_contracts/event-guards.d.ts +67 -0
  7. package/dist/_contracts/event-guards.js +36 -0
  8. package/dist/_contracts/event-stream-client.d.ts +1 -1
  9. package/dist/_contracts/http.js +1 -1
  10. package/dist/_contracts/index.d.ts +2 -0
  11. package/dist/_contracts/index.js +6 -0
  12. package/dist/_contracts/operations.d.ts +2 -47
  13. package/dist/_contracts/operations.js +7 -112
  14. package/dist/_contracts/provider-support.d.ts +48 -138
  15. package/dist/_contracts/provider-support.js +10 -41
  16. package/dist/_contracts/proxy-protocol.d.ts +7 -7
  17. package/dist/_contracts/proxy-protocol.js +8 -8
  18. package/dist/_contracts/run-config.d.ts +7 -20
  19. package/dist/_contracts/run-config.js +8 -46
  20. package/dist/_contracts/run-cost.d.ts +1 -5
  21. package/dist/_contracts/run-cost.js +0 -8
  22. package/dist/_contracts/run-custody.d.ts +4 -6
  23. package/dist/_contracts/run-custody.js +0 -8
  24. package/dist/_contracts/run-trace.d.ts +7 -0
  25. package/dist/_contracts/run-trace.js +9 -0
  26. package/dist/_contracts/run-unit.d.ts +1 -1
  27. package/dist/_contracts/run-unit.js +2 -2
  28. package/dist/_contracts/runner-event.d.ts +1 -1
  29. package/dist/_contracts/runner-event.js +1 -1
  30. package/dist/_contracts/runtime-manifest.d.ts +13 -26
  31. package/dist/_contracts/runtime-manifest.js +6 -35
  32. package/dist/_contracts/runtime-types.d.ts +32 -1
  33. package/dist/_contracts/sdk-secrets.js +4 -4
  34. package/dist/_contracts/side-effect-audit.d.ts +2 -4
  35. package/dist/_contracts/side-effect-audit.js +2 -4
  36. package/dist/_contracts/status.d.ts +1 -1
  37. package/dist/_contracts/status.js +1 -1
  38. package/dist/_contracts/submission.d.ts +19 -126
  39. package/dist/_contracts/submission.js +31 -185
  40. package/dist/_contracts/webhook-verify.d.ts +1 -1
  41. package/dist/_contracts/webhook-verify.js +1 -1
  42. package/dist/agents-md.d.ts +4 -1
  43. package/dist/agents-md.js +10 -9
  44. package/dist/agents-md.js.map +1 -1
  45. package/dist/asset-upload.d.ts +4 -10
  46. package/dist/asset-upload.js +4 -47
  47. package/dist/asset-upload.js.map +1 -1
  48. package/dist/cli.mjs +17647 -3950
  49. package/dist/cli.mjs.sha256 +1 -1
  50. package/dist/client.d.ts +79 -61
  51. package/dist/client.js +207 -125
  52. package/dist/client.js.map +1 -1
  53. package/dist/data-tools.d.ts +23 -0
  54. package/dist/data-tools.js +102 -13
  55. package/dist/data-tools.js.map +1 -1
  56. package/dist/file.d.ts +4 -1
  57. package/dist/file.js +10 -9
  58. package/dist/file.js.map +1 -1
  59. package/dist/index.d.ts +9 -8
  60. package/dist/index.js +10 -8
  61. package/dist/index.js.map +1 -1
  62. package/dist/skill.d.ts +9 -7
  63. package/dist/skill.js +15 -15
  64. package/dist/skill.js.map +1 -1
  65. package/dist/tool.d.ts +4 -1
  66. package/dist/tool.js +10 -8
  67. package/dist/tool.js.map +1 -1
  68. package/dist/version.d.ts +1 -1
  69. package/dist/version.js +1 -1
  70. package/docs/cleanup.md +2 -2
  71. package/docs/concepts/agent-tools.md +9 -5
  72. package/docs/concepts/composition.md +1 -1
  73. package/docs/concepts/providers-and-runtimes.md +2 -4
  74. package/docs/concepts/runs.md +3 -6
  75. package/docs/credentials.md +2 -5
  76. package/docs/defaults.md +22 -22
  77. package/docs/events.md +32 -9
  78. package/docs/limits-and-quotas.md +40 -40
  79. package/docs/limits.md +1 -1
  80. package/docs/networking.md +141 -0
  81. package/docs/outputs.md +1 -1
  82. package/docs/provider-runtime-capabilities.md +36 -64
  83. package/docs/public-surface.json +2 -3
  84. package/docs/quickstart.md +32 -11
  85. package/docs/run-config.md +3 -4
  86. package/docs/secrets.md +7 -5
  87. package/docs/skills.md +4 -12
  88. package/docs/vision-skills.md +1 -1
  89. package/examples/chat-corpus.ts +85 -0
  90. package/package.json +2 -2
package/README.md CHANGED
@@ -9,7 +9,7 @@ aex is an agent execution platform for launching autonomous agents from a simple
9
9
  The package ships:
10
10
 
11
11
  - `AgentExecutor` for submit, run, wait, stream, inspect, download, cancel, and delete.
12
- - Typed run primitives: `Models`, `Providers`, `Regions`, `RuntimeSizes`, `Skill`, `AgentsMd`, `File`, `McpServer`, `ProxyEndpoint`, and `Secret`.
12
+ - Typed run primitives: `Models`, `Providers`, `RuntimeSizes`, `Skill`, `AgentsMd`, `File`, `McpServer`, `ProxyEndpoint`, and `Secret`.
13
13
  - A bundled `aex` CLI with the same run, status, events, outputs, download, cancel, delete, whoami, and skills operations.
14
14
 
15
15
  ## Install
@@ -18,20 +18,40 @@ The package ships:
18
18
  bun add @aexhq/sdk
19
19
  ```
20
20
 
21
+ This installs the TypeScript SDK exports and the bundled `aex` CLI. Set both
22
+ credentials before running the examples: `AEX_API_TOKEN` authenticates to aex,
23
+ and `ANTHROPIC_API_KEY` is your BYOK provider key for Claude.
24
+
25
+ ```bash
26
+ export AEX_API_TOKEN="<your-aex-token>"
27
+ export ANTHROPIC_API_KEY="<your-anthropic-api-key>"
28
+ ```
29
+
21
30
  ## First Run
22
31
 
23
32
  ```ts
24
- import { AgentExecutor, Models, Providers } from "@aexhq/sdk";
33
+ import { AgentExecutor, Models } from "@aexhq/sdk";
34
+
35
+ const aex = new AgentExecutor({ apiToken: process.env.AEX_API_TOKEN! });
25
36
 
26
- const aex = new AgentExecutor({
27
- apiToken: process.env.AEX_API_TOKEN!
37
+ // run() submits, waits for the run to settle, and returns the result —
38
+ // no manual poll loop. `provider` is derived from the model.
39
+ const { text, ok } = await aex.run({
40
+ model: Models.CLAUDE_HAIKU_4_5,
41
+ secrets: { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } },
42
+ prompt: "Summarize this repo."
28
43
  });
29
44
 
45
+ console.log(ok, text);
46
+ ```
47
+
48
+ Need the run id, live events, or downloads? Use `submit` + `stream` + `wait`:
49
+
50
+ ```ts
30
51
  const runId = await aex.submit({
31
- provider: Providers.ANTHROPIC,
32
52
  model: Models.CLAUDE_HAIKU_4_5,
33
- prompt: "Write the report and save outputs.",
34
- secrets: { apiKey: process.env.ANTHROPIC_API_KEY! }
53
+ secrets: { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } },
54
+ prompt: "Write the report and save outputs."
35
55
  });
36
56
 
37
57
  for await (const event of aex.stream(runId)) {
@@ -44,7 +64,23 @@ console.log(run.status);
44
64
  await aex.download(runId, { to: "./run.zip" });
45
65
  ```
46
66
 
47
- The same request can run from the CLI:
67
+ For multiple providers (e.g. subagents on a different model family), include
68
+ each BYOK key in `secrets.apiKeys`:
69
+
70
+ ```ts
71
+ await aex.run({
72
+ model: Models.CLAUDE_HAIKU_4_5,
73
+ secrets: {
74
+ apiKeys: {
75
+ anthropic: process.env.ANTHROPIC_API_KEY!,
76
+ openai: process.env.OPENAI_API_KEY!
77
+ }
78
+ },
79
+ prompt: "Delegate research to a subagent."
80
+ });
81
+ ```
82
+
83
+ The same request can run from the bundled CLI:
48
84
 
49
85
  ```bash
50
86
  aex run \
@@ -55,6 +91,57 @@ aex run \
55
91
  --follow
56
92
  ```
57
93
 
94
+ ## CLI: login, discovery, typed errors
95
+
96
+ Stop re-passing `--api-token` on every command — log in once and the token (plus
97
+ your default `--aex-url`) is persisted to a `0600` config file
98
+ (`$XDG_CONFIG_HOME/aex/config.json` or `~/.config/aex/config.json`; `%APPDATA%\aex\config.json`
99
+ on Windows). An explicit `--api-token` flag always overrides the stored one.
100
+
101
+ ```bash
102
+ aex login --api-token "$AEX_API_TOKEN" [--aex-url https://api.aex.dev]
103
+ aex whoami # no --api-token needed after login
104
+ aex auth status # show the resolved config (the token value is never printed)
105
+ aex logout # clear the stored token
106
+ ```
107
+
108
+ Discover the closed sets the platform accepts — no token, no network (human table
109
+ by default, machine JSON under `--json`):
110
+
111
+ ```bash
112
+ aex models list # canonical models + their default provider
113
+ aex providers list # providers + the models each serves
114
+ aex tools list # builtin tools (default vs opt-in, e.g. notebook_edit)
115
+ aex runtime-sizes list # managed runtime presets (cpus / memory / default)
116
+ ```
117
+
118
+ Errors are typed and actionable. Every `submit()` config-validation failure throws
119
+ a `RunConfigValidationError` (`err.code === "RUN_CONFIG_INVALID"`) you can `catch`
120
+ by code; CLI failures print a JSON envelope carrying the HTTP `status`, a one-line
121
+ `remedy`, and the `runId` where known, and a wrong `--model`, `--provider`, or
122
+ `--runtime-size` gets a "did you mean?" suggestion.
123
+
124
+ ## Chat over a corpus of runs
125
+
126
+ Turn a selected set of runs into a read-only chat. `createCorpusTools(client, { runIds })`
127
+ returns vendor-neutral, corpus-scoped read tools (`list_runs` / `get_run` /
128
+ `list_outputs` / `read_output` / `search_outputs`) — every tool refuses a run
129
+ outside the corpus. Drive them with any LLM; `examples/chat-corpus.ts` shows the
130
+ direct-Claude loop (`@anthropic-ai/sdk`), and the CLI ships it as a one-shot
131
+ command (BYOK; the importable SDK stays LLM-vendor-free):
132
+
133
+ ```bash
134
+ aex chat --run run_<A> --run run_<B> \
135
+ --anthropic-api-key "$ANTHROPIC_API_KEY" \
136
+ --model claude-opus-4-8 \
137
+ --prompt "Across these runs, which produced a report.md and what's its headline finding?" \
138
+ --api-token "$AEX_API_TOKEN"
139
+ ```
140
+
141
+ `AgentExecutor.searchOutputs({ runIds, filename, extension, contentType, limit })`
142
+ finds output files across runs and returns references (no bytes) you then
143
+ `readOutputText`.
144
+
58
145
  ## Feature Areas
59
146
 
60
147
  - **Agent runtime:** managed autonomous runs with filesystem read/edit, grep/glob/head/tail, open web fetch/search defaults, optional notebook tools, and post-hook repair.
@@ -10,7 +10,7 @@
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
- * ONE implementation. Pure Web Crypto — identical under Bun, Node, and workerd.
13
+ * ONE implementation. Pure Web Crypto — identical under Bun and Node.
14
14
  */
15
15
  export type ConnectionTicketChannel = "event" | "log" | "all";
16
16
  /** Mint a `${channel}.${exp}.${mac}` ticket valid for `ttlMs` from `nowMs`. */
@@ -10,7 +10,7 @@
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
- * ONE implementation. Pure Web Crypto — identical under Bun, Node, and workerd.
13
+ * ONE implementation. Pure Web Crypto — identical under Bun and Node.
14
14
  */
15
15
  const DEFAULT_TICKET_TTL_MS = 60_000;
16
16
  const encoder = new TextEncoder();
@@ -21,7 +21,7 @@
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
24
- * on. Absent ⇒ "event" (back-compat for existing producers).
24
+ * on.
25
25
  * - `sourceSeq` — a per-SOURCE monotonic counter assigned AT the source. The
26
26
  * DO's hard guarantee is that records of the same source are
27
27
  * never reordered relative to their `sourceSeq`.
@@ -33,9 +33,8 @@
33
33
  * `sequence` on arrival, which is the canonical stream order. `sourceSeq` /
34
34
  * `emittedAt` are CARRIED through broadcast + archive, not used to reorder.
35
35
  *
36
- * This module is **additive**: it does not change {@link RunnerEvent} or any
37
- * existing wire shape. It is a pure projection plus honest guards and a strict
38
- * AG-UI projection for consumers.
36
+ * This module is a pure projection plus honest guards and a strict AG-UI
37
+ * projection for consumers.
39
38
  */
40
39
  import type { JsonValue } from "./submission.js";
41
40
  import type { RunnerEvent } from "./runner-event.js";
@@ -51,7 +50,7 @@ export declare const AEX_EVENT_MAP_VERSION: 1;
51
50
  /**
52
51
  * Coarse origin classifier — the first axis a consumer filters on.
53
52
  * - `agent` — the model: text, reasoning, builtin tool calls/results.
54
- * - `worker` — the hosted aex edge itself.
53
+ * - `api` — the hosted aex API path.
55
54
  * - `runtime` — the execution runtime: lifecycle, diagnostics, non-fatal
56
55
  * stream errors.
57
56
  * - `mcp` — an MCP server (a tool call/result routed through MCP).
@@ -60,7 +59,7 @@ export declare const AEX_EVENT_MAP_VERSION: 1;
60
59
  * - `host` — the managed host the runtime executes on; distinct from the
61
60
  * runtime process itself.
62
61
  */
63
- export declare const AEX_EVENT_SOURCES: readonly ["agent", "worker", "runtime", "mcp", "aex", "workflow", "host"];
62
+ export declare const AEX_EVENT_SOURCES: readonly ["agent", "api", "runtime", "mcp", "aex", "workflow", "host"];
64
63
  export type AexEventSource = (typeof AEX_EVENT_SOURCES)[number];
65
64
  /**
66
65
  * The channel a record rides on the unified per-run stream:
@@ -134,8 +133,6 @@ export interface AexEvent {
134
133
  * as the authoritative receive marker. It does NOT need to exceed `emittedAt`:
135
134
  * the source runs on a different host with an independent clock, so cross-host
136
135
  * 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).
139
136
  */
140
137
  readonly receivedAt?: number;
141
138
  /**
@@ -21,7 +21,7 @@
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
24
- * on. Absent ⇒ "event" (back-compat for existing producers).
24
+ * on.
25
25
  * - `sourceSeq` — a per-SOURCE monotonic counter assigned AT the source. The
26
26
  * DO's hard guarantee is that records of the same source are
27
27
  * never reordered relative to their `sourceSeq`.
@@ -33,9 +33,8 @@
33
33
  * `sequence` on arrival, which is the canonical stream order. `sourceSeq` /
34
34
  * `emittedAt` are CARRIED through broadcast + archive, not used to reorder.
35
35
  *
36
- * This module is **additive**: it does not change {@link RunnerEvent} or any
37
- * existing wire shape. It is a pure projection plus honest guards and a strict
38
- * AG-UI projection for consumers.
36
+ * This module is a pure projection plus honest guards and a strict AG-UI
37
+ * projection for consumers.
39
38
  */
40
39
  /** CloudEvents `specversion` the envelope conforms to. */
41
40
  export const AEX_EVENT_SPECVERSION = "1.0";
@@ -49,7 +48,7 @@ export const AEX_EVENT_MAP_VERSION = 1;
49
48
  /**
50
49
  * Coarse origin classifier — the first axis a consumer filters on.
51
50
  * - `agent` — the model: text, reasoning, builtin tool calls/results.
52
- * - `worker` — the hosted aex edge itself.
51
+ * - `api` — the hosted aex API path.
53
52
  * - `runtime` — the execution runtime: lifecycle, diagnostics, non-fatal
54
53
  * stream errors.
55
54
  * - `mcp` — an MCP server (a tool call/result routed through MCP).
@@ -58,7 +57,7 @@ export const AEX_EVENT_MAP_VERSION = 1;
58
57
  * - `host` — the managed host the runtime executes on; distinct from the
59
58
  * runtime process itself.
60
59
  */
61
- export const AEX_EVENT_SOURCES = ["agent", "worker", "runtime", "mcp", "aex", "workflow", "host"];
60
+ export const AEX_EVENT_SOURCES = ["agent", "api", "runtime", "mcp", "aex", "workflow", "host"];
62
61
  /**
63
62
  * The channel a record rides on the unified per-run stream:
64
63
  * - `event` — the typed, low-volume, fully-replayed AG-UI event stream.
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Type-narrowing guards over the loose {@link RunEvent} `listEvents` shape.
3
+ *
4
+ * The envelope guards in `event-envelope.ts` operate on the coordinator
5
+ * {@link import("./event-envelope.js").AexEvent} and return a plain `boolean`.
6
+ * These mirror the same AG-UI discriminants but operate on the {@link RunEvent}
7
+ * snapshot shape returned by `listEvents` / `RunResult.events` and NARROW
8
+ * `event.data` to the fields that event type carries, so a consumer reads
9
+ * `event.data.text` (etc.) without a manual cast.
10
+ *
11
+ * They are DISCRIMINANT-only at runtime (they test `event.type`), matching the
12
+ * envelope guards: the narrowed `data` shape is a typing convenience, not a deep
13
+ * runtime validation. Parse/verify the payload fields before trusting them when
14
+ * the producer is untrusted.
15
+ *
16
+ * The parameter is the minimal `{ type }` discriminant both the {@link RunEvent}
17
+ * snapshot and the coordinator `AexEvent` envelope satisfy, so the guards accept
18
+ * either shape while narrowing to the {@link RunEvent}-typed payloads.
19
+ */
20
+ import type { RunEvent } from "./runtime-types.js";
21
+ /** A `TEXT_MESSAGE_CONTENT` run event with its assistant-text payload narrowed. */
22
+ export interface TextMessageRunEvent extends RunEvent {
23
+ readonly type: "TEXT_MESSAGE_CONTENT";
24
+ readonly data: {
25
+ readonly text: string;
26
+ readonly messageId?: string;
27
+ };
28
+ }
29
+ /** A `TOOL_CALL_START` run event with the tool-call id/name/args narrowed. */
30
+ export interface ToolCallStartRunEvent extends RunEvent {
31
+ readonly type: "TOOL_CALL_START";
32
+ readonly data: {
33
+ readonly id: string;
34
+ readonly name: string;
35
+ readonly arguments?: Record<string, unknown>;
36
+ };
37
+ }
38
+ /** A `TOOL_CALL_RESULT` run event with the correlating id + result narrowed. */
39
+ export interface ToolCallResultRunEvent extends RunEvent {
40
+ readonly type: "TOOL_CALL_RESULT";
41
+ readonly data: {
42
+ readonly id: string;
43
+ readonly content?: unknown;
44
+ readonly isError?: boolean;
45
+ };
46
+ }
47
+ /** A terminal `RUN_FINISHED` run event. */
48
+ export interface RunFinishedRunEvent extends RunEvent {
49
+ readonly type: "RUN_FINISHED";
50
+ readonly data: Record<string, unknown>;
51
+ }
52
+ /** True for an assistant text event; narrows `event.data.text` to `string`. */
53
+ export declare function isTextMessage(event: {
54
+ readonly type: string;
55
+ }): event is TextMessageRunEvent;
56
+ /** True for a tool-call start event; narrows `event.data` to `{ id, name }`. */
57
+ export declare function isToolCallStart(event: {
58
+ readonly type: string;
59
+ }): event is ToolCallStartRunEvent;
60
+ /** True for a tool-call result event; narrows `event.data` to `{ id, content }`. */
61
+ export declare function isToolCallResult(event: {
62
+ readonly type: string;
63
+ }): event is ToolCallResultRunEvent;
64
+ /** True for the terminal success event; narrows `event.data` to a record. */
65
+ export declare function isRunFinished(event: {
66
+ readonly type: string;
67
+ }): event is RunFinishedRunEvent;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Type-narrowing guards over the loose {@link RunEvent} `listEvents` shape.
3
+ *
4
+ * The envelope guards in `event-envelope.ts` operate on the coordinator
5
+ * {@link import("./event-envelope.js").AexEvent} and return a plain `boolean`.
6
+ * These mirror the same AG-UI discriminants but operate on the {@link RunEvent}
7
+ * snapshot shape returned by `listEvents` / `RunResult.events` and NARROW
8
+ * `event.data` to the fields that event type carries, so a consumer reads
9
+ * `event.data.text` (etc.) without a manual cast.
10
+ *
11
+ * They are DISCRIMINANT-only at runtime (they test `event.type`), matching the
12
+ * envelope guards: the narrowed `data` shape is a typing convenience, not a deep
13
+ * runtime validation. Parse/verify the payload fields before trusting them when
14
+ * the producer is untrusted.
15
+ *
16
+ * The parameter is the minimal `{ type }` discriminant both the {@link RunEvent}
17
+ * snapshot and the coordinator `AexEvent` envelope satisfy, so the guards accept
18
+ * either shape while narrowing to the {@link RunEvent}-typed payloads.
19
+ */
20
+ /** True for an assistant text event; narrows `event.data.text` to `string`. */
21
+ export function isTextMessage(event) {
22
+ return event.type === "TEXT_MESSAGE_CONTENT";
23
+ }
24
+ /** True for a tool-call start event; narrows `event.data` to `{ id, name }`. */
25
+ export function isToolCallStart(event) {
26
+ return event.type === "TOOL_CALL_START";
27
+ }
28
+ /** True for a tool-call result event; narrows `event.data` to `{ id, content }`. */
29
+ export function isToolCallResult(event) {
30
+ return event.type === "TOOL_CALL_RESULT";
31
+ }
32
+ /** True for the terminal success event; narrows `event.data` to a record. */
33
+ export function isRunFinished(event) {
34
+ return event.type === "RUN_FINISHED";
35
+ }
36
+ //# sourceMappingURL=event-guards.js.map
@@ -65,7 +65,7 @@ export interface CoordinatorStreamOptions {
65
65
  readonly idleTimeoutMs?: number;
66
66
  /**
67
67
  * Client keep-alive ping cadence. The client sends {@link COORDINATOR_PING},
68
- * which the coordinator auto-responds to WITHOUT waking the durable object, so
68
+ * which the coordinator auto-responds to WITHOUT waking the stateful coordinator, so
69
69
  * a legitimately quiet run keeps the socket measurably alive and does not trip
70
70
  * the watchdog. Default 15s. Set 0 to disable (then only real events reset the
71
71
  * watchdog → quiet runs may reconnect).
@@ -103,7 +103,7 @@ function extractErrorMessage(body) {
103
103
  if (typeof message === "string")
104
104
  return message;
105
105
  }
106
- // aex Worker error envelope: `{ ok:false, code, message }`. Surface
106
+ // aex API error envelope: `{ ok:false, code, message }`. Surface
107
107
  // the server's message so structured rejections (e.g. runtime support)
108
108
  // aren't flattened to the generic fallback below.
109
109
  if (typeof obj.message === "string")
@@ -29,3 +29,5 @@ export * from "./run-artifacts.js";
29
29
  export * as operations from "./operations.js";
30
30
  export * from "./proxy-validation.js";
31
31
  export * from "./sse.js";
32
+ export { isRunFinished, isTextMessage, isToolCallResult, isToolCallStart } from "./event-guards.js";
33
+ export type { RunFinishedRunEvent, TextMessageRunEvent, ToolCallResultRunEvent, ToolCallStartRunEvent } from "./event-guards.js";
@@ -29,4 +29,10 @@ export * from "./run-artifacts.js";
29
29
  export * as operations from "./operations.js";
30
30
  export * from "./proxy-validation.js";
31
31
  export * from "./sse.js";
32
+ // Explicit re-export (shadows the same-named `AexEvent` guards from
33
+ // `event-envelope.js`): the public `is*` guards narrow the loose `RunEvent`
34
+ // snapshot shape `listEvents` returns. An `AexEvent` is assignable to `RunEvent`,
35
+ // so envelope consumers keep working; the envelope-typed guards stay reachable
36
+ // via the direct `event-envelope.js` module.
37
+ export { isRunFinished, isTextMessage, isToolCallResult, isToolCallStart } from "./event-guards.js";
32
38
  //# sourceMappingURL=index.js.map
@@ -132,62 +132,17 @@ export declare function downloadEvents(http: HttpClient, runId: string): Promise
132
132
  */
133
133
  export declare function downloadMetadata(http: HttpClient, runId: string): Promise<Uint8Array>;
134
134
  export declare function submitRun(http: HttpClient, request: PlatformRunSubmissionInput): Promise<Run>;
135
- /**
136
- * Multipart variant of `submitRun` for runs that carry transient
137
- * (per-run) skill bundles and/or transient AgentsMd content.
138
- *
139
- * The JSON submission travels as the `submission` part; each
140
- * `InlineSkillRef.slot` in `request.submission.skills` MUST be
141
- * mirrored by exactly one `skill:<slot>` part with the bundle bytes.
142
- * Each `InlineAgentsMdRef.slot` in `request.submission.agentsMd`
143
- * MUST be mirrored by exactly one `agentsmd:<slot>` part with the
144
- * markdown text.
145
- *
146
- * The BFF re-canonicalises and re-hashes each bundle/file; a
147
- * `contentHash` mismatch is rejected with a deterministic error.
148
- *
149
- * At least one of `bundles` or `agentsMdParts` must be non-empty.
150
- */
151
- export declare function submitRunMultipart(http: HttpClient, request: PlatformRunSubmissionInput, bundles: ReadonlyArray<{
152
- readonly slot: string;
153
- readonly bytes: Uint8Array;
154
- readonly filename: string;
155
- }>, agentsMdParts?: ReadonlyArray<{
156
- readonly slot: string;
157
- readonly content: string;
158
- readonly filename: string;
159
- }>, fileParts?: ReadonlyArray<{
160
- readonly slot: string;
161
- readonly bytes: Uint8Array;
162
- readonly filename: string;
163
- }>): Promise<Run>;
164
- /**
165
- * Upload a workspace skill bundle as a zip blob. The hosted API runs
166
- * the two-phase flow internally (insert pending row, stream bytes into
167
- * object storage, validate manifest, transition to ready) and returns
168
- * the finalized `Skill`. Use `Skill.fromPath` / `Skill.upload` in the
169
- * SDK to build the body; this transport function only knows about
170
- * bytes.
171
- */
172
- export declare function createSkillBundle(http: HttpClient, args: {
173
- readonly name: string;
174
- readonly body: Blob | ArrayBuffer | Uint8Array;
175
- readonly contentType?: string;
176
- readonly filename?: string;
177
- }): Promise<Skill>;
178
135
  /**
179
136
  * Upload a workspace skill bundle DIRECTLY to object storage via the presign
180
137
  * flow, so the bytes never transit the hosted API (bundle size bounded by the
181
- * object store, not API memory). Falls back to the buffered multipart
182
- * `createSkillBundle` when the hosted API has no object-store upload
183
- * credentials (503 `presign_unconfigured`).
138
+ * object store, not API memory). Presign errors are terminal.
184
139
  *
185
140
  * 1. POST /api/skills/presign { name, hash, sizeBytes } → { uploadUrl, requiredHeaders, skillId }
186
141
  * 2. PUT bytes → uploadUrl (signed checksum; the store rejects a mismatch)
187
142
  * 3. POST /api/skills/:id/finalize { manifest } → finalized Skill
188
143
  *
189
144
  * `manifest` is the client-computed bundle manifest (the caller already
190
- * validated the zip shape before hashing); the Worker records it on finalize
145
+ * validated the zip shape before hashing); the hosted API records it on finalize
191
146
  * without re-buffering the object.
192
147
  */
193
148
  export declare function createSkillBundleDirect(http: HttpClient, fetchImpl: (input: string, init?: RequestInit) => Promise<{
@@ -628,130 +628,25 @@ export async function submitRun(http, request) {
628
628
  body: JSON.stringify(request)
629
629
  });
630
630
  }
631
- /**
632
- * Multipart variant of `submitRun` for runs that carry transient
633
- * (per-run) skill bundles and/or transient AgentsMd content.
634
- *
635
- * The JSON submission travels as the `submission` part; each
636
- * `InlineSkillRef.slot` in `request.submission.skills` MUST be
637
- * mirrored by exactly one `skill:<slot>` part with the bundle bytes.
638
- * Each `InlineAgentsMdRef.slot` in `request.submission.agentsMd`
639
- * MUST be mirrored by exactly one `agentsmd:<slot>` part with the
640
- * markdown text.
641
- *
642
- * The BFF re-canonicalises and re-hashes each bundle/file; a
643
- * `contentHash` mismatch is rejected with a deterministic error.
644
- *
645
- * At least one of `bundles` or `agentsMdParts` must be non-empty.
646
- */
647
- export async function submitRunMultipart(http, request, bundles, agentsMdParts, fileParts) {
648
- const hasBundles = Array.isArray(bundles) && bundles.length > 0;
649
- const hasAgentsMd = Array.isArray(agentsMdParts) && agentsMdParts.length > 0;
650
- const hasFiles = Array.isArray(fileParts) && fileParts.length > 0;
651
- if (!hasBundles && !hasAgentsMd && !hasFiles) {
652
- throw new Error("submitRunMultipart: bundles, agentsMdParts, or fileParts must be non-empty");
653
- }
654
- const form = new FormData();
655
- // Submission rides as a typed JSON Blob so the BFF reads
656
- // `multipart["submission"]` with the right content-type and never
657
- // has to re-detect the body shape.
658
- form.append("submission", new Blob([JSON.stringify(request)], { type: "application/json" }), "submission.json");
659
- const seen = new Set();
660
- for (const bundle of bundles) {
661
- if (typeof bundle.slot !== "string" || !bundle.slot) {
662
- throw new Error("submitRunMultipart: each bundle must have a non-empty slot id");
663
- }
664
- if (seen.has(bundle.slot)) {
665
- throw new Error(`submitRunMultipart: duplicate inline skill slot "${bundle.slot}"`);
666
- }
667
- seen.add(bundle.slot);
668
- const blob = toBlob(bundle.bytes, "application/zip");
669
- form.append(`skill:${bundle.slot}`, blob, bundle.filename);
670
- }
671
- for (const part of agentsMdParts ?? []) {
672
- if (typeof part.slot !== "string" || !part.slot) {
673
- throw new Error("submitRunMultipart: each agentsMd part must have a non-empty slot id");
674
- }
675
- const partKey = `agentsmd:${part.slot}`;
676
- if (seen.has(partKey)) {
677
- throw new Error(`submitRunMultipart: duplicate agentsMd slot "${part.slot}"`);
678
- }
679
- seen.add(partKey);
680
- const blob = new Blob([part.content], { type: "text/plain" });
681
- form.append(partKey, blob, part.filename);
682
- }
683
- for (const part of fileParts ?? []) {
684
- if (typeof part.slot !== "string" || !part.slot) {
685
- throw new Error("submitRunMultipart: each file part must have a non-empty slot id");
686
- }
687
- const partKey = `file:${part.slot}`;
688
- if (seen.has(partKey)) {
689
- throw new Error(`submitRunMultipart: duplicate file slot "${part.slot}"`);
690
- }
691
- seen.add(partKey);
692
- const blob = toBlob(part.bytes, "application/zip");
693
- form.append(partKey, blob, part.filename);
694
- }
695
- return http.request("/api/runs", {
696
- method: "POST",
697
- body: form
698
- });
699
- }
700
- /**
701
- * Upload a workspace skill bundle as a zip blob. The hosted API runs
702
- * the two-phase flow internally (insert pending row, stream bytes into
703
- * object storage, validate manifest, transition to ready) and returns
704
- * the finalized `Skill`. Use `Skill.fromPath` / `Skill.upload` in the
705
- * SDK to build the body; this transport function only knows about
706
- * bytes.
707
- */
708
- export async function createSkillBundle(http, args) {
709
- const form = new FormData();
710
- form.append("name", args.name);
711
- const blobBody = toBlob(args.body, args.contentType ?? "application/zip");
712
- form.append("bundle", blobBody, args.filename ?? `${args.name}.zip`);
713
- const result = await http.request("/api/skills", {
714
- method: "POST",
715
- body: form
716
- });
717
- return unwrapSkill(result);
718
- }
719
631
  /**
720
632
  * Upload a workspace skill bundle DIRECTLY to object storage via the presign
721
633
  * flow, so the bytes never transit the hosted API (bundle size bounded by the
722
- * object store, not API memory). Falls back to the buffered multipart
723
- * `createSkillBundle` when the hosted API has no object-store upload
724
- * credentials (503 `presign_unconfigured`).
634
+ * object store, not API memory). Presign errors are terminal.
725
635
  *
726
636
  * 1. POST /api/skills/presign { name, hash, sizeBytes } → { uploadUrl, requiredHeaders, skillId }
727
637
  * 2. PUT bytes → uploadUrl (signed checksum; the store rejects a mismatch)
728
638
  * 3. POST /api/skills/:id/finalize { manifest } → finalized Skill
729
639
  *
730
640
  * `manifest` is the client-computed bundle manifest (the caller already
731
- * validated the zip shape before hashing); the Worker records it on finalize
641
+ * validated the zip shape before hashing); the hosted API records it on finalize
732
642
  * without re-buffering the object.
733
643
  */
734
644
  export async function createSkillBundleDirect(http, fetchImpl, args) {
735
- let presign;
736
- try {
737
- presign = await http.request("/api/skills/presign", {
738
- method: "POST",
739
- headers: { "content-type": "application/json" },
740
- body: JSON.stringify({ name: args.name, hash: args.contentHash, sizeBytes: args.body.byteLength })
741
- });
742
- }
743
- catch (err) {
744
- const status = err.status;
745
- const code = (err.details ?? {}).code;
746
- if (status === 503 && code === "presign_unconfigured") {
747
- return createSkillBundle(http, {
748
- name: args.name,
749
- body: args.body,
750
- ...(args.contentType ? { contentType: args.contentType } : {})
751
- });
752
- }
753
- throw err;
754
- }
645
+ const presign = await http.request("/api/skills/presign", {
646
+ method: "POST",
647
+ headers: { "content-type": "application/json" },
648
+ body: JSON.stringify({ name: args.name, hash: args.contentHash, sizeBytes: args.body.byteLength })
649
+ });
755
650
  const putRes = await fetchImpl(presign.uploadUrl, {
756
651
  method: "PUT",
757
652
  headers: { "content-type": args.contentType ?? "application/zip", ...(presign.requiredHeaders ?? {}) },