@aexhq/sdk 0.26.5 → 0.28.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.
@@ -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, Run, RunEvent, 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, 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
@@ -27,6 +27,16 @@ export declare function getRun(http: HttpClient, runId: string): Promise<Run>;
27
27
  * stays for callers that only need the loose record.
28
28
  */
29
29
  export declare function getRunUnit(http: HttpClient, runId: string): Promise<RunUnit>;
30
+ /**
31
+ * List the runs in the token's workspace, most-recent first, one page at a time.
32
+ * Backed by `GET /api/runs` (workspace-token gated; the bare collection path, NOT
33
+ * the run-keyed `GET /api/runs/:runId`). The server clamps `limit` to [1, 100] and
34
+ * returns an opaque `nextCursor` for the next page (absent on the last page).
35
+ *
36
+ * Returns public-safe {@link RunSummary} rows only — never the submission snapshot.
37
+ * For a single page; callers wanting every run loop on `nextCursor` themselves.
38
+ */
39
+ export declare function listRuns(http: HttpClient, query?: RunListQuery): Promise<RunListPage>;
30
40
  /**
31
41
  * List a run's events. The read endpoint is PAGED (bounded per response so a
32
42
  * long run can't return an unbounded body); this follows `nextCursor` across
@@ -56,6 +66,20 @@ export declare function createOutputLink(http: HttpClient, runId: string, select
56
66
  export declare function eventArchiveLink(http: HttpClient, runId: string, options?: OutputLinkOptions): Promise<OutputLink>;
57
67
  export declare function resolveOutputFileSelector(outputs: readonly Output[], selector: OutputFileSelector, runId?: string): Output;
58
68
  export declare function downloadOutput(http: HttpClient, runId: string, selector: OutputFileSelector): Promise<OutputFileDownload>;
69
+ /** Byte ceiling for {@link readOutputText} — a hard cap even if a caller asks for more. */
70
+ export declare const READ_OUTPUT_TEXT_MAX_BYTES = 10000000;
71
+ /** Default `maxBytes` for {@link readOutputText} — a chat-sized preview. */
72
+ export declare const READ_OUTPUT_TEXT_DEFAULT_BYTES = 50000;
73
+ /**
74
+ * Read ONE output file as byte-capped, decoded UTF-8 text. Built for handing a run
75
+ * deliverable to an LLM tool: it streams the file body and STOPS at `maxBytes`, so
76
+ * a 200 MB artifact never fully buffers in memory or context. `truncated` is true
77
+ * when the file is larger than the cap. Optionally `grep` keeps only matching lines.
78
+ *
79
+ * Selector is the same `{ path }` / `{ id }` shape as `downloadOutput`. A path
80
+ * selector lists the run's outputs to resolve the id; an id selector skips that.
81
+ */
82
+ export declare function readOutputText(http: HttpClient, runId: string, selector: OutputFileSelector, options?: ReadOutputTextOptions): Promise<OutputText>;
59
83
  export declare function cancelRun(http: HttpClient, runId: string): Promise<void>;
60
84
  export declare function deleteRun(http: HttpClient, runId: string): Promise<void>;
61
85
  /**
@@ -31,6 +31,27 @@ export async function getRun(http, runId) {
31
31
  export async function getRunUnit(http, runId) {
32
32
  return http.request(`/api/runs/${encodeURIComponent(runId)}`);
33
33
  }
34
+ /**
35
+ * List the runs in the token's workspace, most-recent first, one page at a time.
36
+ * Backed by `GET /api/runs` (workspace-token gated; the bare collection path, NOT
37
+ * the run-keyed `GET /api/runs/:runId`). The server clamps `limit` to [1, 100] and
38
+ * returns an opaque `nextCursor` for the next page (absent on the last page).
39
+ *
40
+ * Returns public-safe {@link RunSummary} rows only — never the submission snapshot.
41
+ * For a single page; callers wanting every run loop on `nextCursor` themselves.
42
+ */
43
+ export async function listRuns(http, query) {
44
+ const params = {};
45
+ if (query?.status !== undefined)
46
+ params.status = query.status;
47
+ if (query?.since !== undefined)
48
+ params.since = query.since;
49
+ if (query?.limit !== undefined)
50
+ params.limit = String(query.limit);
51
+ if (query?.cursor !== undefined)
52
+ params.cursor = query.cursor;
53
+ return http.request("/api/runs", {}, params);
54
+ }
34
55
  // Bound the transparent pager: the read route caps each page at 1000, so this
35
56
  // admits up to ~1e6 events before bailing — past any real run, but bounded so a
36
57
  // server that never clears `nextCursor` can't loop forever.
@@ -146,6 +167,100 @@ export async function downloadOutput(http, runId, selector) {
146
167
  const { response } = await http.download(`/api/runs/${encodeURIComponent(runId)}/outputs/${encodeURIComponent(output.id)}/download`);
147
168
  return { output, bytes: new Uint8Array(await response.arrayBuffer()) };
148
169
  }
170
+ /** Byte ceiling for {@link readOutputText} — a hard cap even if a caller asks for more. */
171
+ export const READ_OUTPUT_TEXT_MAX_BYTES = 10_000_000;
172
+ /** Default `maxBytes` for {@link readOutputText} — a chat-sized preview. */
173
+ export const READ_OUTPUT_TEXT_DEFAULT_BYTES = 50_000;
174
+ /**
175
+ * Read ONE output file as byte-capped, decoded UTF-8 text. Built for handing a run
176
+ * deliverable to an LLM tool: it streams the file body and STOPS at `maxBytes`, so
177
+ * a 200 MB artifact never fully buffers in memory or context. `truncated` is true
178
+ * when the file is larger than the cap. Optionally `grep` keeps only matching lines.
179
+ *
180
+ * Selector is the same `{ path }` / `{ id }` shape as `downloadOutput`. A path
181
+ * selector lists the run's outputs to resolve the id; an id selector skips that.
182
+ */
183
+ export async function readOutputText(http, runId, selector, options) {
184
+ const maxBytes = Math.max(1, Math.min(options?.maxBytes ?? READ_OUTPUT_TEXT_DEFAULT_BYTES, READ_OUTPUT_TEXT_MAX_BYTES));
185
+ const output = isPathSelector(selector)
186
+ ? resolveOutputFileSelector(await listOutputs(http, runId), selector, runId)
187
+ : resolveOutputFileSelector([], selector, runId);
188
+ const { response } = await http.download(`/api/runs/${encodeURIComponent(runId)}/outputs/${encodeURIComponent(output.id)}/download`);
189
+ const capped = await readCappedText(response, maxBytes);
190
+ const text = options?.grep === undefined ? capped.text : grepLines(capped.text, options.grep);
191
+ return { output, text, truncated: capped.truncated, totalBytes: capped.totalBytes };
192
+ }
193
+ /**
194
+ * Read a streamed response body up to `maxBytes`, decode as UTF-8, and report
195
+ * whether the file was larger than the cap. Prefers the `content-length` header
196
+ * for `totalBytes`; falls back to the bytes actually read. Cancels the stream
197
+ * once the cap is reached so the remainder is never transferred.
198
+ */
199
+ async function readCappedText(response, maxBytes) {
200
+ const declaredRaw = response.headers.get("content-length");
201
+ const declared = declaredRaw !== null && /^\d+$/.test(declaredRaw) ? Number(declaredRaw) : undefined;
202
+ const decoder = new TextDecoder("utf-8");
203
+ const body = response.body;
204
+ if (!body) {
205
+ // No streaming body (some fetch polyfills) — buffer, then slice to the cap.
206
+ const buf = new Uint8Array(await response.arrayBuffer());
207
+ const total = declared ?? buf.byteLength;
208
+ return {
209
+ text: decoder.decode(buf.subarray(0, maxBytes)),
210
+ truncated: buf.byteLength > maxBytes,
211
+ totalBytes: total
212
+ };
213
+ }
214
+ const reader = body.getReader();
215
+ const chunks = [];
216
+ let read = 0;
217
+ let sawMore = false;
218
+ try {
219
+ while (read < maxBytes) {
220
+ const { done, value } = await reader.read();
221
+ if (done)
222
+ break;
223
+ if (value && value.byteLength > 0) {
224
+ read += value.byteLength;
225
+ chunks.push(value);
226
+ }
227
+ }
228
+ if (read >= maxBytes) {
229
+ // We hit the cap; peek once more to learn whether bytes remain, then stop.
230
+ const next = await reader.read();
231
+ if (!next.done && next.value && next.value.byteLength > 0)
232
+ sawMore = true;
233
+ }
234
+ }
235
+ finally {
236
+ await reader.cancel().catch(() => { });
237
+ }
238
+ const merged = concatBytes(chunks).subarray(0, maxBytes);
239
+ const truncated = declared !== undefined ? declared > maxBytes : sawMore;
240
+ const totalBytes = declared ?? read;
241
+ return { text: decoder.decode(merged), truncated, totalBytes };
242
+ }
243
+ function concatBytes(chunks) {
244
+ if (chunks.length === 1)
245
+ return chunks[0];
246
+ const total = chunks.reduce((n, c) => n + c.byteLength, 0);
247
+ const out = new Uint8Array(total);
248
+ let offset = 0;
249
+ for (const c of chunks) {
250
+ out.set(c, offset);
251
+ offset += c.byteLength;
252
+ }
253
+ return out;
254
+ }
255
+ function grepLines(text, pattern) {
256
+ const test = typeof pattern === "string"
257
+ ? (line) => line.toLowerCase().includes(pattern.toLowerCase())
258
+ : (line) => pattern.test(line);
259
+ return text
260
+ .split("\n")
261
+ .filter((line) => test(line))
262
+ .join("\n");
263
+ }
149
264
  export async function cancelRun(http, runId) {
150
265
  await http.request(`/api/runs/${encodeURIComponent(runId)}/cancel`, { method: "POST" });
151
266
  }
@@ -45,6 +45,40 @@ export interface UsageSummary {
45
45
  readonly cacheCreationInputTokens?: number;
46
46
  readonly totalTokens?: number;
47
47
  }
48
+ /**
49
+ * Filters for {@link import("./operations.js").listRuns} / `AgentExecutor.listRuns`.
50
+ * Every field is optional; omitting all of them lists the most recent runs in the
51
+ * token's workspace. Workspace identity is derived server-side from the API token,
52
+ * so there is no `workspaceId` here — a token can only ever enumerate its own runs.
53
+ */
54
+ export interface RunListQuery {
55
+ /** Restrict to a single run status, e.g. `"succeeded"`. */
56
+ readonly status?: string;
57
+ /** ISO-8601 lower bound on `createdAt` (inclusive). */
58
+ readonly since?: string;
59
+ /** Page size. Defaults to 25, clamped server-side to [1, 100]. */
60
+ readonly limit?: number;
61
+ /** Opaque keyset cursor from a prior page's `nextCursor`. */
62
+ readonly cursor?: string;
63
+ }
64
+ /**
65
+ * A public-safe run summary as returned by `GET /api/runs` (the workspace run
66
+ * list). DELIBERATELY omits the submission snapshot (model/prompt/env) — the full,
67
+ * redaction-scanned submission is only reachable through `getRunUnit(runId)`.
68
+ */
69
+ export interface RunSummary {
70
+ readonly id: string;
71
+ readonly status: string;
72
+ readonly createdAt: string;
73
+ readonly updatedAt: string;
74
+ /** Settled showback estimate (USD), present once the run has cost telemetry. */
75
+ readonly costUsd?: number;
76
+ }
77
+ /** One page of the workspace run list. `nextCursor` absent ⇒ last page. */
78
+ export interface RunListPage {
79
+ readonly runs: readonly RunSummary[];
80
+ readonly nextCursor?: string;
81
+ }
48
82
  /**
49
83
  * A run event as recorded by the dashboard. Includes the `type` field
50
84
  * that the `is*Event` type guards narrow on plus any provider payload.
@@ -150,6 +184,39 @@ export interface OutputFileDownload {
150
184
  readonly output: Output;
151
185
  readonly bytes: Uint8Array;
152
186
  }
187
+ /** Options for `AgentExecutor.readOutputText` / {@link import("./operations.js").readOutputText}. */
188
+ export interface ReadOutputTextOptions {
189
+ /**
190
+ * Stop reading after this many bytes. Defaults to 50_000; clamped server-side
191
+ * of the SDK to [1, 10_000_000]. The read streams and cancels once the cap is
192
+ * reached, so the remainder of a large file is never transferred.
193
+ */
194
+ readonly maxBytes?: number;
195
+ /**
196
+ * When set, return only the lines of the (capped) text matching this pattern.
197
+ * A string is matched literally (case-insensitive); a RegExp is used as given.
198
+ */
199
+ readonly grep?: string | RegExp;
200
+ }
201
+ /**
202
+ * A byte-capped, decoded text read of one output file, as returned by
203
+ * `AgentExecutor.readOutputText`. Built for feeding run deliverables to an LLM
204
+ * without loading the whole (possibly very large) file into memory or context:
205
+ * the read streams and stops at `maxBytes`, so `text` is at most that many bytes
206
+ * decoded as UTF-8. Check {@link truncated} before treating `text` as complete.
207
+ */
208
+ export interface OutputText {
209
+ readonly output: Output;
210
+ /** Decoded UTF-8, capped to the requested `maxBytes`. */
211
+ readonly text: string;
212
+ /** True when the file is larger than `maxBytes` (so `text` is a prefix). */
213
+ readonly truncated: boolean;
214
+ /**
215
+ * Full size of the file in bytes when the server reports it (`content-length`);
216
+ * otherwise the number of bytes actually read.
217
+ */
218
+ readonly totalBytes: number;
219
+ }
153
220
  export type OutputLinkExpiresIn = number | "15m" | "1h" | "1d";
154
221
  export interface OutputLinkOptions {
155
222
  /** Seconds or one of the documented presets. Defaults to `"1h"`. */
@@ -354,23 +354,24 @@ export interface PlatformSubmission {
354
354
  */
355
355
  readonly outputs?: PlatformOutputCaptureConfig;
356
356
  /**
357
- * Optional override for the managed-runtime builtins enabled inside the
358
- * runner container. Each entry is one of the closed {@link BUILTINS} set
359
- * (prefer the {@link Builtins} symbol const).
357
+ * Whether to inject the standard builtin tool set ({@link DEFAULT_BUILTIN_TOOLS}).
360
358
  *
361
- * Omit the field for {@link DEFAULT_BUILTINS}: web search, web fetch,
362
- * file read/edit, glob, grep, head, and tail. Pass an empty array to opt out
363
- * of all builtins for pure-MCP runs. Pass a custom list to narrow or extend
364
- * the tool surface, for example `[Builtins.WEB_SEARCH, Builtins.NOTEBOOK]`.
359
+ * - omitted / `true` (default): inject the standard builtins.
360
+ * - `false`: inject NO builtins useful for a pure-MCP / pure-custom run.
365
361
  *
366
- * Validation:
367
- * - Each entry must be a member of {@link BUILTINS}.
368
- * - Max 16 entries.
369
- * - Deduplicated.
370
- *
371
- * The dispatcher accepts and persists it for snapshot fidelity.
362
+ * Cherry-pick individual builtins (e.g. opt the notebook in, or pick a narrow
363
+ * subset alongside `includeBuiltinTools: false`) by listing their names in
364
+ * `tools` (a bare-string builtin reference, prefer `BuiltinTools.<name>`).
365
+ */
366
+ readonly includeBuiltinTools?: boolean;
367
+ /**
368
+ * Explicit builtin tool NAME references the caller listed in the wire `tools`
369
+ * union (the bare-string members), extracted at parse time. Each is a member
370
+ * of {@link BUILTIN_TOOL_NAMES}. Composed with {@link includeBuiltinTools} via
371
+ * {@link resolveBuiltinToolNames} to produce the run's final builtin tool set.
372
+ * `tools` itself carries only the custom tool bundles ({@link ToolRef}).
372
373
  */
373
- readonly builtins?: readonly Builtin[];
374
+ readonly builtinTools?: readonly BuiltinToolName[];
374
375
  /**
375
376
  * Assistant-output granularity. `buffered` (the default) emits one event per
376
377
  * assistant message; `stream` emits the agent's per-token text deltas as they
@@ -484,11 +485,30 @@ export interface PlatformRunSubmissionRequest {
484
485
  * callback URL never 409s and the field never enters `request_hash`.
485
486
  */
486
487
  readonly webhook?: RunWebhookSpec;
488
+ /**
489
+ * Optional per-run override of the lineage limits (max concurrent child runs,
490
+ * max subagent depth). A sibling of {@link parentRunId} — these are dials the
491
+ * client may *request*; the server resolves them against the per-workspace
492
+ * ceiling and the hard platform ceiling (clamping happens in the resolver, NOT
493
+ * this parser). Absent fields fall back to the platform defaults. Only shape +
494
+ * positivity are validated here.
495
+ */
496
+ readonly limits?: RunLimits;
487
497
  }
488
498
  /** Per-run webhook callback. v1: terminal-only; the URL must be https. */
489
499
  export interface RunWebhookSpec {
490
500
  readonly url: string;
491
501
  }
502
+ /**
503
+ * Per-run override of the lineage limits. Both fields are optional; an absent
504
+ * field means "use the platform default". The parser ({@link parseRunLimits})
505
+ * only validates positivity/shape — clamping to the workspace + platform
506
+ * ceilings is the resolver's job (see `resolveRunLimits` in `@aexhq/shared`).
507
+ */
508
+ export interface RunLimits {
509
+ readonly maxConcurrentChildRuns?: number;
510
+ readonly maxSubagentDepth?: number;
511
+ }
492
512
  /**
493
513
  * Wire shape posted by the SDK and CLI. `workspaceId` is **omitted by
494
514
  * design** — token-authenticated clients never name the workspace
@@ -537,6 +557,18 @@ export declare function parseRunSubmissionRequest(input: unknown, options?: Pars
537
557
  * is the submit-time shape gate.
538
558
  */
539
559
  export declare function parseRunWebhook(input: unknown): RunWebhookSpec | undefined;
560
+ /**
561
+ * Parse the optional per-run `limits` override. Mirrors {@link parseRunWebhook}:
562
+ * absent ⇒ `undefined`; a non-object or any unknown subfield is rejected so the
563
+ * strict top-level allow-list extends to the nested object. Each present field
564
+ * is validated as a positive safe integer via {@link optionalPositiveInt}.
565
+ *
566
+ * This is a SHAPE/positivity gate only — it does NOT clamp to the workspace or
567
+ * platform ceilings (that precedence lives in the resolver, `resolveRunLimits`).
568
+ * Only the present fields are returned; an all-absent override (e.g. `{}`)
569
+ * collapses to `undefined` so it carries no signal onto the request.
570
+ */
571
+ export declare function parseRunLimits(input: unknown): RunLimits | undefined;
540
572
  export declare function parseRunRegion(input: unknown): RunRegion | undefined;
541
573
  export declare function parseRuntimeKind(input: unknown): RuntimeKind | undefined;
542
574
  export declare function parseRunProvider(input: unknown): RunProvider;
@@ -561,56 +593,69 @@ export declare const OUTPUT_MODES: readonly ["buffered", "stream"];
561
593
  export type OutputMode = (typeof OUTPUT_MODES)[number];
562
594
  export declare const DEFAULT_OUTPUT_MODE: OutputMode;
563
595
  /**
564
- * Managed-runtime builtins the closed set the managed runtime accepts.
565
- * Closed so an invalid name is a compile error via {@link Builtins}, not a
566
- * silent runtime no-op.
596
+ * The CLOSED set of builtin tool NAMES the managed runtime can inject — one per
597
+ * machine tool the hands implement. This list is the single source of truth for
598
+ * validating builtin tool references; the platform's `HANDS_TOOLS` (the execute
599
+ * vocabulary) is pinned EQUAL to it at module load (`platform-runtime-agent`
600
+ * `assertNamesMatch`), so a rename on either side fails loudly rather than
601
+ * silently shipping a name the executors do not speak.
567
602
  *
568
- * The first entries are the recommended concrete builtins. The legacy aggregate
569
- * extension names remain accepted for existing callers, but are not the default.
570
- */
571
- export declare const BUILTINS: readonly ["web_search", "web_fetch", "read", "edit", "glob", "grep", "head", "tail", "bash", "notebook", "developer", "computercontroller", "memory", "autovisualiser", "tutorial"];
572
- export type Builtin = (typeof BUILTINS)[number];
573
- /**
574
- * DX-first managed-runtime defaults. Omitted `builtins` resolves to this list.
575
- * Notebook support remains opt-in through {@link Builtins.NOTEBOOK}.
576
- */
577
- export declare const DEFAULT_BUILTINS: readonly ["web_search", "web_fetch", "read", "edit", "glob", "grep", "head", "tail", "bash"];
578
- /**
579
- * Symbol-style accessors for the closed builtin set, e.g.
580
- * `Builtins.WEB_SEARCH`.
581
- */
582
- export declare const Builtins: {
583
- /** Managed web search. Included in {@link DEFAULT_BUILTINS}. */
584
- readonly WEB_SEARCH: "web_search";
585
- /** Fetch a URL and return readable text. Included in {@link DEFAULT_BUILTINS}. */
586
- readonly WEB_FETCH: "web_fetch";
587
- /** Read files. Included in {@link DEFAULT_BUILTINS}. */
588
- readonly READ: "read";
589
- /** Create/modify files. Included in {@link DEFAULT_BUILTINS}. */
590
- readonly EDIT: "edit";
591
- /** Search paths by glob. Included in {@link DEFAULT_BUILTINS}. */
592
- readonly GLOB: "glob";
593
- /** Search file contents. Included in {@link DEFAULT_BUILTINS}. */
594
- readonly GREP: "grep";
595
- /** Read the first lines of a file. Included in {@link DEFAULT_BUILTINS}. */
596
- readonly HEAD: "head";
597
- /** Read the last lines of a file. Included in {@link DEFAULT_BUILTINS}. */
598
- readonly TAIL: "tail";
599
- /** Shell command execution. Included in {@link DEFAULT_BUILTINS}. */
600
- readonly BASH: "bash";
601
- /** Jupyter notebook editing. Optional; not in {@link DEFAULT_BUILTINS}. */
602
- readonly NOTEBOOK: "notebook";
603
- /** Legacy aggregate: shell/filesystem/navigation/web/notebook tools. */
604
- readonly DEVELOPER: "developer";
605
- /** Legacy aggregate alias retained for existing callers. */
606
- readonly COMPUTER_CONTROLLER: "computercontroller";
607
- /** Legacy aggregate alias retained for existing callers. */
608
- readonly MEMORY: "memory";
609
- /** Legacy aggregate alias retained for existing callers. */
610
- readonly AUTOVISUALISER: "autovisualiser";
611
- /** Legacy aggregate alias retained for existing callers. */
612
- readonly TUTORIAL: "tutorial";
603
+ * Order mirrors `HANDS_TOOLS`. A builtin tool reference (a bare string in
604
+ * `submission.tools`) must be a member of this set.
605
+ */
606
+ export declare const BUILTIN_TOOL_NAMES: readonly ["bash", "read_file", "write_file", "edit_file", "grep", "glob", "head", "tail", "todo_write", "subagent", "subagent_result", "web_fetch", "web_search", "notebook_edit", "bash_output", "bash_kill", "code_execution", "wait", "git"];
607
+ export type BuiltinToolName = (typeof BUILTIN_TOOL_NAMES)[number];
608
+ /**
609
+ * Typo-safe accessors for the closed builtin tool set: each key maps to the
610
+ * real tool NAME string. Reference a builtin in `submission.tools` via
611
+ * `BuiltinTools.notebook_edit` rather than the bare string so a rename is a
612
+ * compile error, not a runtime 400.
613
+ *
614
+ * Keys are the real tool names; a unit test asserts `Object.values(BuiltinTools)`
615
+ * deep-equals `BUILTIN_TOOL_NAMES` so the two can never drift.
616
+ */
617
+ export declare const BuiltinTools: {
618
+ readonly bash: "bash";
619
+ readonly read_file: "read_file";
620
+ readonly write_file: "write_file";
621
+ readonly edit_file: "edit_file";
622
+ readonly grep: "grep";
623
+ readonly glob: "glob";
624
+ readonly head: "head";
625
+ readonly tail: "tail";
626
+ readonly todo_write: "todo_write";
627
+ readonly subagent: "subagent";
628
+ readonly subagent_result: "subagent_result";
629
+ readonly web_fetch: "web_fetch";
630
+ readonly web_search: "web_search";
631
+ readonly notebook_edit: "notebook_edit";
632
+ readonly bash_output: "bash_output";
633
+ readonly bash_kill: "bash_kill";
634
+ readonly code_execution: "code_execution";
635
+ readonly wait: "wait";
636
+ readonly git: "git";
613
637
  };
638
+ /**
639
+ * The default builtin tool set injected when `includeBuiltinTools !== false`:
640
+ * every builtin tool EXCEPT `notebook_edit` (notebook editing stays opt-in —
641
+ * add `BuiltinTools.notebook_edit` to `tools` to enable it). Derived by
642
+ * filtering {@link BUILTIN_TOOL_NAMES} so it can never drift from the closed
643
+ * set.
644
+ */
645
+ export declare const DEFAULT_BUILTIN_TOOLS: readonly BuiltinToolName[];
646
+ /**
647
+ * Resolve the set of builtin tool NAMES a submission injects, deduplicated and
648
+ * in {@link BUILTIN_TOOL_NAMES} order.
649
+ *
650
+ * - `includeBuiltinTools !== false` ⇒ start from {@link DEFAULT_BUILTIN_TOOLS}
651
+ * (the standard set); `false` ⇒ start from none (pure-MCP / pure-custom).
652
+ * - union in every builtin-name string the caller listed in `tools` (a
653
+ * cherry-pick, e.g. `BuiltinTools.notebook_edit` to opt the notebook in).
654
+ *
655
+ * Every `toolRefs` string MUST be a member of {@link BUILTIN_TOOL_NAMES}; the
656
+ * union is validated ⊆ the closed set so an invalid name can never leak through.
657
+ */
658
+ export declare function resolveBuiltinToolNames(includeBuiltinTools: boolean | undefined, toolRefs?: readonly string[]): readonly BuiltinToolName[];
614
659
  /**
615
660
  * Codes emitted when a submission contains features the active runtime cannot
616
661
  * serve. Code values are stable so dashboard / SDK error rendering can branch