@aexhq/sdk 0.33.1 → 0.34.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 (76) hide show
  1. package/README.md +19 -27
  2. package/dist/_contracts/operations.d.ts +2 -54
  3. package/dist/_contracts/operations.js +2 -87
  4. package/dist/_contracts/run-config.d.ts +19 -13
  5. package/dist/_contracts/run-config.js +6 -33
  6. package/dist/_contracts/run-unit.d.ts +1 -33
  7. package/dist/_contracts/run-unit.js +2 -21
  8. package/dist/_contracts/runtime-sizes.d.ts +2 -2
  9. package/dist/_contracts/runtime-sizes.js +2 -2
  10. package/dist/_contracts/status.d.ts +2 -2
  11. package/dist/_contracts/status.js +3 -0
  12. package/dist/_contracts/submission.d.ts +22 -18
  13. package/dist/_contracts/submission.js +60 -42
  14. package/dist/agents-md.d.ts +5 -5
  15. package/dist/agents-md.js +7 -7
  16. package/dist/agents-md.js.map +1 -1
  17. package/dist/asset-upload.d.ts +4 -4
  18. package/dist/asset-upload.js +4 -4
  19. package/dist/bundle.d.ts +2 -2
  20. package/dist/bundle.js +2 -2
  21. package/dist/cli.mjs +354 -12982
  22. package/dist/cli.mjs.sha256 +1 -1
  23. package/dist/client.d.ts +218 -386
  24. package/dist/client.js +347 -645
  25. package/dist/client.js.map +1 -1
  26. package/dist/data-tools.d.ts +25 -22
  27. package/dist/data-tools.js +75 -62
  28. package/dist/data-tools.js.map +1 -1
  29. package/dist/fetch-archive.js +16 -16
  30. package/dist/fetch-archive.js.map +1 -1
  31. package/dist/file.d.ts +5 -5
  32. package/dist/file.js +7 -7
  33. package/dist/file.js.map +1 -1
  34. package/dist/index.d.ts +9 -9
  35. package/dist/index.js +14 -13
  36. package/dist/index.js.map +1 -1
  37. package/dist/mcp-server.d.ts +4 -4
  38. package/dist/mcp-server.js +4 -4
  39. package/dist/proxy-endpoint.d.ts +4 -4
  40. package/dist/proxy-endpoint.js +1 -1
  41. package/dist/secret.d.ts +8 -8
  42. package/dist/secret.js +8 -8
  43. package/dist/secret.js.map +1 -1
  44. package/dist/skill-tool.d.ts +102 -0
  45. package/dist/skill-tool.js +190 -0
  46. package/dist/skill-tool.js.map +1 -0
  47. package/dist/tool.d.ts +1 -1
  48. package/dist/tool.js +3 -3
  49. package/dist/tool.js.map +1 -1
  50. package/dist/version.d.ts +1 -1
  51. package/dist/version.js +1 -1
  52. package/docs/cleanup.md +3 -3
  53. package/docs/concepts/agent-tools.md +6 -25
  54. package/docs/concepts/composition.md +15 -12
  55. package/docs/concepts/providers-and-runtimes.md +3 -3
  56. package/docs/concepts/runs.md +27 -22
  57. package/docs/credentials.md +52 -84
  58. package/docs/defaults.md +6 -6
  59. package/docs/events.md +65 -44
  60. package/docs/limits-and-quotas.md +3 -4
  61. package/docs/mcp.md +3 -3
  62. package/docs/networking.md +8 -8
  63. package/docs/outputs.md +44 -40
  64. package/docs/provider-runtime-capabilities.md +1 -1
  65. package/docs/public-surface.json +2 -2
  66. package/docs/quickstart.md +20 -10
  67. package/docs/run-config.md +12 -14
  68. package/docs/run-record.md +8 -8
  69. package/docs/secrets.md +16 -26
  70. package/docs/skills.md +55 -110
  71. package/docs/vision-skills.md +29 -40
  72. package/examples/chat-corpus.ts +8 -9
  73. package/package.json +1 -1
  74. package/dist/skill.d.ts +0 -149
  75. package/dist/skill.js +0 -198
  76. package/dist/skill.js.map +0 -1
package/docs/outputs.md CHANGED
@@ -4,42 +4,48 @@ title: Outputs
4
4
 
5
5
  # Outputs
6
6
 
7
- Every run produces durable metadata (status, events, snapshots, cleanup state) and an outputs namespace. By default, managed runs capture every regular file the run creates or modifies in the container: the runner snapshots the filesystem just before the agent starts, rescans it when the agent exits, and uploads the delta. There is no default or official output directory. Use `outputs.allowedDirs` only when you want to narrow capture to specific roots, and `outputs.deniedDirs` to subtract noise. `aex.download(runId)` returns the public run record — metadata, typed events, and captured output bytes — as a zip; the per-namespace verbs (`downloadOutputs` / `downloadEvents` / `downloadMetadata`) return one slice each.
7
+ Every session produces durable metadata (status, events, snapshots, cleanup state) and an outputs namespace. By default, managed runs capture every regular file the agent creates or modifies in the container: the runner snapshots the filesystem just before the agent starts, rescans it when the agent exits, and uploads the delta. There is no default or official output directory. Use `outputs.allowedDirs` only when you want to narrow capture to specific roots, and `outputs.deniedDirs` to subtract noise. `session.download()` returns the public session record — metadata, typed events, and captured output bytes — as a zip; the per-namespace verbs (`session.outputs().download()` / `session.events().download()` / `session.downloadMetadata()`) return one slice each.
8
+
9
+ The output verbs below hang off the session's `outputs()` accessor
10
+ (`session.outputs().list()`, `.read()`, `.download()`, …). Reach a handle from a
11
+ live session (`openSession` / `run`) or reopen one later with
12
+ `aex.openSession(sessionId)`; the client also exposes cross-session reads under
13
+ `aex.sessions.*`.
8
14
 
9
15
  ## Quickstart
10
16
 
11
17
  ```ts
12
18
  import { Models } from "@aexhq/sdk";
13
19
 
14
- const runId = await aex.submit({
20
+ const session = await aex.openSession({
15
21
  model: Models.CLAUDE_HAIKU_4_5,
16
- prompt: "Produce a report and save it as a file.",
17
- secrets: { apiKeys: { anthropic: apiKey } }
22
+ apiKeys: { anthropic: apiKey }
18
23
  });
19
24
 
20
- await aex.wait(runId);
21
- await aex.download(runId, { to: "./run.zip" });
25
+ await session.send("Produce a report and save it as a file.").done();
26
+ await session.wait();
27
+ await session.download({ to: "./session.zip" });
22
28
  ```
23
29
 
24
30
  ```bash
25
- aex download <run-id> --out ./run.zip --api-token …
31
+ aex download <session-id> --out ./session.zip --api-token …
26
32
  ```
27
33
 
28
34
  ## The three namespaces
29
35
 
30
- A run's downloadable content is organised into three logical namespaces, each with a matching verb. Every zip is assembled **client-side** from the public read endpoints (`getRun` + `listEvents` + `listOutputs` + per-output `/download`) — there is no server-side archive route.
36
+ A session's downloadable content is organised into three logical namespaces, each with a matching verb. Every zip is assembled **client-side** from the public read endpoints (session record + `session.events().list()` + `session.outputs().list()` + per-output `/download`) — there is no server-side archive route.
31
37
 
32
38
  | Namespace | What it holds | Verb | CLI |
33
39
  | --- | --- | --- | --- |
34
- | `outputs` | The run's real deliverables. | `downloadOutputs(runId)` | `download <id> --only outputs` |
35
- | `events` | Typed event-channel records (`events.jsonl`). | `downloadEvents(runId)` | `download <id> --only events` |
36
- | `metadata` | The run record (`run.json`). | `downloadMetadata(runId)` | `download <id> --only metadata` |
40
+ | `outputs` | The session's real deliverables. | `session.outputs().download()` | `download <id> --only outputs` |
41
+ | `events` | Typed event-channel records (`events.jsonl`). | `session.events().download()` | `download <id> --only events` |
42
+ | `metadata` | The session record (`run.json`). | `session.downloadMetadata()` | `download <id> --only metadata` |
37
43
 
38
44
  Platform diagnostics are stored outside the public archive under `runs/<runId>/internal/logs/` for internal/admin access only. They are not exposed by the SDK download helpers or the public CLI.
39
45
 
40
- ## What `download()` returns
46
+ ## What `session.download()` returns
41
47
 
42
- `download(runId)` is the **whole-run** verb — it bundles the public namespaces as top-level folders. It is distinct from `downloadOutput(runId, selector)`, which fetches a single file. Layout:
48
+ `session.download()` is the **whole-session** verb — it bundles the public namespaces as top-level folders. It is distinct from `session.outputs().download(selector)`, which fetches a single file. Layout:
43
49
 
44
50
  ```
45
51
  metadata/run.json # run record (status, runId, timestamps, snapshot)
@@ -60,30 +66,29 @@ manifest.json # RunRecordManifestV1
60
66
  | `outputs[]` | `{ id, filename, sizeBytes?, contentType? }` — one row per file successfully written under `outputs/`. |
61
67
  | `errors[]` | `{ namespace, id, filename, message }` — per-artifact byte fetches that failed during assembly. Best-effort: a failure records an entry here and is skipped from the tree rather than aborting the whole zip. |
62
68
 
63
- The single-namespace verbs return the same per-file bytes at the zip root (e.g. `downloadOutputs(runId)` -> `report.txt` + a `manifest.json`; `downloadEvents(runId)` -> `events.jsonl`).
69
+ The single-namespace verbs return the same per-file bytes at the zip root (e.g. `session.outputs().download()` -> `report.txt` + a `manifest.json`; `session.events().download()` -> `events.jsonl`).
64
70
 
65
71
  ## Downloading one output
66
72
 
67
- `downloadOutput(runId, selector)` returns a `Uint8Array`. Omit the selector to download the whole outputs namespace as a zip; pass an output from `aex.outputs(runId)`, an `{ id }`, or a path selector against the listed `Output.filename` values to download one file:
73
+ `session.outputs().download(selector)` returns a `Uint8Array`. Omit the selector to download the whole outputs namespace as a zip; pass an output from `session.outputs().list()`, an `{ id }`, or a path selector against the listed `Output.filename` values to download one file:
68
74
 
69
75
  ```ts
70
- const allOutputs = await aex.downloadOutput(runId);
71
- await aex.downloadOutput(runId, undefined, { to: "./outputs.zip" });
76
+ const allOutputs = await session.outputs().download();
77
+ await session.outputs().download(undefined, { to: "./outputs.zip" });
72
78
 
73
- const report = await aex.downloadOutput(runId, { path: "reports/report.txt" });
79
+ const report = await session.outputs().download({ path: "reports/report.txt" });
74
80
  console.log(new TextDecoder().decode(report));
75
81
 
76
- const looseReport = await aex.downloadOutput(runId, { path: "report.txt", match: "suffix" });
82
+ const looseReport = await session.outputs().download({ path: "report.txt", match: "suffix" });
77
83
  console.log(looseReport.byteLength);
78
84
  ```
79
85
 
80
86
  ## Reading one output as text
81
87
 
82
- `readOutputText(runId, selector, options?)` reads ONE output file as byte-capped, decoded UTF-8 text. It streams the file and stops at `options.maxBytes` (default 50 KB, ceiling 10 MB), so a large deliverable never fully buffers — this is the read built for handing a run's output to an LLM tool. Select the file the same way as `downloadOutput`: by `{ path }` (suffix-matchable) or `{ id }`.
88
+ `session.outputs().read(selector, options?)` reads ONE output file as byte-capped, decoded UTF-8 text. It streams the file and stops at `options.maxBytes` (default 50 KB, ceiling 10 MB), so a large deliverable never fully buffers — this is the read built for handing a session's output to an LLM tool. Select the file by `{ path }` (suffix-matchable) or `{ id }`. To read from a session id without a live handle, use `aex.sessions.outputs(sessionId).read(selector, options?)` — the same accessor, addressed by id.
83
89
 
84
90
  ```ts
85
- const { text, truncated, totalBytes } = await aex.readOutputText(
86
- runId,
91
+ const { text, truncated, totalBytes } = await session.outputs().read(
87
92
  { path: "report.md", match: "suffix" },
88
93
  { maxBytes: 50_000, grep: "error" }
89
94
  );
@@ -97,25 +102,25 @@ Check `truncated` before treating `text` as complete. Pass `options.grep` (a sub
97
102
 
98
103
  ### Chatting over a workspace's outputs
99
104
 
100
- `createDataTools(client)` packages the read surface (`listRuns` + `listOutputs` + `readOutputText`) as a vendor-neutral LLM tool set (`{ tools, instructions, execute }`) so you can build a search-then-fetch chat over your runs and their outputs in a few lines on top of the public SDK. The `tools` are plain JSON-Schema definitions (the shape every major LLM tool API accepts); `execute(name, input)` dispatches a tool call against the workspace-scoped client. See the runnable `examples/data-chat/` example.
105
+ `createDataTools(client)` packages the read surface (`sessions.list` + `sessions.outputs(id).list` + `sessions.outputs(id).read`) as a vendor-neutral LLM tool set (`{ tools, instructions, execute }`) so you can build a search-then-fetch chat over your sessions and their outputs in a few lines on top of the public SDK. The `tools` are plain JSON-Schema definitions (the shape every major LLM tool API accepts); `execute(name, input)` dispatches a tool call against the workspace-scoped client. See the runnable `examples/data-chat/` example.
101
106
 
102
107
  ## Finding outputs
103
108
 
104
- `listOutputs(runId, query?)` and its alias `outputs(runId, query?)` can filter the captured output list client-side. Use `findOutputs` when you want discovery to be explicit, or `findOutput` when exactly one file is expected:
109
+ `session.outputs().list(query?)` can filter the captured output list client-side. Use `session.outputs().find(query)` when you want discovery to be explicit, or `session.outputs().findOne(query)` when exactly one file is expected:
105
110
 
106
111
  ```ts
107
- const images = await aex.findOutputs(runId, { type: "image" });
108
- const jsonReports = await aex.outputs(runId, {
112
+ const images = await session.outputs().find({ type: "image" });
113
+ const jsonReports = await session.outputs().list({
109
114
  dir: "reports",
110
115
  extension: ".json"
111
116
  });
112
117
 
113
- const report = await aex.findOutput(runId, {
118
+ const report = await session.outputs().findOne({
114
119
  filename: "summary.json",
115
120
  contentType: "application/json"
116
121
  });
117
122
  if (report) {
118
- const bytes = await aex.downloadOutput(runId, report);
123
+ const bytes = await session.outputs().download(report);
119
124
  }
120
125
  ```
121
126
 
@@ -130,15 +135,14 @@ Query fields compose with AND semantics:
130
135
  | `contentType` | Exact content type or a prefix wildcard such as `image/*`. |
131
136
  | `type` | High-level type: `text`, `json`, `image`, `audio`, `video`, `pdf`, `archive`, `binary`, or `unknown`. |
132
137
 
133
- `findOutput` returns `null` when nothing matches and throws `RunStateError` when the query matches more than one output.
138
+ `session.outputs().findOne(query)` returns `null` when nothing matches and throws `RunStateError` when the query matches more than one output.
134
139
 
135
140
  ## Temporary output links
136
141
 
137
- Use `outputLink(runId, selectorOrQuery, options?)` when another process, browser, media tag, or downloader needs a direct artifact URL instead of bytes buffered through the SDK. `createOutputLink` remains as the compatibility name.
142
+ Use `session.outputs().link(selectorOrQuery, options?)` when another process, browser, media tag, or downloader needs a direct artifact URL instead of bytes buffered through the SDK.
138
143
 
139
144
  ```ts
140
- const link = await aex.outputLink(
141
- runId,
145
+ const link = await session.outputs().link(
142
146
  { path: "reports/summary.json" },
143
147
  { expiresIn: "15m" }
144
148
  );
@@ -150,16 +154,16 @@ Selectors can be an output id, an `Output` object, a path selector, or an `Outpu
150
154
 
151
155
  The returned URL is a reusable bearer URL until it expires. Anyone who has it can read that artifact during the TTL. aex does not promise one-time use or early revocation for these direct artifact URLs.
152
156
 
153
- For large files, `fetchOutput` mints the same temporary URL and returns the `Response` from fetching it directly, without adding the SDK API token to that second request:
157
+ For large files, `session.outputs().fetch()` mints the same temporary URL and returns the `Response` from fetching it directly, without adding the SDK API token to that second request:
154
158
 
155
159
  ```ts
156
- const response = await aex.fetchOutput(runId, { type: "video", filename: /clip\.mp4$/ });
160
+ const response = await session.outputs().fetch({ type: "video", filename: /clip\.mp4$/ });
157
161
  const stream = response.body;
158
162
  ```
159
163
 
160
164
  ## Lifecycle behaviour
161
165
 
162
- `download()` works at any run state — it reads whatever the public endpoints currently expose, so the zip reflects the run as of the call:
166
+ `session.download()` works at any session state — it reads whatever the public endpoints currently expose, so the zip reflects the session as of the call:
163
167
 
164
168
  | Run state | Behaviour |
165
169
  | --- | --- |
@@ -170,8 +174,8 @@ const stream = response.body;
170
174
  ## `outputs.allowedDirs` — override capture roots
171
175
 
172
176
  ```ts
173
- aex.submit({
174
- /* ... */,
177
+ aex.openSession({
178
+ /* ... */
175
179
  outputs: {
176
180
  allowedDirs: ["/workspace/reports", "/workspace/state"]
177
181
  }
@@ -195,8 +199,8 @@ Runtime notes:
195
199
  ## `outputs.deniedDirs` — subtract noise
196
200
 
197
201
  ```ts
198
- aex.submit({
199
- /* ... */,
202
+ aex.openSession({
203
+ /* ... */
200
204
  outputs: {
201
205
  deniedDirs: ["node_modules", "/var/cache", "*.tmp"]
202
206
  }
@@ -227,7 +231,7 @@ Metadata still gets the full treatment. aex captures every regular file the run
227
231
 
228
232
  ## Mid-session download semantics
229
233
 
230
- Mid-session calls are **best-effort and side-effect-free**: they expose whatever artifacts have already been uploaded. Files written by the agent are normally uploaded near terminal, after the filesystem diff. If you need the full output set, wait for the run to reach terminal status and call `download()` again.
234
+ Mid-session calls are **best-effort and side-effect-free**: they expose whatever artifacts have already been uploaded. Files written by the agent are normally uploaded near terminal, after the filesystem diff. If you need the full output set, wait for the session to park and call `session.download()` again.
231
235
 
232
236
  ## Safety
233
237
 
@@ -40,7 +40,7 @@ All new submissions run on the managed runtime. Public support is expressed as s
40
40
 
41
41
  ## Skills
42
42
 
43
- Only asset-backed skills are accepted on submissions. Supply skill bytes through `Skill.fromFiles`, `Skill.fromPath`, `Skill.fromUrl`, or `Skill.fromCatalog`; each path normalizes to an asset that the platform snapshots into durable run asset storage.
43
+ Skills are supplied as load-tools in the `tools` array. Build one with `Tools.fromSkillDir` or `Tools.fromSkillUrl`; each normalizes to an asset that the platform snapshots into durable run asset storage.
44
44
 
45
45
  Notes:
46
46
 
@@ -2,7 +2,7 @@
2
2
  "brand": "aex",
3
3
  "productName": "Agent Executor",
4
4
  "oneLine": "aex is an agent execution platform for launching autonomous agents from a simple TypeScript SDK and CLI.",
5
- "description": "Submit typed runs, stream durable events, capture outputs, and compose agents with skills, files, MCP, proxy endpoints, and subagents across the managed runtime.",
5
+ "description": "Open durable agent sessions, send turns, stream events, capture outputs, and compose agents with skills, files, MCP, proxy endpoints, and subagents across the managed runtime.",
6
6
  "alpha": {
7
7
  "label": "Alpha testing",
8
8
  "description": "Access is limited to invited testers while we harden the hosted runtime, dashboard, and SDK workflows."
@@ -49,7 +49,7 @@
49
49
  "slug": "agent-runtime",
50
50
  "href": "/docs/features/#agent-runtime",
51
51
  "title": "Agent runtime",
52
- "description": "Managed autonomous runs with filesystem read/edit, grep/glob/head/tail, open web fetch/search defaults, and optional notebook tools."
52
+ "description": "Managed autonomous runs with filesystem read/edit, grep/glob/head/tail, open web fetch/search, background commands, code execution, git, and subagents."
53
53
  },
54
54
  {
55
55
  "slug": "durable-infrastructure",
@@ -65,26 +65,36 @@ const result = await aex.run({
65
65
  console.log(result.runId, result.status, result.text);
66
66
  ```
67
67
 
68
- ## 5. Low-level run control
68
+ ## 5. Session control: stream, wait, download
69
69
 
70
- The lower-level `submit` path remains available for explicit run-record
71
- workflows:
70
+ Sessions are the low-level API. The handle a session gives you can do everything
71
+ to itself — stream its events, wait for it to park, and download its record:
72
72
 
73
73
  ```ts
74
- const runId = await aex.submit({
74
+ const session = await aex.openSession({
75
75
  model: Models.CLAUDE_HAIKU_4_5,
76
- secrets: { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } },
77
- prompt: "Write a short report and save it as a file."
76
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
78
77
  });
79
78
 
80
- for await (const event of aex.stream(runId)) {
79
+ // A turn streams its own events; iterate them, then collect the result.
80
+ const turn = session.send("Write a short report and save it as a file.");
81
+ for await (const event of turn) {
81
82
  console.log(event.type);
82
83
  }
84
+ await turn.done();
85
+
86
+ // Reads/streams/downloads are grouped into accessor sub-resources:
87
+ // session.messages() / events() / outputs() / webhooks(). Grab the last
88
+ // assistant message (an AssistantTextEntry; use ?.text for the string).
89
+ const lastText = (await session.messages().last())?.text;
90
+ console.log(lastText);
83
91
 
84
- const run = await aex.wait(runId);
85
- console.log(run.status);
92
+ // Poll the record until the session parks (idle / suspended / error).
93
+ const record = await session.wait();
94
+ console.log(record.status);
86
95
 
87
- await aex.download(runId, { to: "./run.zip" });
96
+ // Download the whole session record (metadata, events, outputs) as a zip.
97
+ await session.download({ to: "./session.zip" });
88
98
  ```
89
99
 
90
100
  The same run from the bundled CLI:
@@ -4,28 +4,26 @@ title: Run configuration
4
4
 
5
5
  # Run configuration
6
6
 
7
- A run config is the credential-free subset of a `submit` request that you can keep in code or load from a JSON file. It is not a platform object, saved definition, DSL, trigger, or persistent agent profile. aex only stores the immutable run record created when you submit.
7
+ A run config is the credential-free subset of the session options (`openSession` / `run`) that you can keep in code or load from a JSON file. It is not a platform object, saved definition, DSL, trigger, or persistent agent profile. aex only stores the immutable session record created when the session lands.
8
8
 
9
9
  Allowed fields:
10
10
 
11
11
  - `model` - required.
12
- - `prompt` - required, string or array of strings.
13
12
  - `system` - optional system message.
14
- - `skills` - array of storage-neutral `kind:"asset"` refs. Config files cannot carry local draft bytes; use `Skill.fromPath(...)` / `Skill.fromFiles(...)` in SDK code first, or reference an existing asset/catalog skill.
15
- - `mcpServers` - array of `McpServerRef`; headers are split into `secrets.mcpServers` server-side.
16
- - `environment` - `{ networking?, packages?, envVars? }`. Networking is open by default; set `networking.mode` to `limited` only when you want an allowlist. `envVars` are merged into the in-container `RUNTIME.env` / `RUNTIME.json` mounts.
17
- - `runtimeSize` - optional managed-runtime preset. Prefer `RuntimeSizes` in TypeScript.
18
- - `timeout` - optional run deadline duration string such as `"30m"` or `"2h"`.
19
- - `proxyEndpoints` - array of `PlatformProxyEndpoint`; endpoint-level `retry` is allowed here and remains declaration-based.
13
+ - `mcpServers` - array of `McpServerRef`; headers are split into the vaulted secrets channel server-side.
14
+ - `environment` - `{ networking?, packages?, variables? }`. Networking is open by default; set `networking.mode` to `limited` only when you want an allowlist. `variables` are merged into the in-container `RUNTIME.env` / `RUNTIME.json` mounts. (Run secrets go in `environment.secrets`, which carries live `Secret` instances and is not part of a shareable config.)
15
+ - `runtime` - optional managed-runtime preset. Prefer `Sizes` in TypeScript.
16
+ - `proxyEndpoints` - array of `ProxyEndpoint` instances; endpoint-level `retry` is allowed here and remains declaration-based.
20
17
  - `metadata` - non-secret structured metadata.
18
+ - `overrides` - `{ idleTtl?, timeout?, maxSpendUsd? }`. `timeout` is an optional session deadline (e.g. `"30m"`, `"2h"`); `maxSpendUsd` stops the session once its spend would exceed the cap (see [Limits & quotas](limits-and-quotas.md)).
21
19
 
22
- `agentsMd`, `files`, `outputs`, `tools`, `includeBuiltinTools`, `limits`, and `outputMode` are top-level `submit` options, not run-config fields. They carry bytes, capture behavior, or agent tool/output controls that belong on a concrete run submission. The `limits` option sets per-run caps: the subagent-lineage caps (`maxConcurrentChildRuns`, `maxSubagentDepth`) and a USD spend cap (`maxSpendUsd`, which stops the run once its spend would exceed the cap); see [Limits & quotas](limits-and-quotas.md).
20
+ `message` (the one-shot `run` input), `agentsMd`, `files`, `outputs`, `tools`, `includeBuiltinTools`, and `outputMode` are `openSession` / `run` options, not reusable run-config fields. They carry the turn input, bytes, capture behavior, or agent tool/output controls that belong on a concrete call. Skill bundles are `tools` entries built with `Tools.fromSkillDir(...)` / `Tools.fromSkillUrl(...)`, so they too are SDK-code options rather than config fields. Subagents run in-process; there is no `limits` / `parentRunId` option.
23
21
 
24
- Secrets never live in run config. Pass credentials through `submit({ ...config, secrets })` in the SDK or the equivalent host-mode flags (`--anthropic-api-key`, `--mcp-auth`, `--proxy-auth`) in the CLI. See [Secrets](secrets.md) for secret lifecycles and [Credentials](credentials.md) for the proxy endpoint policy/auth split and retry fields.
22
+ Secrets never live in run config. Pass provider keys through the top-level `apiKeys` map (and run secrets through `environment.secrets`) in the SDK, or the equivalent host-mode flags (`--anthropic-api-key`, `--mcp-auth`, `--proxy-auth`) in the CLI. See [Secrets](secrets.md) for secret lifecycles and [Credentials](credentials.md) for the proxy endpoint policy/auth split and retry fields.
25
23
 
26
24
  ## Reuse in code
27
25
 
28
- Use an ordinary function when you want reusable typed parameters. aex does not store or execute this function; it only receives the run parameters you submit.
26
+ Use an ordinary function when you want reusable typed parameters. aex does not store or execute this function; it only receives the parameters you pass.
29
27
 
30
28
  ```ts
31
29
  import { Models } from "@aexhq/sdk";
@@ -34,13 +32,13 @@ function summarise(topic: string) {
34
32
  return {
35
33
  model: Models.CLAUDE_HAIKU_4_5,
36
34
  system: "You are a concise automation agent.",
37
- prompt: `Write a short answer about ${topic}.`
35
+ message: `Write a short answer about ${topic}.`
38
36
  };
39
37
  }
40
38
 
41
- await aex.submit({
39
+ await aex.run({
42
40
  ...summarise("agent-first SDK design"),
43
- secrets: { apiKeys: { anthropic: apiKey } }
41
+ apiKeys: { anthropic: apiKey }
44
42
  });
45
43
  ```
46
44
 
@@ -4,28 +4,28 @@ title: Run record
4
4
 
5
5
  # Run record
6
6
 
7
- The run record is the durable product primitive for one run id. It is the public-safe bundle of status metadata, the non-secret submission snapshot when available, typed events, captured outputs, and manifest entries for custody and cost telemetry.
7
+ The run record is the durable product primitive for one session. It is the public-safe bundle of status metadata, the non-secret submission snapshot when available, typed events, captured outputs, and manifest entries for custody and cost telemetry.
8
8
 
9
- ## Listing runs
9
+ ## Listing sessions
10
10
 
11
- `aex.listRuns(query?)` enumerates the runs in this workspace, most-recent first, one page at a time. The workspace is derived server-side from the API token, so this only ever returns your own runs. It is the workspace-wide discovery entry point: combine it with `listOutputs` / `readOutputText` (see [Outputs](outputs.md)) to reach any run's deliverables.
11
+ `aex.sessions.list(query?)` enumerates the sessions in this workspace, most-recent first, one page at a time. The workspace is derived server-side from the API token, so this only ever returns your own sessions. It is the workspace-wide discovery entry point: combine it with `aex.sessions.outputs(id).list()` / `.read(...)` (see [Outputs](outputs.md)) to reach any session's deliverables.
12
12
 
13
13
  ```ts
14
14
  let cursor: string | undefined;
15
15
  do {
16
- const page = await aex.listRuns({ status: "succeeded", limit: 25, cursor });
17
- for (const run of page.runs) {
18
- console.log(run.id, run.status, run.createdAt, run.costUsd);
16
+ const page = await aex.sessions.list({ status: "idle", limit: 25, cursor });
17
+ for (const session of page.sessions) {
18
+ console.log(session.id, session.status, session.createdAt, session.costUsd);
19
19
  }
20
20
  cursor = page.nextCursor;
21
21
  } while (cursor);
22
22
  ```
23
23
 
24
- `query` fields are all optional: `status` (single run status, e.g. `"succeeded"`), `since` (ISO-8601 lower bound on `createdAt`), `limit` (defaults to 25, clamped to `[1, 100]`), and `cursor` (the opaque keyset cursor from a prior page's `nextCursor` — absent on the last page). Each page row is a public-safe `RunSummary` (`id`, `status`, `createdAt`, `updatedAt`, and `costUsd` once settled); it deliberately omits the submission snapshot (model / prompt / env). Use `aex.getRun(runId)` for status / timing / cost on one run, or `aex.getRunUnit(runId)` (alias `getUnit`) for the full self-contained record including the parsed submission.
24
+ `query` fields are all optional: `status` (single session status, e.g. `"idle"`), `since` (ISO-8601 lower bound on `createdAt`), `limit` (defaults to 25, clamped to `[1, 100]`), and `cursor` (the opaque keyset cursor from a prior page's `nextCursor` — absent on the last page). Each page row is a public-safe `SessionSummary` (`id`, `status`, `createdAt`, `updatedAt`, and `costUsd` once settled); it deliberately omits the submission snapshot (model / system / env). Use `aex.sessions.get(id)` for status / timing / cost on one session, or `session.unit()` on a handle for the full self-contained record including the parsed submission.
25
25
 
26
26
  ## Downloading a run record
27
27
 
28
- `aex.download(runId)` and `aex download <run-id>` return a zip with this layout:
28
+ `session.download()` and `aex download <session-id>` return a zip with this layout:
29
29
 
30
30
  ```text
31
31
  manifest.json
package/docs/secrets.md CHANGED
@@ -16,14 +16,14 @@ provider key, such as `ANTHROPIC_API_KEY` for Claude.
16
16
  ### TypeScript
17
17
 
18
18
  ```ts
19
- import { AgentExecutor, Models } from "@aexhq/sdk";
19
+ import { Aex, Models } from "@aexhq/sdk";
20
20
 
21
- const aex = new AgentExecutor({ apiToken: process.env.AEX_API_TOKEN! });
21
+ const aex = new Aex({ apiToken: process.env.AEX_API_TOKEN! });
22
22
 
23
- await aex.submit({
23
+ await aex.run({
24
24
  model: Models.CLAUDE_HAIKU_4_5,
25
- prompt: "Write a short report and save it as a file.",
26
- secrets: { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } }
25
+ message: "Write a short report and save it as a file.",
26
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
27
27
  });
28
28
  ```
29
29
 
@@ -43,20 +43,20 @@ Use `Secret.value(...).upload(...)` when you start with an ephemeral value and
43
43
  want to persist it as a named workspace secret for later runs.
44
44
 
45
45
  ```ts
46
- import { AgentExecutor, Models, Providers, Secret } from "@aexhq/sdk";
46
+ import { Aex, Models, Providers, Secret } from "@aexhq/sdk";
47
47
 
48
- const aex = new AgentExecutor({ apiToken: process.env.AEX_API_TOKEN! });
48
+ const aex = new Aex({ apiToken: process.env.AEX_API_TOKEN! });
49
49
 
50
50
  const githubToken = await Secret.value(process.env.GITHUB_TOKEN!).upload(aex, {
51
51
  name: "github-token"
52
52
  });
53
53
 
54
- await aex.submit({
54
+ await aex.run({
55
55
  provider: Providers.ANTHROPIC,
56
56
  model: Models.CLAUDE_HAIKU_4_5,
57
- prompt: "Inspect the repository issues.",
58
- secretEnv: { GITHUB_TOKEN: githubToken },
59
- secrets: { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } }
57
+ message: "Inspect the repository issues.",
58
+ environment: { secrets: { GITHUB_TOKEN: githubToken } },
59
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
60
60
  });
61
61
  ```
62
62
 
@@ -86,16 +86,6 @@ const secrets = await aex.secrets.list();
86
86
  const metadata = await aex.secrets.get("serper-api-key");
87
87
  ```
88
88
 
89
- ## Get A Secret Value
90
-
91
- Use `get_value` only when the value is intentionally needed outside a run. It is
92
- the explicit audited value-read path.
93
-
94
- ```ts
95
- const secretValue = await aex.secrets.get_value("serper-api-key");
96
- console.log(secretValue.value);
97
- ```
98
-
99
89
  ## Inject A Workspace Secret Into A Run
100
90
 
101
91
  Reference workspace secrets with `Secret.ref(name)`. The value resolves
@@ -104,14 +94,14 @@ server-side and is injected as the named environment variable.
104
94
  ```ts
105
95
  import { Models, Providers, Secret } from "@aexhq/sdk";
106
96
 
107
- await aex.submit({
97
+ await aex.run({
108
98
  provider: Providers.ANTHROPIC,
109
99
  model: Models.CLAUDE_HAIKU_4_5,
110
- prompt: "Use SERPER_API_KEY for web search.",
111
- secretEnv: {
112
- SERPER_API_KEY: Secret.ref("serper-api-key")
100
+ message: "Use SERPER_API_KEY for web search.",
101
+ environment: {
102
+ secrets: { SERPER_API_KEY: Secret.ref("serper-api-key") }
113
103
  },
114
- secrets: { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } }
104
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
115
105
  });
116
106
  ```
117
107