@aexhq/sdk 0.31.0 → 0.33.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 (43) hide show
  1. package/README.md +29 -31
  2. package/dist/_contracts/event-stream-client.d.ts +2 -2
  3. package/dist/_contracts/event-stream-client.js +3 -3
  4. package/dist/_contracts/index.d.ts +0 -1
  5. package/dist/_contracts/index.js +0 -1
  6. package/dist/_contracts/models.d.ts +0 -76
  7. package/dist/_contracts/models.js +0 -20
  8. package/dist/_contracts/operations.d.ts +15 -18
  9. package/dist/_contracts/operations.js +81 -40
  10. package/dist/_contracts/post-hook.d.ts +4 -4
  11. package/dist/_contracts/post-hook.js +1 -1
  12. package/dist/_contracts/run-config.d.ts +0 -4
  13. package/dist/_contracts/run-config.js +0 -7
  14. package/dist/_contracts/run-unit.js +4 -4
  15. package/dist/_contracts/runtime-types.d.ts +86 -2
  16. package/dist/_contracts/status.d.ts +3 -1
  17. package/dist/_contracts/status.js +17 -0
  18. package/dist/_contracts/submission.d.ts +1 -10
  19. package/dist/_contracts/submission.js +0 -4
  20. package/dist/cli.mjs +118 -135
  21. package/dist/cli.mjs.sha256 +1 -1
  22. package/dist/client.d.ts +118 -72
  23. package/dist/client.js +427 -96
  24. package/dist/client.js.map +1 -1
  25. package/dist/index.d.ts +5 -4
  26. package/dist/index.js +3 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/version.d.ts +1 -1
  29. package/dist/version.js +1 -1
  30. package/docs/cleanup.md +2 -2
  31. package/docs/credentials.md +3 -3
  32. package/docs/defaults.md +0 -2
  33. package/docs/events.md +32 -13
  34. package/docs/limits.md +4 -3
  35. package/docs/outputs.md +2 -2
  36. package/docs/provider-runtime-capabilities.md +2 -2
  37. package/docs/public-surface.json +15 -10
  38. package/docs/quickstart.md +38 -12
  39. package/docs/run-config.md +3 -8
  40. package/docs/secrets.md +2 -2
  41. package/docs/skills.md +4 -4
  42. package/docs/vision-skills.md +2 -2
  43. package/package.json +1 -1
package/README.md CHANGED
@@ -8,7 +8,8 @@ aex is an agent execution platform for launching autonomous agents from a simple
8
8
 
9
9
  The package ships:
10
10
 
11
- - `AgentExecutor` for submit, run, wait, stream, inspect, download, cancel, and delete.
11
+ - `Aex` / `AgentExecutor` for sessions, one-shot runs, inspect, download, cancel, and delete.
12
+ - `sessions` / `openSession()` for durable, resumable agent sessions.
12
13
  - Typed run primitives: `Models`, `Providers`, `RuntimeSizes`, `Skill`, `AgentsMd`, `File`, `McpServer`, `ProxyEndpoint`, and `Secret`.
13
14
  - A bundled `aex` CLI with the same run, status, events, outputs, download, cancel, delete, whoami, and skills operations.
14
15
 
@@ -27,56 +28,53 @@ export AEX_API_TOKEN="<your-aex-token>"
27
28
  export ANTHROPIC_API_KEY="<your-anthropic-api-key>"
28
29
  ```
29
30
 
30
- ## First Run
31
+ ## First Session
31
32
 
32
33
  ```ts
33
- import { AgentExecutor, Models } from "@aexhq/sdk";
34
+ import { Aex, Models, Sizes } from "@aexhq/sdk";
34
35
 
35
- const aex = new AgentExecutor({ apiToken: process.env.AEX_API_TOKEN! });
36
+ const aex = new Aex({ apiToken: process.env.AEX_API_TOKEN! });
36
37
 
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({
38
+ const session = await aex.openSession({
40
39
  model: Models.CLAUDE_HAIKU_4_5,
41
- secrets: { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } },
42
- prompt: "Summarize this repo."
40
+ system: "You are a concise engineering assistant.",
41
+ runtime: Sizes.SHARED_0_25X_1GB,
42
+ // Default is "3m"; set it explicitly when you want a different idle window.
43
+ overrides: { idleTtl: "3m" },
44
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
43
45
  });
44
46
 
45
- console.log(ok, text);
47
+ const first = await session.send("Summarize this repo.").done();
48
+ console.log(first.status, first.text);
49
+
50
+ const resumed = await aex.openSession(session.id);
51
+ await resumed.send("Continue with the follow-up validation.").done();
46
52
  ```
47
53
 
48
- Need the run id, live events, or downloads? Use `submit` + `stream` + `wait`:
54
+ Need a one-shot convenience? `run()` opens a session, sends `message` as one
55
+ turn, and returns the collected result. The returned `runId` is the session id,
56
+ so it can be resumed later with `openSession(runId)`.
49
57
 
50
58
  ```ts
51
- const runId = await aex.submit({
59
+ const result = await aex.run({
52
60
  model: Models.CLAUDE_HAIKU_4_5,
53
- secrets: { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } },
54
- prompt: "Write the report and save outputs."
61
+ apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! },
62
+ message: "Write the report and save outputs."
55
63
  });
56
64
 
57
- for await (const event of aex.stream(runId)) {
58
- console.log(event.type);
59
- }
60
-
61
- const run = await aex.wait(runId);
62
- console.log(run.status);
63
-
64
- await aex.download(runId, { to: "./run.zip" });
65
+ console.log(result.runId, result.status, result.text);
65
66
  ```
66
67
 
67
- For multiple providers (e.g. subagents on a different model family), include
68
- each BYOK key in `secrets.apiKeys`:
68
+ For multiple providers, include each BYOK key in `apiKeys`:
69
69
 
70
70
  ```ts
71
71
  await aex.run({
72
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
- }
73
+ apiKeys: {
74
+ anthropic: process.env.ANTHROPIC_API_KEY!,
75
+ openai: process.env.OPENAI_API_KEY!
78
76
  },
79
- prompt: "Delegate research to a subagent."
77
+ message: "Delegate research to a subagent."
80
78
  });
81
79
  ```
82
80
 
@@ -144,7 +142,7 @@ finds output files across runs and returns references (no bytes) you then
144
142
 
145
143
  ## Feature Areas
146
144
 
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.
145
+ - **Agent runtime:** managed autonomous runs with filesystem read/edit, grep/glob/head/tail, open web fetch/search defaults, and optional notebook tools.
148
146
  - **Durable infrastructure:** run records, status, wait/cancel/delete, idempotency, typed events, output capture, downloads, timeouts, and runtime sizes.
149
147
  - **Agent composition:** skills, files, AGENTS.md, remote MCP servers, proxy endpoints, environment variables, packages, and networking controls.
150
148
  - **Subagents:** typed parent/child lineage for async child runs, output handoff, and bounded agent delegation.
@@ -12,7 +12,7 @@
12
12
  * A silently half-open socket (no close/error, no frames) is the dangerous
13
13
  * case: the read loop would block forever and MISS a terminal that was already
14
14
  * persisted server-side. So the client sends a tiny keep-alive ping the
15
- * coordinator auto-responds to (hibernation-safe, no DO wake) and runs an idle
15
+ * coordinator answers with a matching pong, and runs an idle
16
16
  * watchdog: if no frame arrives within {@link CoordinatorStreamOptions.idleTimeoutMs},
17
17
  * the socket is treated as dead and reconnected — resume-from-cursor then
18
18
  * replays the terminal.
@@ -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 stateful coordinator, so
68
+ * which the coordinator answers with a matching pong, 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).
@@ -12,7 +12,7 @@
12
12
  * A silently half-open socket (no close/error, no frames) is the dangerous
13
13
  * case: the read loop would block forever and MISS a terminal that was already
14
14
  * persisted server-side. So the client sends a tiny keep-alive ping the
15
- * coordinator auto-responds to (hibernation-safe, no DO wake) and runs an idle
15
+ * coordinator answers with a matching pong, and runs an idle
16
16
  * watchdog: if no frame arrives within {@link CoordinatorStreamOptions.idleTimeoutMs},
17
17
  * the socket is treated as dead and reconnected — resume-from-cursor then
18
18
  * replays the terminal.
@@ -26,8 +26,8 @@
26
26
  */
27
27
  const isTerminalType = (e) => e.type === "RUN_FINISHED" || e.type === "RUN_ERROR";
28
28
  /**
29
- * Keep-alive ping the client sends; the coordinator answers it via
30
- * `setWebSocketAutoResponse` without waking the DO. Must stay byte-identical to
29
+ * Keep-alive ping the client sends; the coordinator answers it with the matching
30
+ * pong in its WebSocket message handler. Must stay byte-identical to
31
31
  * the coordinator's pair (aex-platform `packages/shared/src/event-stream-client.ts`).
32
32
  */
33
33
  const COORDINATOR_PING = "aex:ping";
@@ -4,7 +4,6 @@ export * from "./models.js";
4
4
  export * from "./status.js";
5
5
  export * from "./submission.js";
6
6
  export * from "./runtime-sizes.js";
7
- export * from "./post-hook.js";
8
7
  export * from "./runner-event.js";
9
8
  export * from "./event-envelope.js";
10
9
  export * from "./connection-ticket.js";
@@ -4,7 +4,6 @@ export * from "./models.js";
4
4
  export * from "./status.js";
5
5
  export * from "./submission.js";
6
6
  export * from "./runtime-sizes.js";
7
- export * from "./post-hook.js";
8
7
  export * from "./runner-event.js";
9
8
  export * from "./event-envelope.js";
10
9
  export * from "./connection-ticket.js";
@@ -36,12 +36,6 @@ export declare const MODEL_PROVIDER_IDS: {
36
36
  readonly "deepseek-v4-pro": {
37
37
  readonly deepseek: "deepseek-v4-pro";
38
38
  };
39
- readonly "deepseek-chat": {
40
- readonly deepseek: "deepseek-chat";
41
- };
42
- readonly "deepseek-reasoner": {
43
- readonly deepseek: "deepseek-reasoner";
44
- };
45
39
  readonly "gpt-4.1": {
46
40
  readonly openai: "gpt-4.1";
47
41
  };
@@ -102,76 +96,6 @@ export declare const Models: {
102
96
  readonly DEEPSEEK_V4_FLASH: "deepseek-v4-flash";
103
97
  /** DeepSeek V4 Pro — DeepSeek (reasoning-heavy). */
104
98
  readonly DEEPSEEK_V4_PRO: "deepseek-v4-pro";
105
- /**
106
- * @deprecated Legacy alias DeepSeek routes to `deepseek-v4-flash` (non-thinking).
107
- * DeepSeek removes this name on 2026-07-24 15:59 UTC — migrate to
108
- * {@link Models.DEEPSEEK_V4_FLASH}.
109
- */
110
- readonly DEEPSEEK_CHAT: "deepseek-chat";
111
- /**
112
- * @deprecated Legacy alias DeepSeek routes to `deepseek-v4-flash` (thinking).
113
- * DeepSeek removes this name on 2026-07-24 15:59 UTC — migrate to
114
- * {@link Models.DEEPSEEK_V4_FLASH} (or {@link Models.DEEPSEEK_V4_PRO} for
115
- * heavier reasoning).
116
- */
117
- readonly DEEPSEEK_REASONER: "deepseek-reasoner";
118
- /** GPT-4.1 — OpenAI. */
119
- readonly GPT_4_1: "gpt-4.1";
120
- /** GPT-4o mini — OpenAI, or via OpenRouter (`provider: Providers.OPENROUTER`). */
121
- readonly GPT_4O_MINI: "gpt-4o-mini";
122
- /** GPT-4o — via OpenRouter (`provider: Providers.OPENROUTER`). */
123
- readonly GPT_4O: "gpt-4o";
124
- /** Gemini 2.0 Flash — Gemini, or via OpenRouter (`provider: Providers.OPENROUTER`). */
125
- readonly GEMINI_2_0_FLASH: "gemini-2.0-flash";
126
- /** Gemini 2.5 Flash — Gemini. */
127
- readonly GEMINI_2_5_FLASH: "gemini-2.5-flash";
128
- /** Mistral Large (latest) — Mistral. */
129
- readonly MISTRAL_LARGE_LATEST: "mistral-large-latest";
130
- /** Mistral Small (latest) — Mistral. */
131
- readonly MISTRAL_SMALL_LATEST: "mistral-small-latest";
132
- /**
133
- * Doubao Seed 1.8 — ByteDance, via the official Ark API. Default routes
134
- * through the international BytePlus gateway (`Providers.DOUBAO`); pair with
135
- * `Providers.DOUBAO_CN` for the China Volcengine gateway.
136
- */
137
- readonly DOUBAO_SEED_PRO: "doubao-seed-pro";
138
- /**
139
- * Doubao Seed 1.6 Flash — ByteDance, via the official Ark API (fast/cheap).
140
- * Default `Providers.DOUBAO` (international); pair with `Providers.DOUBAO_CN`
141
- * for China.
142
- */
143
- readonly DOUBAO_SEED_FLASH: "doubao-seed-flash";
144
- };
145
- /**
146
- * Back-compat alias for {@link Models}. Existing imports of `RunModels`
147
- * keep working; new code should prefer `Models`.
148
- */
149
- export declare const RunModels: {
150
- /** Claude Haiku 4.5 — Anthropic. */
151
- readonly CLAUDE_HAIKU_4_5: "claude-haiku-4-5";
152
- /** Claude 3.5 Haiku (latest) — Anthropic. */
153
- readonly CLAUDE_3_5_HAIKU_LATEST: "claude-3-5-haiku-latest";
154
- /** Claude 3.5 Sonnet (latest) — Anthropic. */
155
- readonly CLAUDE_3_5_SONNET_LATEST: "claude-3-5-sonnet-latest";
156
- /** Claude Sonnet 4.6 — Anthropic (1M context, reasoning-capable). */
157
- readonly CLAUDE_SONNET_4_6: "claude-sonnet-4-6";
158
- /** DeepSeek V4 Flash — DeepSeek (non-thinking, fast). */
159
- readonly DEEPSEEK_V4_FLASH: "deepseek-v4-flash";
160
- /** DeepSeek V4 Pro — DeepSeek (reasoning-heavy). */
161
- readonly DEEPSEEK_V4_PRO: "deepseek-v4-pro";
162
- /**
163
- * @deprecated Legacy alias DeepSeek routes to `deepseek-v4-flash` (non-thinking).
164
- * DeepSeek removes this name on 2026-07-24 15:59 UTC — migrate to
165
- * {@link Models.DEEPSEEK_V4_FLASH}.
166
- */
167
- readonly DEEPSEEK_CHAT: "deepseek-chat";
168
- /**
169
- * @deprecated Legacy alias DeepSeek routes to `deepseek-v4-flash` (thinking).
170
- * DeepSeek removes this name on 2026-07-24 15:59 UTC — migrate to
171
- * {@link Models.DEEPSEEK_V4_FLASH} (or {@link Models.DEEPSEEK_V4_PRO} for
172
- * heavier reasoning).
173
- */
174
- readonly DEEPSEEK_REASONER: "deepseek-reasoner";
175
99
  /** GPT-4.1 — OpenAI. */
176
100
  readonly GPT_4_1: "gpt-4.1";
177
101
  /** GPT-4o mini — OpenAI, or via OpenRouter (`provider: Providers.OPENROUTER`). */
@@ -23,8 +23,6 @@ export const MODEL_PROVIDER_IDS = {
23
23
  "claude-sonnet-4-6": { anthropic: "claude-sonnet-4-6" },
24
24
  "deepseek-v4-flash": { deepseek: "deepseek-v4-flash" },
25
25
  "deepseek-v4-pro": { deepseek: "deepseek-v4-pro" },
26
- "deepseek-chat": { deepseek: "deepseek-chat" },
27
- "deepseek-reasoner": { deepseek: "deepseek-reasoner" },
28
26
  "gpt-4.1": { openai: "gpt-4.1" },
29
27
  "gpt-4o-mini": { openai: "gpt-4o-mini", openrouter: "openai/gpt-4o-mini" },
30
28
  "gpt-4o": { openrouter: "openai/gpt-4o" },
@@ -69,19 +67,6 @@ export const Models = {
69
67
  DEEPSEEK_V4_FLASH: "deepseek-v4-flash",
70
68
  /** DeepSeek V4 Pro — DeepSeek (reasoning-heavy). */
71
69
  DEEPSEEK_V4_PRO: "deepseek-v4-pro",
72
- /**
73
- * @deprecated Legacy alias DeepSeek routes to `deepseek-v4-flash` (non-thinking).
74
- * DeepSeek removes this name on 2026-07-24 15:59 UTC — migrate to
75
- * {@link Models.DEEPSEEK_V4_FLASH}.
76
- */
77
- DEEPSEEK_CHAT: "deepseek-chat",
78
- /**
79
- * @deprecated Legacy alias DeepSeek routes to `deepseek-v4-flash` (thinking).
80
- * DeepSeek removes this name on 2026-07-24 15:59 UTC — migrate to
81
- * {@link Models.DEEPSEEK_V4_FLASH} (or {@link Models.DEEPSEEK_V4_PRO} for
82
- * heavier reasoning).
83
- */
84
- DEEPSEEK_REASONER: "deepseek-reasoner",
85
70
  /** GPT-4.1 — OpenAI. */
86
71
  GPT_4_1: "gpt-4.1",
87
72
  /** GPT-4o mini — OpenAI, or via OpenRouter (`provider: Providers.OPENROUTER`). */
@@ -109,11 +94,6 @@ export const Models = {
109
94
  */
110
95
  DOUBAO_SEED_FLASH: "doubao-seed-flash"
111
96
  };
112
- /**
113
- * Back-compat alias for {@link Models}. Existing imports of `RunModels`
114
- * keep working; new code should prefer `Models`.
115
- */
116
- export const RunModels = Models;
117
97
  /**
118
98
  * Per-model provider lists, in declaration order. Derived from
119
99
  * {@link MODEL_PROVIDER_IDS} so the two never drift.
@@ -1,6 +1,6 @@
1
1
  import type { HttpClient } from "./http.js";
2
2
  import type { RunUnit } from "./run-unit.js";
3
- import type { AgentsMdRecord, FileRecord, Output, OutputLink, OutputLinkOptions, OutputFileDownload, OutputFileSelector, OutputFileType, OutputQuery, OutputText, ReadOutputTextOptions, Run, RunEvent, RunListPage, RunListQuery, RunWebhookDelivery, SecretRecord, SecretReveal, Skill, WhoAmI } from "./runtime-types.js";
3
+ import type { AgentsMdRecord, FileRecord, Output, OutputLink, OutputLinkOptions, OutputFileDownload, OutputFileSelector, OutputFileType, OutputQuery, OutputText, ReadOutputTextOptions, Run, RunEvent, RunListPage, RunListQuery, Session, SessionCreateRequest, SessionEvent, SessionListPage, SessionListQuery, SessionMessageAccepted, SessionMessageRequest, SessionStateChangeAccepted, RunWebhookDelivery, SecretRecord, SecretReveal, Skill, WhoAmI } from "./runtime-types.js";
4
4
  import type { PlatformRunSubmissionInput } from "./submission.js";
5
5
  /**
6
6
  * The single source of truth for SDK<->BFF transport. The SDK class
@@ -37,6 +37,20 @@ export declare function getRunUnit(http: HttpClient, runId: string): Promise<Run
37
37
  * For a single page; callers wanting every run loop on `nextCursor` themselves.
38
38
  */
39
39
  export declare function listRuns(http: HttpClient, query?: RunListQuery): Promise<RunListPage>;
40
+ export interface IdempotencyOptions {
41
+ readonly idempotencyKey?: string;
42
+ }
43
+ export declare function createSession(http: HttpClient, request: SessionCreateRequest, options?: IdempotencyOptions): Promise<Session>;
44
+ export declare function getSession(http: HttpClient, sessionId: string): Promise<Session>;
45
+ export declare function listSessions(http: HttpClient, query?: SessionListQuery): Promise<SessionListPage>;
46
+ export declare function sendSessionMessage(http: HttpClient, sessionId: string, request: SessionMessageRequest, options?: IdempotencyOptions): Promise<SessionMessageAccepted>;
47
+ export declare function suspendSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
48
+ export declare function cancelSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
49
+ export declare function resumeSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
50
+ export declare function deleteSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted | void>;
51
+ export declare function listSessionEvents(http: HttpClient, sessionId: string): Promise<readonly SessionEvent[]>;
52
+ export declare function listSessionOutputs(http: HttpClient, sessionId: string, query?: OutputQuery): Promise<readonly Output[]>;
53
+ export declare function getSessionCoordinatorTicket(http: HttpClient, sessionId: string): Promise<CoordinatorTicket>;
40
54
  /**
41
55
  * List a run's events. The read endpoint is PAGED (bounded per response so a
42
56
  * long run can't return an unbounded body); this follows `nextCursor` across
@@ -183,26 +197,9 @@ export declare function findSkillByHash(http: HttpClient, args: {
183
197
  * indexed by-hash route is reserved for `uploadIfChanged`.
184
198
  */
185
199
  export declare function findSkillByName(http: HttpClient, name: string): Promise<Skill | null>;
186
- /**
187
- * Upload a workspace AgentsMd file as a markdown string. The BFF
188
- * canonicalises the content into a deterministic zip with AGENTS.md at
189
- * root and runs the two-phase pending → ready upload.
190
- */
191
- export declare function createAgentsMd(http: HttpClient, args: {
192
- readonly name: string;
193
- readonly content: string;
194
- }): Promise<AgentsMdRecord>;
195
200
  export declare function listAgentsMd(http: HttpClient): Promise<readonly AgentsMdRecord[]>;
196
201
  export declare function getAgentsMd(http: HttpClient, agentsMdId: string): Promise<AgentsMdRecord>;
197
202
  export declare function deleteAgentsMd(http: HttpClient, agentsMdId: string): Promise<void>;
198
- /**
199
- * Upload a workspace File as a zip bundle. The BFF canonicalises the
200
- * content and runs the two-phase pending → ready upload.
201
- */
202
- export declare function createFile(http: HttpClient, args: {
203
- readonly name: string;
204
- readonly bytes: Uint8Array;
205
- }): Promise<FileRecord>;
206
203
  export declare function listFiles(http: HttpClient): Promise<readonly FileRecord[]>;
207
204
  export declare function getFile(http: HttpClient, fileId: string): Promise<FileRecord>;
208
205
  export declare function deleteFile(http: HttpClient, fileId: string): Promise<void>;
@@ -52,6 +52,79 @@ export async function listRuns(http, query) {
52
52
  params.cursor = query.cursor;
53
53
  return http.request("/api/runs", {}, params);
54
54
  }
55
+ function idempotencyHeaders(options) {
56
+ return options?.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : undefined;
57
+ }
58
+ export async function createSession(http, request, options) {
59
+ const headers = idempotencyHeaders(options);
60
+ const result = await http.request("/api/sessions", {
61
+ method: "POST",
62
+ ...(headers ? { headers } : {}),
63
+ body: JSON.stringify(request)
64
+ });
65
+ return unwrapSession(result);
66
+ }
67
+ export async function getSession(http, sessionId) {
68
+ const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}`);
69
+ return unwrapSession(result);
70
+ }
71
+ export async function listSessions(http, query) {
72
+ const params = {};
73
+ if (query?.status !== undefined)
74
+ params.status = query.status;
75
+ if (query?.since !== undefined)
76
+ params.since = query.since;
77
+ if (query?.limit !== undefined)
78
+ params.limit = String(query.limit);
79
+ if (query?.cursor !== undefined)
80
+ params.cursor = query.cursor;
81
+ return http.request("/api/sessions", {}, params);
82
+ }
83
+ export async function sendSessionMessage(http, sessionId, request, options) {
84
+ const headers = idempotencyHeaders(options);
85
+ return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/messages`, {
86
+ method: "POST",
87
+ ...(headers ? { headers } : {}),
88
+ body: JSON.stringify(request)
89
+ });
90
+ }
91
+ export async function suspendSession(http, sessionId, options) {
92
+ const headers = idempotencyHeaders(options);
93
+ return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/suspend`, { method: "POST", ...(headers ? { headers } : {}) });
94
+ }
95
+ export async function cancelSession(http, sessionId, options) {
96
+ const headers = idempotencyHeaders(options);
97
+ return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/cancel`, { method: "POST", ...(headers ? { headers } : {}) });
98
+ }
99
+ export async function resumeSession(http, sessionId, options) {
100
+ const headers = idempotencyHeaders(options);
101
+ return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/resume`, { method: "POST", ...(headers ? { headers } : {}) });
102
+ }
103
+ export async function deleteSession(http, sessionId, options) {
104
+ const headers = idempotencyHeaders(options);
105
+ return http.request(`/api/sessions/${encodeURIComponent(sessionId)}`, { method: "DELETE", ...(headers ? { headers } : {}) });
106
+ }
107
+ export async function listSessionEvents(http, sessionId) {
108
+ const path = `/api/sessions/${encodeURIComponent(sessionId)}/events`;
109
+ const all = [];
110
+ let cursor;
111
+ for (let page = 0; page < LIST_EVENTS_PAGE_BUDGET; page++) {
112
+ const query = cursor !== undefined ? { cursor: String(cursor) } : {};
113
+ const result = await http.request(path, {}, query);
114
+ all.push(...result.events);
115
+ if (typeof result.nextCursor !== "number")
116
+ break;
117
+ cursor = result.nextCursor;
118
+ }
119
+ return all;
120
+ }
121
+ export async function listSessionOutputs(http, sessionId, query) {
122
+ const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}/outputs`);
123
+ return query === undefined ? result.outputs : filterOutputs(result.outputs, query);
124
+ }
125
+ export async function getSessionCoordinatorTicket(http, sessionId) {
126
+ return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/events/ticket`, { method: "POST" });
127
+ }
55
128
  // Bound the transparent pager: the read route caps each page at 1000, so this
56
129
  // admits up to ~1e6 events before bailing — past any real run, but bounded so a
57
130
  // server that never clears `nextCursor` can't loop forever.
@@ -707,20 +780,8 @@ export async function findSkillByName(http, name) {
707
780
  return skills.find((skill) => skill.name === name) ?? null;
708
781
  }
709
782
  // ===========================================================================
710
- // AgentsMd upload helpers. Launch submissions use content-addressed asset refs.
783
+ // AgentsMd read/delete helpers. Launch submissions use content-addressed asset refs.
711
784
  // ===========================================================================
712
- /**
713
- * Upload a workspace AgentsMd file as a markdown string. The BFF
714
- * canonicalises the content into a deterministic zip with AGENTS.md at
715
- * root and runs the two-phase pending → ready upload.
716
- */
717
- export async function createAgentsMd(http, args) {
718
- const form = new FormData();
719
- form.append("name", args.name);
720
- form.append("content", new Blob([args.content], { type: "text/plain" }), "AGENTS.md");
721
- const result = await http.request("/api/agentsmd", { method: "POST", body: form });
722
- return unwrapAgentsMd(result);
723
- }
724
785
  export async function listAgentsMd(http) {
725
786
  const result = await http.request("/api/agentsmd");
726
787
  if (Array.isArray(result)) {
@@ -744,20 +805,8 @@ function unwrapAgentsMd(result) {
744
805
  return result;
745
806
  }
746
807
  // ===========================================================================
747
- // File upload helpers. Launch submissions use content-addressed asset refs.
808
+ // File read/delete helpers. Launch submissions use content-addressed asset refs.
748
809
  // ===========================================================================
749
- /**
750
- * Upload a workspace File as a zip bundle. The BFF canonicalises the
751
- * content and runs the two-phase pending → ready upload.
752
- */
753
- export async function createFile(http, args) {
754
- const form = new FormData();
755
- form.append("name", args.name);
756
- const blob = toBlob(args.bytes, "application/zip");
757
- form.append("bundle", blob, `${args.name}.zip`);
758
- const result = await http.request("/api/files", { method: "POST", body: form });
759
- return unwrapFile(result);
760
- }
761
810
  export async function listFiles(http) {
762
811
  const result = await http.request("/api/files");
763
812
  if (Array.isArray(result)) {
@@ -836,23 +885,15 @@ function unwrapSkill(result) {
836
885
  }
837
886
  return result;
838
887
  }
839
- function toBlob(input, contentType) {
840
- if (input instanceof Blob) {
841
- return input;
842
- }
843
- if (input instanceof Uint8Array) {
844
- // BlobPart accepts ArrayBufferView, but lib.dom's overload set
845
- // narrows on the underlying buffer kind. Slice into a fresh
846
- // ArrayBuffer so a SharedArrayBuffer-backed Uint8Array works.
847
- const copy = new Uint8Array(input.byteLength);
848
- copy.set(input);
849
- return new Blob([copy.buffer], { type: contentType });
850
- }
851
- return new Blob([input], { type: contentType });
852
- }
853
888
  function hasRun(value) {
854
889
  return Boolean(value && typeof value === "object" && "run" in value);
855
890
  }
891
+ function unwrapSession(result) {
892
+ if (result && typeof result === "object" && "session" in result) {
893
+ return result.session;
894
+ }
895
+ return result;
896
+ }
856
897
  /**
857
898
  * Upload bytes to the hosted API's content-addressable asset endpoint.
858
899
  * Returns a storage-neutral asset id suitable for `kind:"asset"` refs in a
@@ -3,9 +3,9 @@ export declare const DEFAULT_POST_HOOK_TIMEOUT_MS: number;
3
3
  /** Default number of repair turns after a failing hook. */
4
4
  export declare const DEFAULT_POST_HOOK_MAX_TURNS = 10;
5
5
  /**
6
- * Customer-facing post-agent-run verifier shape. The SDK and run-config JSON
7
- * send this form on the wire; the server parser normalizes it to
8
- * {@link PlatformPostHook}.
6
+ * Legacy/private post-agent-run verifier input. The public SDK no longer
7
+ * accepts this field; platform-internal paths may still normalize old wire
8
+ * records to {@link PlatformPostHook}.
9
9
  */
10
10
  export interface PlatformPostHookInput {
11
11
  readonly command: string;
@@ -21,7 +21,7 @@ export interface PlatformPostHook {
21
21
  readonly maxChars: number | null;
22
22
  }
23
23
  /**
24
- * Parse the public `postHook` option. An omitted hook, null hook, or hook with
24
+ * Parse the legacy/private `postHook` option. An omitted hook, null hook, or hook with
25
25
  * an empty/whitespace-only command is treated as omitted so callers can pre-fill
26
26
  * configs without enabling the verifier accidentally.
27
27
  */
@@ -4,7 +4,7 @@ export const DEFAULT_POST_HOOK_TIMEOUT_MS = 5 * 60 * 1000;
4
4
  /** Default number of repair turns after a failing hook. */
5
5
  export const DEFAULT_POST_HOOK_MAX_TURNS = 10;
6
6
  /**
7
- * Parse the public `postHook` option. An omitted hook, null hook, or hook with
7
+ * Parse the legacy/private `postHook` option. An omitted hook, null hook, or hook with
8
8
  * an empty/whitespace-only command is treated as omitted so callers can pre-fill
9
9
  * configs without enabling the verifier accidentally.
10
10
  */
@@ -31,7 +31,6 @@
31
31
  import { type JsonValue, type PlatformProxyEndpoint, type PlatformEnvironment } from "./submission.js";
32
32
  import { type RunModel } from "./models.js";
33
33
  import type { RuntimeSize } from "./runtime-sizes.js";
34
- import { type PlatformPostHookInput } from "./post-hook.js";
35
34
  /**
36
35
  * Mirrors the server-side CHECK constraint
37
36
  * `skill_bundles_id_format_chk = check (id ~ '^skl_[A-Za-z0-9_-]{8,128}$')`
@@ -299,8 +298,6 @@ export interface RunRequestConfig {
299
298
  readonly runtimeSize?: RuntimeSize;
300
299
  /** Run deadline as a duration string (`"1h"`, `"30m"`); bounded [1m, 6h] server-side. */
301
300
  readonly timeout?: string;
302
- /** Post-agent-run verifier command. Empty command is treated as omitted. */
303
- readonly postHook?: PlatformPostHookInput;
304
301
  readonly proxyEndpoints?: readonly PlatformProxyEndpoint[];
305
302
  readonly metadata?: Readonly<Record<string, JsonValue>>;
306
303
  }
@@ -330,7 +327,6 @@ export interface NormalisedRunRequestConfig {
330
327
  readonly environment?: PlatformEnvironment;
331
328
  readonly proxyEndpoints?: readonly PlatformProxyEndpoint[];
332
329
  readonly metadata?: Readonly<Record<string, JsonValue>>;
333
- readonly postHook?: PlatformPostHookInput;
334
330
  /**
335
331
  * MCP servers whose run-config entry carried `headers`. Keyed by the `name`
336
332
  * that appears in `mcpServers` so the BFF can pair them up.
@@ -29,7 +29,6 @@
29
29
  * boundary.
30
30
  */
31
31
  import { parseRunModel } from "./models.js";
32
- import { parsePostHook } from "./post-hook.js";
33
32
  // ---------------------------------------------------------------------------
34
33
  // Skill ID + name format
35
34
  // ---------------------------------------------------------------------------
@@ -617,7 +616,6 @@ export function parseRunRequestConfig(input) {
617
616
  "environment",
618
617
  "runtimeSize",
619
618
  "timeout",
620
- "postHook",
621
619
  "proxyEndpoints",
622
620
  "metadata"
623
621
  ]);
@@ -634,7 +632,6 @@ export function parseRunRequestConfig(input) {
634
632
  const prompt = parseRunRequestConfigPrompt(record.prompt);
635
633
  const skills = parseRunRequestConfigSkills(record.skills);
636
634
  const mcpServers = parseRunRequestConfigMcpServers(record.mcpServers);
637
- const postHook = parsePostHook(record.postHook, "run request config postHook");
638
635
  return {
639
636
  model,
640
637
  ...(system !== undefined ? { system } : {}),
@@ -654,9 +651,6 @@ export function parseRunRequestConfig(input) {
654
651
  ...(record.timeout !== undefined
655
652
  ? { timeout: record.timeout }
656
653
  : {}),
657
- ...(postHook !== undefined
658
- ? { postHook: record.postHook }
659
- : {}),
660
654
  ...(record.proxyEndpoints !== undefined
661
655
  ? { proxyEndpoints: record.proxyEndpoints }
662
656
  : {}),
@@ -734,7 +728,6 @@ export function normaliseRunRequestConfig(config) {
734
728
  ...(config.environment !== undefined ? { environment: config.environment } : {}),
735
729
  ...(config.proxyEndpoints !== undefined ? { proxyEndpoints: config.proxyEndpoints } : {}),
736
730
  ...(config.metadata !== undefined ? { metadata: config.metadata } : {}),
737
- ...(config.postHook !== undefined ? { postHook: config.postHook } : {}),
738
731
  mcpServerSecrets
739
732
  };
740
733
  }
@@ -20,7 +20,7 @@
20
20
  * detail response stays bounded). The archive zip carries the bytes.
21
21
  */
22
22
  import { parseMcpServerRef, parseSkillRef } from "./run-config.js";
23
- import { RunModels, parseRunModel } from "./models.js";
23
+ import { Models, parseRunModel } from "./models.js";
24
24
  import { PLATFORM_PACKAGE_ECOSYSTEMS } from "./submission.js";
25
25
  // ---------------------------------------------------------------------------
26
26
  // Submission parser
@@ -105,7 +105,7 @@ function fallbackFlat() {
105
105
  return {
106
106
  kind: "submission",
107
107
  submission: {
108
- model: RunModels.CLAUDE_HAIKU_4_5,
108
+ model: Models.CLAUDE_HAIKU_4_5,
109
109
  prompt: [],
110
110
  skills: [],
111
111
  agentsMd: [],
@@ -125,12 +125,12 @@ function isRecord(value) {
125
125
  }
126
126
  function coerceRunUnitModel(value) {
127
127
  if (typeof value !== "string")
128
- return RunModels.CLAUDE_HAIKU_4_5;
128
+ return Models.CLAUDE_HAIKU_4_5;
129
129
  try {
130
130
  return parseRunModel(value, "run unit submission.model");
131
131
  }
132
132
  catch {
133
- return RunModels.CLAUDE_HAIKU_4_5;
133
+ return Models.CLAUDE_HAIKU_4_5;
134
134
  }
135
135
  }
136
136
  function isJsonRecord(value) {