@aexhq/sdk 0.26.5 → 0.27.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.
@@ -1233,7 +1233,7 @@ export function parseSubmission(input) {
1233
1233
  "securityProfile",
1234
1234
  "metadata",
1235
1235
  "outputs",
1236
- "builtins",
1236
+ "includeBuiltinTools",
1237
1237
  "outputMode",
1238
1238
  "platform"
1239
1239
  ]);
@@ -1246,7 +1246,7 @@ export function parseSubmission(input) {
1246
1246
  const system = optionalString(value.system, "submission.system");
1247
1247
  const prompt = parsePrompt(value.prompt);
1248
1248
  const skills = parseSkills(value.skills);
1249
- const tools = parseTools(value.tools);
1249
+ const { tools, builtinTools } = parseTools(value.tools);
1250
1250
  const agentsMd = parseAgentsMd(value.agentsMd);
1251
1251
  const files = parseFiles(value.files);
1252
1252
  const mcpServers = parseMcpServers(value.mcpServers);
@@ -1255,7 +1255,7 @@ export function parseSubmission(input) {
1255
1255
  const securityProfile = parseRuntimeSecurityProfile(value.securityProfile);
1256
1256
  const metadata = optionalJsonRecord(value.metadata, "submission.metadata");
1257
1257
  const outputs = parseOutputs(value.outputs);
1258
- const builtins = parseBuiltins(value.builtins);
1258
+ const includeBuiltinTools = parseIncludeBuiltinTools(value.includeBuiltinTools);
1259
1259
  const outputMode = parseOutputMode(value.outputMode);
1260
1260
  const platform = parsePlatformConfig(value.platform);
1261
1261
  return {
@@ -1272,7 +1272,8 @@ export function parseSubmission(input) {
1272
1272
  ...(securityProfile ? { securityProfile } : {}),
1273
1273
  ...(metadata ? { metadata } : {}),
1274
1274
  ...(outputs ? { outputs } : {}),
1275
- ...(builtins !== undefined ? { builtins } : {}),
1275
+ ...(includeBuiltinTools !== undefined ? { includeBuiltinTools } : {}),
1276
+ ...(builtinTools.length > 0 ? { builtinTools } : {}),
1276
1277
  ...(outputMode !== undefined ? { outputMode } : {}),
1277
1278
  ...(platform ? { platform } : {})
1278
1279
  };
@@ -1336,108 +1337,105 @@ function parseOutputMode(input) {
1336
1337
  return input;
1337
1338
  }
1338
1339
  /**
1339
- * Managed-runtime builtins the closed set the managed runtime accepts.
1340
- * Closed so an invalid name is a compile error via {@link Builtins}, not a
1341
- * silent runtime no-op.
1340
+ * The CLOSED set of builtin tool NAMES the managed runtime can inject — one per
1341
+ * machine tool the hands implement. This list is the single source of truth for
1342
+ * validating builtin tool references; the platform's `HANDS_TOOLS` (the execute
1343
+ * vocabulary) is pinned EQUAL to it at module load (`platform-runtime-agent`
1344
+ * `assertNamesMatch`), so a rename on either side fails loudly rather than
1345
+ * silently shipping a name the executors do not speak.
1342
1346
  *
1343
- * The first entries are the recommended concrete builtins. The legacy aggregate
1344
- * extension names remain accepted for existing callers, but are not the default.
1347
+ * Order mirrors `HANDS_TOOLS`. A builtin tool reference (a bare string in
1348
+ * `submission.tools`) must be a member of this set.
1345
1349
  */
1346
- export const BUILTINS = [
1347
- "web_search",
1348
- "web_fetch",
1349
- "read",
1350
- "edit",
1351
- "glob",
1352
- "grep",
1353
- "head",
1354
- "tail",
1350
+ export const BUILTIN_TOOL_NAMES = [
1355
1351
  "bash",
1356
- "notebook",
1357
- "developer",
1358
- "computercontroller",
1359
- "memory",
1360
- "autovisualiser",
1361
- "tutorial"
1362
- ];
1363
- /**
1364
- * DX-first managed-runtime defaults. Omitted `builtins` resolves to this list.
1365
- * Notebook support remains opt-in through {@link Builtins.NOTEBOOK}.
1366
- */
1367
- export const DEFAULT_BUILTINS = [
1368
- "web_search",
1369
- "web_fetch",
1370
- "read",
1371
- "edit",
1372
- "glob",
1352
+ "read_file",
1353
+ "write_file",
1354
+ "edit_file",
1373
1355
  "grep",
1356
+ "glob",
1374
1357
  "head",
1375
1358
  "tail",
1376
- "bash"
1359
+ "todo_write",
1360
+ "subagent",
1361
+ "subagent_result",
1362
+ "web_fetch",
1363
+ "web_search",
1364
+ "notebook_edit",
1365
+ "bash_output",
1366
+ "bash_kill",
1367
+ "code_execution",
1368
+ "wait",
1369
+ "git"
1377
1370
  ];
1378
1371
  /**
1379
- * Symbol-style accessors for the closed builtin set, e.g.
1380
- * `Builtins.WEB_SEARCH`.
1372
+ * Typo-safe accessors for the closed builtin tool set: each key maps to the
1373
+ * real tool NAME string. Reference a builtin in `submission.tools` via
1374
+ * `BuiltinTools.notebook_edit` rather than the bare string so a rename is a
1375
+ * compile error, not a runtime 400.
1376
+ *
1377
+ * Keys are the real tool names; a unit test asserts `Object.values(BuiltinTools)`
1378
+ * deep-equals `BUILTIN_TOOL_NAMES` so the two can never drift.
1381
1379
  */
1382
- export const Builtins = {
1383
- /** Managed web search. Included in {@link DEFAULT_BUILTINS}. */
1384
- WEB_SEARCH: "web_search",
1385
- /** Fetch a URL and return readable text. Included in {@link DEFAULT_BUILTINS}. */
1386
- WEB_FETCH: "web_fetch",
1387
- /** Read files. Included in {@link DEFAULT_BUILTINS}. */
1388
- READ: "read",
1389
- /** Create/modify files. Included in {@link DEFAULT_BUILTINS}. */
1390
- EDIT: "edit",
1391
- /** Search paths by glob. Included in {@link DEFAULT_BUILTINS}. */
1392
- GLOB: "glob",
1393
- /** Search file contents. Included in {@link DEFAULT_BUILTINS}. */
1394
- GREP: "grep",
1395
- /** Read the first lines of a file. Included in {@link DEFAULT_BUILTINS}. */
1396
- HEAD: "head",
1397
- /** Read the last lines of a file. Included in {@link DEFAULT_BUILTINS}. */
1398
- TAIL: "tail",
1399
- /** Shell command execution. Included in {@link DEFAULT_BUILTINS}. */
1400
- BASH: "bash",
1401
- /** Jupyter notebook editing. Optional; not in {@link DEFAULT_BUILTINS}. */
1402
- NOTEBOOK: "notebook",
1403
- /** Legacy aggregate: shell/filesystem/navigation/web/notebook tools. */
1404
- DEVELOPER: "developer",
1405
- /** Legacy aggregate alias retained for existing callers. */
1406
- COMPUTER_CONTROLLER: "computercontroller",
1407
- /** Legacy aggregate alias retained for existing callers. */
1408
- MEMORY: "memory",
1409
- /** Legacy aggregate alias retained for existing callers. */
1410
- AUTOVISUALISER: "autovisualiser",
1411
- /** Legacy aggregate alias retained for existing callers. */
1412
- TUTORIAL: "tutorial"
1380
+ export const BuiltinTools = {
1381
+ bash: "bash",
1382
+ read_file: "read_file",
1383
+ write_file: "write_file",
1384
+ edit_file: "edit_file",
1385
+ grep: "grep",
1386
+ glob: "glob",
1387
+ head: "head",
1388
+ tail: "tail",
1389
+ todo_write: "todo_write",
1390
+ subagent: "subagent",
1391
+ subagent_result: "subagent_result",
1392
+ web_fetch: "web_fetch",
1393
+ web_search: "web_search",
1394
+ notebook_edit: "notebook_edit",
1395
+ bash_output: "bash_output",
1396
+ bash_kill: "bash_kill",
1397
+ code_execution: "code_execution",
1398
+ wait: "wait",
1399
+ git: "git"
1413
1400
  };
1414
- const MAX_BUILTINS = 16;
1415
- function parseBuiltins(input) {
1401
+ /**
1402
+ * The default builtin tool set injected when `includeBuiltinTools !== false`:
1403
+ * every builtin tool EXCEPT `notebook_edit` (notebook editing stays opt-in —
1404
+ * add `BuiltinTools.notebook_edit` to `tools` to enable it). Derived by
1405
+ * filtering {@link BUILTIN_TOOL_NAMES} so it can never drift from the closed
1406
+ * set.
1407
+ */
1408
+ export const DEFAULT_BUILTIN_TOOLS = BUILTIN_TOOL_NAMES.filter((name) => name !== "notebook_edit");
1409
+ /**
1410
+ * Resolve the set of builtin tool NAMES a submission injects, deduplicated and
1411
+ * in {@link BUILTIN_TOOL_NAMES} order.
1412
+ *
1413
+ * - `includeBuiltinTools !== false` ⇒ start from {@link DEFAULT_BUILTIN_TOOLS}
1414
+ * (the standard set); `false` ⇒ start from none (pure-MCP / pure-custom).
1415
+ * - union in every builtin-name string the caller listed in `tools` (a
1416
+ * cherry-pick, e.g. `BuiltinTools.notebook_edit` to opt the notebook in).
1417
+ *
1418
+ * Every `toolRefs` string MUST be a member of {@link BUILTIN_TOOL_NAMES}; the
1419
+ * union is validated ⊆ the closed set so an invalid name can never leak through.
1420
+ */
1421
+ export function resolveBuiltinToolNames(includeBuiltinTools, toolRefs) {
1422
+ const enabled = new Set(includeBuiltinTools !== false ? DEFAULT_BUILTIN_TOOLS : []);
1423
+ for (const ref of toolRefs ?? []) {
1424
+ if (!BUILTIN_TOOL_NAMES.includes(ref)) {
1425
+ throw new Error(`${JSON.stringify(ref)} is not a builtin tool; expected one of: ${BUILTIN_TOOL_NAMES.join(", ")}`);
1426
+ }
1427
+ enabled.add(ref);
1428
+ }
1429
+ return BUILTIN_TOOL_NAMES.filter((name) => enabled.has(name));
1430
+ }
1431
+ /** Validate the optional `includeBuiltinTools` flag (default `true`). */
1432
+ function parseIncludeBuiltinTools(input) {
1416
1433
  if (input === undefined || input === null)
1417
1434
  return undefined;
1418
- if (!Array.isArray(input)) {
1419
- throw new Error("submission.builtins must be an array of strings");
1420
- }
1421
- if (input.length > MAX_BUILTINS) {
1422
- throw new Error(`submission.builtins exceeds the max of ${MAX_BUILTINS} entries`);
1423
- }
1424
- const seen = new Set();
1425
- const out = [];
1426
- for (let i = 0; i < input.length; i++) {
1427
- const v = input[i];
1428
- if (typeof v !== "string") {
1429
- throw new Error(`submission.builtins[${i}] must be a string`);
1430
- }
1431
- if (!BUILTINS.includes(v)) {
1432
- throw new Error(`submission.builtins[${i}] (${JSON.stringify(v)}) is not a managed-runtime builtin; ` +
1433
- `expected one of: ${BUILTINS.join(", ")}`);
1434
- }
1435
- if (seen.has(v))
1436
- continue; // dedupe silently
1437
- seen.add(v);
1438
- out.push(v);
1435
+ if (typeof input !== "boolean") {
1436
+ throw new Error("submission.includeBuiltinTools must be a boolean");
1439
1437
  }
1440
- return out;
1438
+ return input;
1441
1439
  }
1442
1440
  /**
1443
1441
  * Maximum number of output capture entries accepted per list.
@@ -1665,17 +1663,35 @@ function parseSkills(input) {
1665
1663
  return ref;
1666
1664
  });
1667
1665
  }
1666
+ /**
1667
+ * Parse the `submission.tools` union: each entry is either a BARE STRING (a
1668
+ * builtin tool reference, validated against {@link BUILTIN_TOOL_NAMES}) or a
1669
+ * custom tool bundle OBJECT ({@link ToolRef}). Returns the two groups split:
1670
+ * `tools` (custom bundles, the existing downstream shape) and `builtinTools`
1671
+ * (the deduped builtin-name references, in {@link BUILTIN_TOOL_NAMES} order).
1672
+ */
1668
1673
  function parseTools(input) {
1669
1674
  if (input === undefined) {
1670
- return [];
1675
+ return { tools: [], builtinTools: [] };
1671
1676
  }
1672
1677
  if (!Array.isArray(input)) {
1673
- throw new Error("submission.tools must be an array of ToolRef objects");
1678
+ throw new Error("submission.tools must be an array of builtin tool names or ToolRef objects");
1674
1679
  }
1675
1680
  const seenNames = new Set();
1676
1681
  const seenAssetIds = new Set();
1677
- return input.map((item, index) => {
1682
+ const seenBuiltins = new Set();
1683
+ const tools = [];
1684
+ input.forEach((item, index) => {
1678
1685
  const path = `submission.tools[${index}]`;
1686
+ // A bare string is a builtin tool reference (e.g. BuiltinTools.notebook_edit).
1687
+ if (typeof item === "string") {
1688
+ if (!BUILTIN_TOOL_NAMES.includes(item)) {
1689
+ throw new Error(`${path} (${JSON.stringify(item)}) is not a builtin tool name; ` +
1690
+ `expected one of: ${BUILTIN_TOOL_NAMES.join(", ")}`);
1691
+ }
1692
+ seenBuiltins.add(item);
1693
+ return;
1694
+ }
1679
1695
  const raw = requireRecord(item, path);
1680
1696
  for (const key of Object.keys(raw)) {
1681
1697
  if (key !== "kind" &&
@@ -1717,15 +1733,17 @@ function parseTools(input) {
1717
1733
  throw new Error(`${path}.input_schema.type must be "object"`);
1718
1734
  }
1719
1735
  const entry = normaliseSkillBundlePath(requireString(raw.entry, `${path}.entry`));
1720
- return {
1736
+ tools.push({
1721
1737
  kind: "asset",
1722
1738
  assetId: fields.assetId,
1723
1739
  name: fields.name,
1724
1740
  description,
1725
1741
  input_schema: inputSchema,
1726
1742
  entry
1727
- };
1743
+ });
1728
1744
  });
1745
+ const builtinTools = BUILTIN_TOOL_NAMES.filter((name) => seenBuiltins.has(name));
1746
+ return { tools, builtinTools };
1729
1747
  }
1730
1748
  function parseAgentsMd(input) {
1731
1749
  if (input === undefined)
package/dist/cli.mjs CHANGED
@@ -798,6 +798,28 @@ function parseRunRegion(input) {
798
798
  }
799
799
  return input;
800
800
  }
801
+ var BUILTIN_TOOL_NAMES = [
802
+ "bash",
803
+ "read_file",
804
+ "write_file",
805
+ "edit_file",
806
+ "grep",
807
+ "glob",
808
+ "head",
809
+ "tail",
810
+ "todo_write",
811
+ "subagent",
812
+ "subagent_result",
813
+ "web_fetch",
814
+ "web_search",
815
+ "notebook_edit",
816
+ "bash_output",
817
+ "bash_kill",
818
+ "code_execution",
819
+ "wait",
820
+ "git"
821
+ ];
822
+ var DEFAULT_BUILTIN_TOOLS = BUILTIN_TOOL_NAMES.filter((name) => name !== "notebook_edit");
801
823
  var MAX_OUTPUT_CAPTURE_TIMEOUT_MS = 6 * 60 * 60 * 1e3;
802
824
 
803
825
  // ../contracts/dist/connection-ticket.js
@@ -1376,6 +1398,8 @@ function extractErrorMessage(body) {
1376
1398
  // ../contracts/dist/operations.js
1377
1399
  var operations_exports = {};
1378
1400
  __export(operations_exports, {
1401
+ READ_OUTPUT_TEXT_DEFAULT_BYTES: () => READ_OUTPUT_TEXT_DEFAULT_BYTES,
1402
+ READ_OUTPUT_TEXT_MAX_BYTES: () => READ_OUTPUT_TEXT_MAX_BYTES,
1379
1403
  cancelRun: () => cancelRun,
1380
1404
  classifyOutput: () => classifyOutput,
1381
1405
  createAgentsMd: () => createAgentsMd,
@@ -1414,10 +1438,12 @@ __export(operations_exports, {
1414
1438
  listFiles: () => listFiles,
1415
1439
  listOutputs: () => listOutputs,
1416
1440
  listRunEvents: () => listRunEvents,
1441
+ listRuns: () => listRuns,
1417
1442
  listSecrets: () => listSecrets,
1418
1443
  listSkills: () => listSkills,
1419
1444
  normalizeOutputLinkExpiresIn: () => normalizeOutputLinkExpiresIn,
1420
1445
  outputLink: () => outputLink,
1446
+ readOutputText: () => readOutputText,
1421
1447
  redeliverRunWebhook: () => redeliverRunWebhook,
1422
1448
  resolveOutputFileSelector: () => resolveOutputFileSelector,
1423
1449
  rotateSecret: () => rotateSecret,
@@ -2151,6 +2177,18 @@ async function getRun(http, runId) {
2151
2177
  async function getRunUnit(http, runId) {
2152
2178
  return http.request(`/api/runs/${encodeURIComponent(runId)}`);
2153
2179
  }
2180
+ async function listRuns(http, query) {
2181
+ const params = {};
2182
+ if (query?.status !== void 0)
2183
+ params.status = query.status;
2184
+ if (query?.since !== void 0)
2185
+ params.since = query.since;
2186
+ if (query?.limit !== void 0)
2187
+ params.limit = String(query.limit);
2188
+ if (query?.cursor !== void 0)
2189
+ params.cursor = query.cursor;
2190
+ return http.request("/api/runs", {}, params);
2191
+ }
2154
2192
  var LIST_EVENTS_PAGE_BUDGET = 1e3;
2155
2193
  async function listRunEvents(http, runId) {
2156
2194
  const path = `/api/runs/${encodeURIComponent(runId)}/events`;
@@ -2249,6 +2287,74 @@ async function downloadOutput(http, runId, selector) {
2249
2287
  const { response } = await http.download(`/api/runs/${encodeURIComponent(runId)}/outputs/${encodeURIComponent(output.id)}/download`);
2250
2288
  return { output, bytes: new Uint8Array(await response.arrayBuffer()) };
2251
2289
  }
2290
+ var READ_OUTPUT_TEXT_MAX_BYTES = 1e7;
2291
+ var READ_OUTPUT_TEXT_DEFAULT_BYTES = 5e4;
2292
+ async function readOutputText(http, runId, selector, options) {
2293
+ const maxBytes = Math.max(1, Math.min(options?.maxBytes ?? READ_OUTPUT_TEXT_DEFAULT_BYTES, READ_OUTPUT_TEXT_MAX_BYTES));
2294
+ const output = isPathSelector(selector) ? resolveOutputFileSelector(await listOutputs(http, runId), selector, runId) : resolveOutputFileSelector([], selector, runId);
2295
+ const { response } = await http.download(`/api/runs/${encodeURIComponent(runId)}/outputs/${encodeURIComponent(output.id)}/download`);
2296
+ const capped = await readCappedText(response, maxBytes);
2297
+ const text = options?.grep === void 0 ? capped.text : grepLines(capped.text, options.grep);
2298
+ return { output, text, truncated: capped.truncated, totalBytes: capped.totalBytes };
2299
+ }
2300
+ async function readCappedText(response, maxBytes) {
2301
+ const declaredRaw = response.headers.get("content-length");
2302
+ const declared = declaredRaw !== null && /^\d+$/.test(declaredRaw) ? Number(declaredRaw) : void 0;
2303
+ const decoder = new TextDecoder("utf-8");
2304
+ const body = response.body;
2305
+ if (!body) {
2306
+ const buf = new Uint8Array(await response.arrayBuffer());
2307
+ const total = declared ?? buf.byteLength;
2308
+ return {
2309
+ text: decoder.decode(buf.subarray(0, maxBytes)),
2310
+ truncated: buf.byteLength > maxBytes,
2311
+ totalBytes: total
2312
+ };
2313
+ }
2314
+ const reader = body.getReader();
2315
+ const chunks = [];
2316
+ let read = 0;
2317
+ let sawMore = false;
2318
+ try {
2319
+ while (read < maxBytes) {
2320
+ const { done, value } = await reader.read();
2321
+ if (done)
2322
+ break;
2323
+ if (value && value.byteLength > 0) {
2324
+ read += value.byteLength;
2325
+ chunks.push(value);
2326
+ }
2327
+ }
2328
+ if (read >= maxBytes) {
2329
+ const next = await reader.read();
2330
+ if (!next.done && next.value && next.value.byteLength > 0)
2331
+ sawMore = true;
2332
+ }
2333
+ } finally {
2334
+ await reader.cancel().catch(() => {
2335
+ });
2336
+ }
2337
+ const merged = concatBytes(chunks).subarray(0, maxBytes);
2338
+ const truncated = declared !== void 0 ? declared > maxBytes : sawMore;
2339
+ const totalBytes = declared ?? read;
2340
+ return { text: decoder.decode(merged), truncated, totalBytes };
2341
+ }
2342
+ function concatBytes(chunks) {
2343
+ if (chunks.length === 1)
2344
+ return chunks[0];
2345
+ const total = chunks.reduce((n, c) => n + c.byteLength, 0);
2346
+ const out = new Uint8Array(total);
2347
+ let offset = 0;
2348
+ for (const c of chunks) {
2349
+ out.set(c, offset);
2350
+ offset += c.byteLength;
2351
+ }
2352
+ return out;
2353
+ }
2354
+ function grepLines(text, pattern) {
2355
+ const test = typeof pattern === "string" ? (line) => line.toLowerCase().includes(pattern.toLowerCase()) : (line) => pattern.test(line);
2356
+ return text.split("\n").filter((line) => test(line)).join("\n");
2357
+ }
2252
2358
  async function cancelRun(http, runId) {
2253
2359
  await http.request(`/api/runs/${encodeURIComponent(runId)}/cancel`, { method: "POST" });
2254
2360
  }
@@ -1 +1 @@
1
- 41301b02d51ef616bfff7b0d282d58e6ccc0ac5792c693f094bcae3c05c105db cli.mjs
1
+ 0386d2625bfa4f8aea426cffc3bf21546c48b33b7134eb7cd4bbfefdc2d69d96 cli.mjs
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { HttpClient, SecretString, type AexEvent, type AgentsMdRecord, type CredentialMode, type DebugSink, type FetchLike, type FileRecord, type Output, type OutputFileType, type OutputLink, type OutputLinkOptions, type OutputQuery, type OutputMode, type PlatformEnvironmentInput, type PlatformSubmission, type PlatformInlineSecrets, type PlatformProxyEndpoint, type PlatformProxyEndpointAuth, type PlatformPostHookInput, type Run, type RunModel, type RunEvent, type RunWebhookDelivery, type RunProvider, type RunRegion, type SecretRecord, type SecretReveal, type RunUnit, type Builtin, type RuntimeSize, type RuntimeKind, type Skill as SkillRecord, type WhoAmI } from "./_contracts/index.js";
1
+ import { HttpClient, SecretString, type AexEvent, type AgentsMdRecord, type CredentialMode, type DebugSink, type FetchLike, type FileRecord, type Output, type OutputFileType, type OutputLink, type OutputLinkOptions, type OutputQuery, type OutputText, type OutputMode, type ReadOutputTextOptions, type RunListPage, type RunListQuery, type PlatformEnvironmentInput, type PlatformSubmission, type PlatformInlineSecrets, type PlatformProxyEndpoint, type PlatformProxyEndpointAuth, type PlatformPostHookInput, type Run, type RunModel, type RunEvent, type RunWebhookDelivery, type RunProvider, type RunRegion, type SecretRecord, type SecretReveal, type RunUnit, type BuiltinToolName, type RuntimeSize, type RuntimeKind, type Skill as SkillRecord, type WhoAmI } from "./_contracts/index.js";
2
2
  import { AgentsMd } from "./agents-md.js";
3
3
  import { type UploadedAsset } from "./asset-upload.js";
4
4
  import { File } from "./file.js";
@@ -91,7 +91,18 @@ export interface SubmitOptions {
91
91
  readonly system?: string;
92
92
  readonly prompt: string | readonly string[];
93
93
  readonly skills?: readonly Skill[];
94
- readonly tools?: readonly Tool[];
94
+ /**
95
+ * Tools available to the agent. Each entry is either a custom {@link Tool}
96
+ * bundle, or a BUILTIN tool reference — a bare name string, preferably
97
+ * `BuiltinTools.<name>` (e.g. `BuiltinTools.notebook_edit`) so a typo is a
98
+ * compile error. Builtin references compose with {@link includeBuiltinTools}:
99
+ * use them to cherry-pick a tool the default set omits (notebook editing), or
100
+ * to pick a narrow subset alongside `includeBuiltinTools: false`.
101
+ *
102
+ * Order in the agent's tool list: resolved builtin tools, then custom tools,
103
+ * then MCP tools.
104
+ */
105
+ readonly tools?: readonly (Tool | BuiltinToolName)[];
95
106
  readonly agentsMd?: readonly AgentsMd[];
96
107
  readonly files?: readonly File[];
97
108
  readonly mcpServers?: readonly McpServer[];
@@ -146,22 +157,14 @@ export interface SubmitOptions {
146
157
  readonly maxFiles?: number;
147
158
  };
148
159
  /**
149
- * Override the managed runtime builtins enabled inside the runner.
150
- * Each entry is one of the closed {@link Builtin} set prefer the
151
- * {@link Builtins} symbol const so a typo is a compile error.
160
+ * Whether to inject the standard builtin tool set
161
+ * ({@link DEFAULT_BUILTIN_TOOLS} — every builtin except `notebook_edit`).
152
162
  *
153
- * - Omitted (default): the runner enables `DEFAULT_BUILTINS`
154
- * (`web_search`, `web_fetch`, `read`, `edit`, `glob`, `grep`, `head`,
155
- * `tail`).
156
- * - Empty array: the agent runs with zero builtins — useful for pure-MCP
157
- * setups where every tool comes from a submitted `mcpServers` entry.
158
- * - Custom list: narrows or extends the surface, e.g.
159
- * `[Builtins.WEB_SEARCH, Builtins.NOTEBOOK]`.
160
- *
161
- * Validation: each entry must be a member of {@link Builtins}, max 16
162
- * entries, deduplicated server-side.
163
+ * - Omitted / `true` (default): inject the standard builtins.
164
+ * - `false`: inject NO builtins — useful for a pure-MCP / pure-custom run.
165
+ * Cherry-pick a narrow subset back by listing builtin names in `tools`.
163
166
  */
164
- readonly builtins?: readonly Builtin[];
167
+ readonly includeBuiltinTools?: boolean;
165
168
  /**
166
169
  * Assistant-output granularity. `"buffered"` (default) delivers one event per
167
170
  * assistant message; `"stream"` delivers per-token text deltas for live
@@ -480,6 +483,17 @@ export declare class AgentExecutor {
480
483
  getRun(runId: string): Promise<Run>;
481
484
  /** Short alias for `getRun`. */
482
485
  get(runId: string): Promise<Run>;
486
+ /**
487
+ * List the runs in this workspace, most-recent first, one page at a time.
488
+ * The workspace is derived server-side from the API token, so this only ever
489
+ * enumerates your own runs. Pass `query.cursor` (from a prior page's
490
+ * `nextCursor`) to page; omit it for the first page. Returns public-safe
491
+ * {@link RunSummary} rows — the full submission stays behind `getRunUnit`.
492
+ *
493
+ * This is the workspace-wide discovery entry point: combine it with
494
+ * `listOutputs` / `readOutputText` to reach any run's deliverables.
495
+ */
496
+ listRuns(query?: RunListQuery): Promise<RunListPage>;
483
497
  /**
484
498
  * Fetch the self-contained `RunUnit`: parsed submission inputs,
485
499
  * attempts, indexed events (inline + cursor for the tail), raw
@@ -530,6 +544,15 @@ export declare class AgentExecutor {
530
544
  outputLink(runId: string, selectorOrQuery: OutputLinkSelector, options?: OutputLinkOptions): Promise<OutputLink>;
531
545
  createOutputLink(runId: string, selectorOrQuery: OutputLinkSelector, options?: OutputLinkOptions): Promise<OutputLink>;
532
546
  fetchOutput(runId: string, selectorOrQuery: OutputLinkSelector, options?: OutputLinkOptions): Promise<Response>;
547
+ /**
548
+ * Read ONE output file as byte-capped, decoded UTF-8 text. Streams the file and
549
+ * STOPS at `options.maxBytes` (default 50 KB, ceiling 10 MB), so a huge
550
+ * deliverable never fully buffers — ideal for handing a run's output to an LLM
551
+ * tool. Check `result.truncated` before treating the text as complete; pass
552
+ * `options.grep` to keep only matching lines. Select by `{ path }` or `{ id }`,
553
+ * same as `downloadOutput`.
554
+ */
555
+ readOutputText(runId: string, selector: OutputFileSelector, options?: ReadOutputTextOptions): Promise<OutputText>;
533
556
  eventArchiveLink(runId: string, options?: OutputLinkOptions): Promise<OutputLink>;
534
557
  /**
535
558
  * Download captured deliverables. Omit `selector` to receive the full
package/dist/client.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AexError, DEFAULT_CREDENTIAL_MODE, DEFAULT_RUN_PROVIDER, HttpClient, RUN_REGIONS, RUNTIME_KINDS, RunStateError, SecretString, isRunSettled, operations, parseCredentialMode, providersForModel, streamCoordinatorEvents, TERMINAL_RUN_STATUSES } from "./_contracts/index.js";
1
+ import { AexError, DEFAULT_CREDENTIAL_MODE, DEFAULT_RUN_PROVIDER, HttpClient, RUN_REGIONS, RUNTIME_KINDS, RunStateError, SecretString, isRunSettled, operations, parseCredentialMode, providersForModel, streamCoordinatorEvents, BUILTIN_TOOL_NAMES, TERMINAL_RUN_STATUSES } from "./_contracts/index.js";
2
2
  import { AgentsMd } from "./agents-md.js";
3
3
  import { uploadAsset } from "./asset-upload.js";
4
4
  import { File } from "./file.js";
@@ -380,7 +380,12 @@ export class AgentExecutor {
380
380
  ...(options.system ? { system: options.system } : {}),
381
381
  prompt,
382
382
  skills: preparedSkills,
383
- tools: preparedTools,
383
+ // The wire `tools` is the union: builtin name strings (cherry-picks)
384
+ // followed by the custom tool bundle refs. The shared parser splits them
385
+ // back into `tools` (custom) + `builtinTools` (names). The cast
386
+ // acknowledges the SDK is producing pre-parse wire input here, same as
387
+ // `mcpServers` / `environment` below.
388
+ tools: [...preparedTools.builtinNames, ...preparedTools.refs],
384
389
  agentsMd: preparedAgentsMd,
385
390
  files: preparedFiles,
386
391
  // submissionMcpServers may contain workspace refs of the shape
@@ -401,10 +406,10 @@ export class AgentExecutor {
401
406
  : {}),
402
407
  ...(options.metadata ? { metadata: options.metadata } : {}),
403
408
  ...(outputCapture ? { outputs: outputCapture } : {}),
404
- // Pass-through `builtins` verbatim including an empty array,
405
- // which is the "disable all builtins" signal. Distinguish from
406
- // omitted (default applies) via `!== undefined`.
407
- ...(options.builtins !== undefined ? { builtins: options.builtins } : {}),
409
+ // Pass-through the builtin-tool toggle verbatim (omitted default ON).
410
+ ...(options.includeBuiltinTools !== undefined
411
+ ? { includeBuiltinTools: options.includeBuiltinTools }
412
+ : {}),
408
413
  ...(options.outputMode !== undefined ? { outputMode: options.outputMode } : {})
409
414
  };
410
415
  const secrets = {
@@ -451,6 +456,19 @@ export class AgentExecutor {
451
456
  get(runId) {
452
457
  return this.getRun(runId);
453
458
  }
459
+ /**
460
+ * List the runs in this workspace, most-recent first, one page at a time.
461
+ * The workspace is derived server-side from the API token, so this only ever
462
+ * enumerates your own runs. Pass `query.cursor` (from a prior page's
463
+ * `nextCursor`) to page; omit it for the first page. Returns public-safe
464
+ * {@link RunSummary} rows — the full submission stays behind `getRunUnit`.
465
+ *
466
+ * This is the workspace-wide discovery entry point: combine it with
467
+ * `listOutputs` / `readOutputText` to reach any run's deliverables.
468
+ */
469
+ listRuns(query) {
470
+ return operations.listRuns(this.#http, query);
471
+ }
454
472
  /**
455
473
  * Fetch the self-contained `RunUnit`: parsed submission inputs,
456
474
  * attempts, indexed events (inline + cursor for the tail), raw
@@ -581,6 +599,17 @@ export class AgentExecutor {
581
599
  const link = await this.outputLink(runId, selectorOrQuery, options);
582
600
  return (this.#fetch ?? fetch)(link.url);
583
601
  }
602
+ /**
603
+ * Read ONE output file as byte-capped, decoded UTF-8 text. Streams the file and
604
+ * STOPS at `options.maxBytes` (default 50 KB, ceiling 10 MB), so a huge
605
+ * deliverable never fully buffers — ideal for handing a run's output to an LLM
606
+ * tool. Check `result.truncated` before treating the text as complete; pass
607
+ * `options.grep` to keep only matching lines. Select by `{ path }` or `{ id }`,
608
+ * same as `downloadOutput`.
609
+ */
610
+ readOutputText(runId, selector, options) {
611
+ return operations.readOutputText(this.#http, runId, selector, options);
612
+ }
584
613
  eventArchiveLink(runId, options) {
585
614
  return operations.eventArchiveLink(this.#http, runId, options);
586
615
  }
@@ -826,12 +855,33 @@ async function prepareSkills(skills, uploader) {
826
855
  }
827
856
  return refs;
828
857
  }
858
+ /**
859
+ * Split the `tools` union into custom tool refs (drafts eagerly uploaded as
860
+ * assets) and builtin tool-name references (bare strings, validated against the
861
+ * closed {@link BUILTIN_TOOL_NAMES} set). Builtin names are deduped, in input
862
+ * order; the two groups are recombined on the wire (builtins first) by the
863
+ * caller.
864
+ */
829
865
  async function prepareTools(tools, uploader) {
830
866
  const refs = [];
867
+ const seenBuiltins = new Set();
868
+ const builtinNames = [];
831
869
  for (let i = 0; i < tools.length; i++) {
832
870
  const entry = tools[i];
871
+ // A bare string is a builtin tool reference.
872
+ if (typeof entry === "string") {
873
+ if (!BUILTIN_TOOL_NAMES.includes(entry)) {
874
+ throw new Error(`AgentExecutor.submit: tools[${i}] (${JSON.stringify(entry)}) is not a builtin tool name; ` +
875
+ `expected a Tool instance or one of: ${BUILTIN_TOOL_NAMES.join(", ")}`);
876
+ }
877
+ if (!seenBuiltins.has(entry)) {
878
+ seenBuiltins.add(entry);
879
+ builtinNames.push(entry);
880
+ }
881
+ continue;
882
+ }
833
883
  if (!(entry instanceof Tool)) {
834
- throw new Error(`AgentExecutor.submit: tools[${i}] must be a Tool instance`);
884
+ throw new Error(`AgentExecutor.submit: tools[${i}] must be a Tool instance or a builtin tool name`);
835
885
  }
836
886
  if (entry.isConsumed) {
837
887
  throw new Error(`AgentExecutor.submit: tools[${i}] was already consumed by a prior submit`);
@@ -852,7 +902,7 @@ async function prepareTools(tools, uploader) {
852
902
  }
853
903
  refs.push(ref);
854
904
  }
855
- return refs;
905
+ return { refs, builtinNames };
856
906
  }
857
907
  /** Walk AgentsMd[], eagerly upload drafts as assets, and return plain asset refs. */
858
908
  async function prepareAgentsMd(agentsMds, uploader) {