@aexhq/sdk 0.35.0 → 0.37.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 (72) hide show
  1. package/README.md +17 -16
  2. package/dist/_contracts/event-envelope.d.ts +22 -1
  3. package/dist/_contracts/event-envelope.js +26 -2
  4. package/dist/_contracts/event-stream-client.js +7 -1
  5. package/dist/_contracts/index.d.ts +3 -4
  6. package/dist/_contracts/index.js +1 -4
  7. package/dist/_contracts/operations.d.ts +31 -1
  8. package/dist/_contracts/operations.js +64 -1
  9. package/dist/_contracts/run-config.d.ts +2 -4
  10. package/dist/_contracts/run-config.js +2 -7
  11. package/dist/_contracts/run-trace.d.ts +0 -86
  12. package/dist/_contracts/run-trace.js +1 -184
  13. package/dist/_contracts/run-unit.d.ts +14 -25
  14. package/dist/_contracts/run-unit.js +56 -2
  15. package/dist/_contracts/runtime-manifest.d.ts +1 -1
  16. package/dist/_contracts/runtime-security-profile.d.ts +0 -2
  17. package/dist/_contracts/runtime-security-profile.js +0 -9
  18. package/dist/_contracts/runtime-sizes.d.ts +2 -2
  19. package/dist/_contracts/runtime-sizes.js +5 -5
  20. package/dist/_contracts/runtime-types.d.ts +123 -4
  21. package/dist/_contracts/stable.d.ts +1 -1
  22. package/dist/_contracts/stable.js +1 -1
  23. package/dist/_contracts/submission.d.ts +8 -76
  24. package/dist/_contracts/submission.js +5 -472
  25. package/dist/cli.mjs +574 -511
  26. package/dist/cli.mjs.sha256 +1 -1
  27. package/dist/client.d.ts +69 -25
  28. package/dist/client.js +338 -68
  29. package/dist/client.js.map +1 -1
  30. package/dist/index.d.ts +8 -16
  31. package/dist/index.js +5 -17
  32. package/dist/index.js.map +1 -1
  33. package/dist/secret.d.ts +2 -2
  34. package/dist/secret.js +1 -1
  35. package/dist/version.d.ts +1 -1
  36. package/dist/version.js +1 -1
  37. package/docs/authentication.md +92 -0
  38. package/docs/billing.md +112 -0
  39. package/docs/concepts/agent-tools.md +4 -4
  40. package/docs/concepts/composition.md +8 -14
  41. package/docs/concepts/providers-and-runtimes.md +4 -1
  42. package/docs/concepts/runs.md +2 -1
  43. package/docs/concepts/subagents.md +85 -0
  44. package/docs/credentials.md +78 -96
  45. package/docs/defaults.md +9 -15
  46. package/docs/errors.md +132 -0
  47. package/docs/events.md +44 -32
  48. package/docs/limits-and-quotas.md +30 -17
  49. package/docs/limits.md +4 -8
  50. package/docs/mcp.md +5 -6
  51. package/docs/networking.md +75 -59
  52. package/docs/outputs.md +4 -7
  53. package/docs/public-surface.json +4 -4
  54. package/docs/quickstart.md +12 -13
  55. package/docs/run-config.md +7 -4
  56. package/docs/secrets.md +6 -1
  57. package/docs/skills.md +3 -3
  58. package/docs/vision-skills.md +52 -101
  59. package/docs/webhooks.md +132 -0
  60. package/examples/feature-tour.ts +4 -21
  61. package/package.json +1 -1
  62. package/dist/_contracts/proxy-protocol.d.ts +0 -305
  63. package/dist/_contracts/proxy-protocol.js +0 -297
  64. package/dist/_contracts/proxy-validation.d.ts +0 -19
  65. package/dist/_contracts/proxy-validation.js +0 -51
  66. package/dist/data-tools.d.ts +0 -82
  67. package/dist/data-tools.js +0 -251
  68. package/dist/data-tools.js.map +0 -1
  69. package/dist/proxy-endpoint.d.ts +0 -131
  70. package/dist/proxy-endpoint.js +0 -144
  71. package/dist/proxy-endpoint.js.map +0 -1
  72. package/examples/chat-corpus.ts +0 -84
package/docs/secrets.md CHANGED
@@ -88,6 +88,11 @@ const metadata = await aex.secrets.get("serper-api-key");
88
88
 
89
89
  ## Inject A Workspace Secret Into A Run
90
90
 
91
+ > **Availability note:** workspace-secret `Secret.ref(...)` injection requires
92
+ > the next platform deploy — on the current hosted plane the referenced
93
+ > variable can resolve empty inside the run. Per-run `Secret.value(...)`
94
+ > secrets are unaffected. This note will be removed once the deploy lands.
95
+
91
96
  Reference workspace secrets with `Secret.ref(name)`. The value resolves
92
97
  server-side and is injected as the named environment variable.
93
98
 
@@ -111,5 +116,5 @@ await aex.run({
111
116
  await aex.secrets.delete("serper-api-key");
112
117
  ```
113
118
 
114
- The CLI supports per-run provider, MCP, and proxy credentials. Workspace secret
119
+ The CLI supports per-run provider and MCP credentials. Workspace secret
115
120
  administration is exposed through the SDK.
package/docs/skills.md CHANGED
@@ -72,9 +72,9 @@ files into the workspace under `/workspace/skills/<name>/`. So the `SKILL.md` bo
72
72
  and every supporting file are on disk from the first turn; the load-tool call is
73
73
  how that body enters the model's context, not how the files get written.
74
74
 
75
- The platform also mounts the `aex` CLI and a per-run manifest into every run.
76
- Skills call managed HTTP proxy endpoints through the mounted CLI
77
- (`aex proxy ...`); see [Credentials](credentials.md) for the policy and auth model.
75
+ Skills that call external HTTP APIs should read credentials from
76
+ `environment.secrets` and use the normal client for that service. See
77
+ [Credentials](credentials.md) for the secret model.
78
78
 
79
79
  Run-scoped asset copies are part of the run record and are removed by run deletion
80
80
  or retention cleanup.
@@ -1,73 +1,57 @@
1
1
  ---
2
- title: Call a vision (or any model) API from a skill
2
+ title: Call a vision API from a skill
3
3
  ---
4
4
 
5
- # Call a vision (or any model) API from a skill
5
+ # Call a vision API from a skill
6
6
 
7
- aex has no built-in vision tool. The agent's `provider`/`model` selects the
8
- *reasoning* model it is not an endpoint a skill can POST an image to mid-run.
9
- To give a run image understanding (or to call any other model/HTTP API), ship a
10
- **skill** that POSTs to the provider's OpenAI-compatible endpoint **through the
11
- managed proxy**, with the key supplied on a `ProxyEndpoint.bearer(...)` instance.
12
- The raw key never enters the container.
7
+ aex has no built-in vision tool. The agent's `provider` / `model` selects the
8
+ reasoning model for the run; if a skill needs image understanding mid-run, ship a
9
+ skill that calls the vision provider with normal HTTP and pass that provider key
10
+ as a runtime secret.
13
11
 
14
- This is the same proxy described in `credentials.md` — this page is the worked
15
- recipe for the model-API case, which has two wrinkles a plain JSON call does not:
16
- the image rides as a **base64 data URL** in the request body, and that body is
17
- large enough to need a raised `maxRequestBytes`.
12
+ The runnable example lives at [`examples/vision-skill/`](../../../examples/vision-skill).
13
+ It captions a frame with ByteDance Doubao Seed Vision (Ark) and returns a
14
+ per-noun "does the frame depict X?" verdict.
18
15
 
19
- The canonical, runnable example lives in the repo at
20
- [`examples/vision-skill/`](../../../examples/vision-skill) (`SKILL.md`,
21
- `caption_frame.py`, `verify_frame.py`, `run_with_vision_skill.mjs`). It
22
- captions a frame with ByteDance Doubao Seed Vision (Ark) and returns a per-noun
23
- "does the frame depict X?" verdict. Everything below is taken from it.
24
-
25
- ## 1. Declare the model endpoint as a proxy endpoint
26
-
27
- The vision provider's API is just an HTTPS host. Declare it with
28
- `ProxyEndpoint.bearer(...)`, which carries the key on the instance. The two
29
- model-specific settings are `responseMode: "full"` (so the skill gets the upstream
30
- JSON back) and a raised `maxRequestBytes` (so the base64 image fits):
16
+ ## Submit the run
31
17
 
32
18
  ```ts
33
- import { Aex, Models, Tools, ProxyEndpoint } from "@aexhq/sdk";
19
+ import { Aex, Models, Secret, Tools } from "@aexhq/sdk";
34
20
 
35
21
  const aex = new Aex({ apiToken: process.env.AEX_API_TOKEN! });
36
22
 
37
- const doubaoArk = ProxyEndpoint.bearer({
38
- name: "doubao-ark",
39
- baseUrl: "https://ark.ap-southeast.bytepluses.com", // intl BytePlus gateway
40
- token: process.env.DOUBAO_API_KEY!,
41
- allowMethods: ["POST"],
42
- allowPathPrefixes: ["/api/v3/chat/completions"],
43
- maxRequestBytes: 2_000_000, // base64 image POSTs — see note below
44
- responseMode: "full",
45
- timeoutMs: 60_000
46
- });
47
-
48
- await aex.run({
23
+ const result = await aex.run({
49
24
  model: Models.CLAUDE_HAIKU_4_5,
50
- message: "…read skills/frame-vision-gate/SKILL.md, then caption + verify the frame",
25
+ message: "Read skills/frame-vision-gate/SKILL.md, then caption and verify the frame.",
51
26
  tools: [await Tools.fromSkillDir("./vision-skill", { name: "frame-vision-gate" })],
52
- proxyEndpoints: [doubaoArk],
27
+ environment: {
28
+ secrets: {
29
+ DOUBAO_API_KEY: Secret.value(process.env.DOUBAO_API_KEY!)
30
+ },
31
+ networking: {
32
+ mode: "limited",
33
+ allowedHosts: ["ark.ap-southeast.bytepluses.com"]
34
+ }
35
+ },
53
36
  apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
54
37
  });
38
+
39
+ console.log(result.runId, result.text);
55
40
  ```
56
41
 
57
- `Tools.fromSkillDir("./vision-skill", )` is resolved relative to the process CWD, so
58
- run the script from the directory that *contains* `vision-skill/` (in the
59
- repo, that is `examples/`). The same pattern works for OpenAI, Gemini's
60
- OpenAI-compatible endpoint, or any other OpenAI-chat-shaped vision API — only
61
- `baseUrl` and the path prefix change.
42
+ `Tools.fromSkillDir("./vision-skill", ...)` is resolved relative to the process
43
+ CWD. Run the script from the directory that contains `vision-skill/` (in this
44
+ repo, `examples/`).
62
45
 
63
- ## 2. POST the image as a base64 data URL through the proxy
46
+ ## Call the provider from the skill
64
47
 
65
- Inside the run, the skill builds the OpenAI-compatible chat-completions body. The
66
- image is **base64-inlined as a data URL** in an `image_url` content part — it is
67
- not uploaded:
48
+ Inside the run, the skill reads `DOUBAO_API_KEY` and makes an
49
+ OpenAI-compatible chat-completions request with Python's standard HTTP client.
50
+ The image is base64-inlined as a data URL in the request body:
68
51
 
69
52
  ```python
70
- import base64, json
53
+ import base64, json, os, urllib.request
54
+
71
55
  b64 = base64.b64encode(open("/workspace/files/frame.jpg", "rb").read()).decode()
72
56
  request_body = {
73
57
  "model": "doubao-seed-1-6-vision-250815",
@@ -81,63 +65,30 @@ request_body = {
81
65
  ]}
82
66
  ]
83
67
  }
84
- ```
85
-
86
- Write the body to a file and hand it to the mounted CLI with `--data @<file>`
87
- (the mount has no execute bit, so invoke through `bun`; see `credentials.md`):
88
68
 
89
- ```python
90
- import subprocess
91
- body_path = "/workspace/.aex/_ark_request.json"
92
- open(body_path, "w").write(json.dumps(request_body))
93
-
94
- result = subprocess.run(
95
- ["bun", "/mnt/session/uploads/aex/aex", "proxy", "doubao-ark",
96
- "--method", "POST",
97
- "--path", "/api/v3/chat/completions",
98
- "--header", "content-type=application/json",
99
- "--data", f"@{body_path}",
100
- "--response-mode", "full"],
101
- capture_output=True, text=True, timeout=90,
69
+ req = urllib.request.Request(
70
+ "https://ark.ap-southeast.bytepluses.com/api/v3/chat/completions",
71
+ data=json.dumps(request_body).encode("utf-8"),
72
+ headers={
73
+ "Authorization": f"Bearer {os.environ['DOUBAO_API_KEY']}",
74
+ "Content-Type": "application/json"
75
+ },
76
+ method="POST",
102
77
  )
103
78
  ```
104
79
 
105
- In `--response-mode full` the CLI prints a `ProxyResponseEnvelope` on stdout. The
106
- upstream JSON is **base64-encoded** in `upstreamBodyBase64`; an error instead
107
- carries an `error` field. Unwrap it:
108
-
109
- ```python
110
- envelope = json.loads(result.stdout)
111
- if "error" in envelope:
112
- raise RuntimeError(f"proxy error: {envelope['error']}: {envelope['message']}")
113
- upstream = json.loads(base64.b64decode(envelope["upstreamBodyBase64"]).decode())
114
- content = upstream["choices"][0]["message"]["content"] # the model's JSON answer
115
- ```
116
-
117
- The key is injected by the hosted proxy on the outbound call; it never appears on disk in
118
- the container or in the model's context.
119
-
120
- ## `maxRequestBytes` and timeout defaults
80
+ The same pattern works for OpenAI, Gemini's OpenAI-compatible endpoint, or any
81
+ other HTTPS model API. Put the key in `environment.secrets`, allow-list the host
82
+ when using limited networking, and use the provider's normal SDK or HTTP API.
121
83
 
122
- The per-endpoint `maxRequestBytes` default is **10 MiB** and the default timeout
123
- is **5 minutes**. That fits typical base64 image/model POSTs without extra
124
- configuration. If a body does exceed the cap, the proxy rejects it before any
125
- upstream call with an explicit error naming the observed size, the configured
126
- cap, and how to raise it:
84
+ ## Payload size
127
85
 
128
- > request body is 2400000 bytes, which exceeds this endpoint's maxRequestBytes
129
- > (10485760). Raise the per-endpoint maxRequestBytes in the proxy endpoint policy …
86
+ Base64 images are larger than their source files. Scale frames before captioning
87
+ when possible, for example:
130
88
 
131
- Two ways to stay under the cap: raise `maxRequestBytes`, and/or scale frames
132
- before captioning (`ffmpeg -i source.mp4 -vf fps=1,scale=960:-1 frame_%03d.jpg`)
133
- so full-res frames do not add payload and model cost without useful signal.
134
-
135
- ## Notes
89
+ ```bash
90
+ ffmpeg -i source.mp4 -vf fps=1,scale=960:-1 frame_%03d.jpg
91
+ ```
136
92
 
137
- - **Host selection.** Use the provider endpoint that matches your account and
138
- declare it as the proxy endpoint `baseUrl`.
139
- - **Keyless model hosts.** If the upstream takes no credential, declare the
140
- endpoint with `ProxyEndpoint.none(...)` (see `credentials.md`).
141
- - **Response size.** `responseMode: "full"` is required to read the model's reply
142
- back. Leave `maxResponseBytes` at its default (`0` = unlimited, streamed) unless
143
- you want a truncation cap.
93
+ This keeps upload size and model cost bounded without losing the signal most
94
+ vision models need.
@@ -0,0 +1,132 @@
1
+ ---
2
+ title: Webhooks
3
+ ---
4
+
5
+ # Webhooks
6
+
7
+ aex can notify your endpoint when a run finishes. Webhooks are **per-run**: you
8
+ pass a callback URL with the submission, and the platform delivers exactly one
9
+ `run.finished` event to it when the run reaches its terminal state.
10
+
11
+ > **Availability note:** terminal webhook delivery for session-based runs
12
+ > requires the next platform deploy — on the current hosted plane a session
13
+ > run's webhook may not fire. This note will be removed once the deploy lands.
14
+
15
+ ## Register a callback
16
+
17
+ ```ts
18
+ import { Aex, Models } from "@aexhq/sdk";
19
+
20
+ const aex = new Aex(process.env.AEX_API_TOKEN!);
21
+
22
+ const session = await aex.openSession({
23
+ model: Models.CLAUDE_HAIKU_4_5,
24
+ webhook: { url: "https://hooks.example.com/aex" },
25
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
26
+ });
27
+ ```
28
+
29
+ ```bash
30
+ aex run \
31
+ --api-token "$AEX_API_TOKEN" \
32
+ --anthropic-api-key "$ANTHROPIC_API_KEY" \
33
+ --model claude-haiku-4-5 \
34
+ --prompt "Write the report." \
35
+ --webhook https://hooks.example.com/aex
36
+ ```
37
+
38
+ The URL must be `https`. The callback URL is an operational concern, not part
39
+ of the submission fingerprint: retrying the same submission with the same
40
+ idempotency key but a different callback URL never conflicts.
41
+
42
+ ## What gets delivered
43
+
44
+ One POST carrying the terminal `run.finished` event, sent at the
45
+ settle-consistent barrier — when you receive it, the run record is already
46
+ terminal and its outputs are complete and readable. The body is built once at
47
+ settle, frozen, and re-sent byte-identical on every retry or manual redelivery:
48
+
49
+ ```json
50
+ {
51
+ "specversion": "1.0",
52
+ "id": "<delivery id — matches the webhook-id header>",
53
+ "source": "aex",
54
+ "type": "run.finished",
55
+ "subject": "<the run id>",
56
+ "time": "2026-07-02T12:34:56.000Z",
57
+ "data": {
58
+ "runId": "<the run id>",
59
+ "status": "succeeded",
60
+ "terminalAt": "2026-07-02T12:34:56.000Z",
61
+ "reason": null,
62
+ "failureClass": null,
63
+ "costTelemetry": { "billedCostUsd": 0.42 }
64
+ }
65
+ }
66
+ ```
67
+
68
+ `reason` / `failureClass` carry the failure detail on non-success terminals;
69
+ `costTelemetry` is present when the billed cost is known.
70
+
71
+ ## Verify deliveries
72
+
73
+ Deliveries are signed [Standard Webhooks](https://www.standardwebhooks.com/)
74
+ style: HMAC-SHA256 over `` `${webhook-id}.${webhook-timestamp}.${rawBody}` ``,
75
+ sent in three headers — `webhook-id` (stable across retries; your dedupe key),
76
+ `webhook-timestamp` (unix seconds), and `webhook-signature` (a space-delimited
77
+ list of `v1,<base64>` entries).
78
+
79
+ The signing key is a per-workspace secret. Reveal it (it is created on first
80
+ use) with either surface:
81
+
82
+ ```bash
83
+ aex webhooks secret --api-token "$AEX_API_TOKEN" # prints whsec_...
84
+ ```
85
+
86
+ ```ts
87
+ const { whsec } = await aex.webhookSigningSecret();
88
+ ```
89
+
90
+ Verify inbound requests with the exported `verifyAexWebhook` — pure Web Crypto,
91
+ identical under Bun and Node, and interoperable with the `standardwebhooks`
92
+ reference library:
93
+
94
+ ```ts
95
+ import { verifyAexWebhook } from "@aexhq/sdk";
96
+
97
+ // In your HTTP handler — use the EXACT raw body bytes, never re-serialize.
98
+ const ok = await verifyAexWebhook({
99
+ rawBody,
100
+ headers: request.headers,
101
+ secret: process.env.AEX_WEBHOOK_SECRET! // the whsec_... value
102
+ });
103
+ if (!ok) return new Response("bad signature", { status: 401 });
104
+ ```
105
+
106
+ `verifyAexWebhook` rejects stale timestamps (default tolerance 300 seconds) and
107
+ compares signatures constant-time. It accepts every `v1` entry in the signature
108
+ list, so it is already rotation-ready — but **server-side rotation of the
109
+ signing secret is not available yet**: `aex webhooks secret` reveals or creates
110
+ the one workspace secret and there is no rotate endpoint today. If your secret
111
+ is compromised, contact <support@aex.dev>.
112
+
113
+ ## Delivery ledger and redelivery
114
+
115
+ Each run keeps a delivery ledger — attempts, last status code, and last error:
116
+
117
+ ```ts
118
+ const deliveries = await session.webhooks().list();
119
+ await session.webhooks().redeliver(deliveries[0]!.id);
120
+ ```
121
+
122
+ ```bash
123
+ aex deliveries <session-id> --api-token "$AEX_API_TOKEN"
124
+ ```
125
+
126
+ Redelivery re-sends the frozen payload with the **same** `webhook-id`, so a
127
+ consumer that dedupes on `webhook-id` handles retries, redeliveries, and
128
+ at-least-once delivery uniformly. An empty ledger means the run carried no
129
+ `webhook` or has not reached a terminal state yet.
130
+
131
+ For the terminal-event mechanics behind delivery timing, see
132
+ [Events](events.md).
@@ -2,7 +2,7 @@
2
2
  * SDK feature tour: one managed session that uses typed model/runtime constants,
3
3
  * inline AGENTS.md guidance, uploaded files, a custom tool bundle, selected
4
4
  * built-in tools, runtime env vars/secrets, streamed events, output reads, and
5
- * corpus-scoped data tools.
5
+ * a follow-up session turn.
6
6
  *
7
7
  * Run from the repository root after building the workspace package:
8
8
  *
@@ -20,13 +20,11 @@ import {
20
20
  AgentsMd,
21
21
  Aex,
22
22
  BuiltinTools,
23
- createCorpusTools,
24
23
  File,
25
24
  isRateLimited,
26
25
  isTextMessage,
27
26
  McpServer,
28
27
  Models,
29
- ProxyEndpoint,
30
28
  Providers,
31
29
  Secret,
32
30
  Sizes,
@@ -132,17 +130,6 @@ const environmentSecrets = demoRuntimeSecret
132
130
  ? { DEMO_RUNTIME_SECRET: Secret.value(demoRuntimeSecret) }
133
131
  : undefined;
134
132
 
135
- const proxyEndpoints = [
136
- ProxyEndpoint.none({
137
- name: "httpbin",
138
- baseUrl: "https://httpbin.org",
139
- allowMethods: ["GET"],
140
- allowPathPrefixes: ["/json"],
141
- responseMode: "full",
142
- timeoutMs: 10_000
143
- })
144
- ];
145
-
146
133
  console.log("creating feature-tour session...");
147
134
  console.log(`optional mcp: ${mcpServers.length > 0 ? "enabled" : "disabled"}`);
148
135
  console.log(`optional runtime secret: ${environmentSecrets ? "enabled" : "disabled"}`);
@@ -165,7 +152,6 @@ const session = await aex.openSession({
165
152
  BuiltinTools.code_execution,
166
153
  metricLookup
167
154
  ],
168
- proxyEndpoints,
169
155
  mcpServers,
170
156
  environment: {
171
157
  networking: { mode: "open" },
@@ -201,8 +187,7 @@ const prompt = [
201
187
  "Analyze the attached quarterly metrics.",
202
188
  "Call metric_lookup for atlas, beacon, and cinder.",
203
189
  "Create /workspace/outputs/feature-tour-report.md with a short table, a ranking by q2_revenue_usd, and two risks.",
204
- "Create /workspace/outputs/summary.json with keys topProduct, totalQ2RevenueUsd, highestActivationProduct, and riskCount.",
205
- "Mention whether the httpbin proxy endpoint is declared, but do not call it unless you need to."
190
+ "Create /workspace/outputs/summary.json with keys topProduct, totalQ2RevenueUsd, highestActivationProduct, and riskCount."
206
191
  ].join(" ");
207
192
 
208
193
  const firstTurn = session.send(prompt);
@@ -272,10 +257,8 @@ if (report) {
272
257
  console.log(reportPreview.text || "(no risk lines found)");
273
258
  }
274
259
 
275
- const corpusTools = createCorpusTools(aex, { sessionIds: [session.id] }, { defaultReadBytes: 4_000 });
276
- const corpusOutputs = await corpusTools.execute("list_outputs", { session_id: session.id });
277
- console.log("corpus-scoped list_outputs result:");
278
- console.log(JSON.stringify(corpusOutputs, null, 2));
260
+ const reopenedOutputs = await aex.sessions.outputs(session.id).list();
261
+ console.log(`outputs via aex.sessions.outputs(...): ${reopenedOutputs.length}`);
279
262
 
280
263
  if (downloadPath) {
281
264
  const bytes = await session.download({ to: downloadPath });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexhq/sdk",
3
- "version": "0.35.0",
3
+ "version": "0.37.0",
4
4
  "description": "TypeScript SDK for running autonomous agent sessions across providers (Anthropic, OpenAI, DeepSeek, Gemini, Mistral) behind one interface.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {