@robota-sdk/agent-tools 3.0.0-beta.76 → 3.0.0-beta.78

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.
@@ -25,6 +25,7 @@ let node_fs_promises = require("node:fs/promises");
25
25
  let node_path = require("node:path");
26
26
  let _robota_sdk_agent_core = require("@robota-sdk/agent-core");
27
27
  let node_child_process = require("node:child_process");
28
+ let _robota_sdk_agent_process = require("@robota-sdk/agent-process");
28
29
  let zod = require("zod");
29
30
  let node_crypto = require("node:crypto");
30
31
  let fast_glob = require("fast-glob");
@@ -445,111 +446,6 @@ function validateToolParameters(parameters, schemaRequired, schemaProperties, ad
445
446
  };
446
447
  }
447
448
  //#endregion
448
- //#region src/implementations/function-tool/schema-converter.ts
449
- /**
450
- * Convert Zod schema to JSON Schema format with safe undefined handling
451
- */
452
- function zodToJsonSchema(schema, options = {}) {
453
- const properties = {};
454
- const required = [];
455
- const schemaDef = schema._def;
456
- if (!schemaDef) throw new Error("Zod schema is missing _def; cannot convert to JSON schema.");
457
- if (schemaDef.typeName === "ZodObject" && schemaDef.shape) {
458
- const shape = typeof schemaDef.shape === "function" ? schemaDef.shape() : schemaDef.shape;
459
- for (const [key, typeObj] of Object.entries(shape)) {
460
- properties[key] = convertZodTypeToProperty(typeObj);
461
- if (isRequiredField(typeObj)) required.push(key);
462
- }
463
- }
464
- return {
465
- type: "object",
466
- properties,
467
- required,
468
- ...(options.allowAdditionalProperties || schemaDef.unknownKeys === "passthrough") && { additionalProperties: true }
469
- };
470
- }
471
- /**
472
- * Convert individual Zod type to parameter schema with safe undefined handling
473
- */
474
- function convertZodTypeToProperty(typeObj) {
475
- const typeDef = typeObj._def;
476
- if (!typeDef) throw new Error("Zod type is missing _def; cannot convert to JSON schema.");
477
- const base = {};
478
- if (typeDef.description) base.description = typeDef.description;
479
- switch (typeDef.typeName) {
480
- case "ZodString": return {
481
- type: "string",
482
- ...base
483
- };
484
- case "ZodNumber": return {
485
- type: "number",
486
- ...base
487
- };
488
- case "ZodBoolean": return {
489
- type: "boolean",
490
- ...base
491
- };
492
- case "ZodArray":
493
- if (!typeDef.type) throw new Error("ZodArray is missing item type; cannot convert to JSON schema.");
494
- return {
495
- type: "array",
496
- items: convertZodTypeToProperty(typeDef.type),
497
- ...base
498
- };
499
- case "ZodObject": return {
500
- type: "object",
501
- ...base
502
- };
503
- case "ZodEnum": {
504
- const enumValues = typeDef.values;
505
- if (!enumValues || !Array.isArray(enumValues)) throw new Error("ZodEnum is missing enum values; cannot convert to JSON schema.");
506
- return {
507
- type: "string",
508
- enum: enumValues,
509
- ...base
510
- };
511
- }
512
- case "ZodOptional":
513
- if (typeDef.innerType) return {
514
- ...convertZodTypeToProperty(typeDef.innerType),
515
- ...base
516
- };
517
- throw new Error("ZodOptional is missing innerType; cannot convert to JSON schema.");
518
- case "ZodNullable":
519
- if (typeDef.innerType) return {
520
- ...convertZodTypeToProperty(typeDef.innerType),
521
- ...base
522
- };
523
- throw new Error("ZodNullable is missing innerType; cannot convert to JSON schema.");
524
- case "ZodDefault":
525
- if (typeDef.innerType) return {
526
- ...convertZodTypeToProperty(typeDef.innerType),
527
- ...base
528
- };
529
- throw new Error("ZodDefault is missing innerType; cannot convert to JSON schema.");
530
- case "ZodRecord":
531
- if (typeDef.valueType) return {
532
- type: "object",
533
- additionalProperties: convertZodTypeToProperty(typeDef.valueType),
534
- ...base
535
- };
536
- return {
537
- type: "object",
538
- additionalProperties: { type: "string" },
539
- ...base
540
- };
541
- default: throw new Error(`Unsupported Zod type: ${String(typeDef.typeName)}`);
542
- }
543
- }
544
- /**
545
- * Check if a Zod field is required (not optional or nullable)
546
- */
547
- function isRequiredField(typeObj) {
548
- const typeDef = typeObj._def;
549
- if (!typeDef) throw new Error("Zod schema is missing _def; cannot determine required fields.");
550
- return typeDef.typeName !== "ZodOptional" && typeDef.typeName !== "ZodNullable" && typeDef.typeName !== "ZodDefault";
551
- }
552
- //#endregion
553
449
  //#region src/implementations/function-tool.ts
554
450
  /**
555
451
  * Function tool implementation
@@ -653,39 +549,59 @@ function createZodFunctionTool(name, description, zodSchema, fn) {
653
549
  const schema = {
654
550
  name,
655
551
  description,
656
- parameters: zodToJsonSchema(zodSchema)
552
+ parameters: (0, _robota_sdk_agent_core.zodToJsonSchema)(zodSchema)
657
553
  };
658
554
  const wrappedFn = async (parameters, context) => {
659
555
  const parseResult = zodSchema.safeParse(parameters);
660
556
  if (!parseResult.success) throw new _robota_sdk_agent_core.ValidationError(`Zod validation failed: ${parseResult.error}`);
661
- const result = await fn(parseResult.data || parameters, context);
557
+ const result = await fn(parseResult.data, context);
662
558
  return typeof result === "string" ? result : JSON.stringify(result);
663
559
  };
664
560
  return new FunctionTool(schema, wrappedFn);
665
561
  }
666
562
  //#endregion
667
- //#region src/builtins/bash-tool.ts
563
+ //#region src/builtins/shell-tool.ts
668
564
  /**
669
- * BashTool — execute shell commands via child_process.spawn
565
+ * ShellTool — execute a host shell command via child_process.spawn (TERM-008).
566
+ *
567
+ * Cross-platform: the shell is resolved per OS through `resolvePlatformShell()` (POSIX `sh`/`bash`,
568
+ * Windows PowerShell). The tool name is `Shell` and its description is built dynamically from the
569
+ * resolved shell so the model is told the active shell/OS and writes the right syntax.
670
570
  *
671
- * Returns TToolResult JSON string. Non-zero exit is returned as success:true
672
- * with exitCode set, matching Claude Code behaviour (the command ran, it just
673
- * exited non-zero — the LLM can decide what to do with that information).
571
+ * Returns an IToolInvocationResult JSON string. A non-zero exit is returned as success:true with
572
+ * exitCode set (the command ran, it just exited non-zero — the LLM decides what to do with that).
674
573
  */
574
+ /** POSIX children are spawned detached so a process-group kill reaps grandchildren (CORE-023). */
575
+ const SPAWN_DETACHED = process.platform !== "win32";
675
576
  const DEFAULT_TIMEOUT_MS$2 = 12e4;
676
- const BashSchema = zod.z.object({
677
- command: zod.z.string().describe("The bash command to execute"),
577
+ const ShellSchema = zod.z.object({
578
+ command: zod.z.string().describe("The shell command to execute"),
678
579
  timeout: zod.z.number().optional().describe("Optional timeout in milliseconds (max 600000). Default is 120000 (2 minutes)"),
679
580
  workingDirectory: zod.z.string().optional().describe("Working directory for the command. Defaults to the current working directory")
680
581
  });
681
- /**
682
- * Run a shell command and return stdout + stderr.
683
- * Resolves with the TToolResult JSON string.
684
- */
685
- async function runBash(args, options = {}) {
686
- const { command, timeout: rawTimeout = DEFAULT_TIMEOUT_MS$2, workingDirectory } = args;
687
- const timeout = Math.min(rawTimeout, 6e5);
688
- if (options.sandboxClient) try {
582
+ /** Build the OS-aware tool description so the model writes syntax the host shell can run. */
583
+ function buildShellToolDescription(shell) {
584
+ return [
585
+ `Executes a command in the host shell and returns its output.`,
586
+ ``,
587
+ `Active shell: ${shell.label}. ${shell.syntaxHint}`,
588
+ ``,
589
+ `The working directory persists between commands, but shell state does not.`,
590
+ ``,
591
+ `IMPORTANT: Avoid using this tool to run \`find\`, \`grep\`, \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands. Instead, use the appropriate dedicated tool:`,
592
+ ` - File search: Use Glob (NOT find or ls)`,
593
+ ` - Content search: Use Grep (NOT grep or rg)`,
594
+ ` - Read files: Use Read (NOT cat/head/tail)`,
595
+ ` - Edit files: Use Edit (NOT sed/awk)`,
596
+ ``,
597
+ `For simple commands, keep the description brief (5-10 words). For complex commands, include enough context to clarify what the command does.`,
598
+ ``,
599
+ `Output is limited to 30,000 characters. Longer output will be middle-truncated.`
600
+ ].join("\n");
601
+ }
602
+ /** Run a shell command through the sandbox client, surfacing failures as a structured result. */
603
+ async function runInSandbox(command, timeout, workingDirectory, options) {
604
+ try {
689
605
  const sandboxResult = await options.sandboxClient.run(command, {
690
606
  timeoutMs: timeout,
691
607
  workingDirectory
@@ -704,20 +620,37 @@ async function runBash(args, options = {}) {
704
620
  };
705
621
  return JSON.stringify(result);
706
622
  }
623
+ }
624
+ /**
625
+ * Run a shell command and return stdout + stderr.
626
+ * Resolves with the IToolInvocationResult JSON string.
627
+ */
628
+ async function runShell(args, options = {}, signal) {
629
+ const { command, timeout: rawTimeout = DEFAULT_TIMEOUT_MS$2, workingDirectory } = args;
630
+ const timeout = Math.min(rawTimeout, 6e5);
631
+ if (options.sandboxClient) return runInSandbox(command, timeout, workingDirectory, options);
632
+ const shell = (0, _robota_sdk_agent_core.resolvePlatformShell)();
633
+ if (signal?.aborted) return JSON.stringify({
634
+ success: false,
635
+ output: "",
636
+ error: "Aborted before start"
637
+ });
707
638
  return new Promise((resolve) => {
708
639
  const stdoutChunks = [];
709
640
  const stderrChunks = [];
710
641
  let timedOut = false;
711
642
  let settled = false;
712
- const child = (0, node_child_process.spawn)("sh", ["-c", command], {
643
+ const child = (0, node_child_process.spawn)(shell.command, shell.commandArgs(command), {
713
644
  cwd: workingDirectory ?? process.cwd(),
714
645
  env: process.env,
715
646
  stdio: [
716
647
  "pipe",
717
648
  "pipe",
718
649
  "pipe"
719
- ]
650
+ ],
651
+ detached: SPAWN_DETACHED
720
652
  });
653
+ child.stdin?.end();
721
654
  child.stdout.on("data", (chunk) => {
722
655
  stdoutChunks.push(chunk);
723
656
  });
@@ -726,7 +659,7 @@ async function runBash(args, options = {}) {
726
659
  });
727
660
  const timer = setTimeout(() => {
728
661
  timedOut = true;
729
- child.kill("SIGTERM");
662
+ (0, _robota_sdk_agent_process.killProcessTree)(child, { processGroup: SPAWN_DETACHED });
730
663
  settle({
731
664
  success: false,
732
665
  output: Buffer.concat(stdoutChunks).toString("utf8"),
@@ -737,8 +670,18 @@ async function runBash(args, options = {}) {
737
670
  if (settled) return;
738
671
  settled = true;
739
672
  clearTimeout(timer);
673
+ signal?.removeEventListener("abort", onAbort);
740
674
  resolve(JSON.stringify(result));
741
675
  }
676
+ function onAbort() {
677
+ (0, _robota_sdk_agent_process.killProcessTree)(child, { processGroup: SPAWN_DETACHED });
678
+ settle({
679
+ success: false,
680
+ output: Buffer.concat(stdoutChunks).toString("utf8"),
681
+ error: "Aborted"
682
+ });
683
+ }
684
+ signal?.addEventListener("abort", onAbort, { once: true });
742
685
  child.on("error", (err) => {
743
686
  settle({
744
687
  success: false,
@@ -768,21 +711,37 @@ async function runBash(args, options = {}) {
768
711
  });
769
712
  }
770
713
  /**
771
- * Create a BashTool instance — register with Robota agent tools registry.
714
+ * Build a host-shell command tool under a given registered name. Both `Shell` and the
715
+ * model-familiar `Bash` are registered as aliases of this one OS-aware implementation
716
+ * (TERM-008): the shell is resolved per OS and the description names the active shell so the
717
+ * model writes the right syntax regardless of which alias it calls.
772
718
  */
773
- function createBashTool(options = {}) {
774
- return createZodFunctionTool("Bash", "Executes a given bash command and returns its output.\n\nThe working directory persists between commands, but shell state does not.\n\nIMPORTANT: Avoid using this tool to run `find`, `grep`, `cat`, `head`, `tail`, `sed`, `awk`, or `echo` commands. Instead, use the appropriate dedicated tool:\n - File search: Use Glob (NOT find or ls)\n - Content search: Use Grep (NOT grep or rg)\n - Read files: Use Read (NOT cat/head/tail)\n - Edit files: Use Edit (NOT sed/awk)\n\nFor simple commands, keep the description brief (5-10 words). For complex commands, include enough context to clarify what the command does.\n\nOutput is limited to 30,000 characters. Longer output will be middle-truncated.", BashSchema, async (params) => {
775
- return runBash(params, options);
719
+ function createHostShellTool(name, options) {
720
+ return createZodFunctionTool(name, buildShellToolDescription((0, _robota_sdk_agent_core.resolvePlatformShell)()), ShellSchema, async (params, context) => {
721
+ return runShell(params, options, context?.signal);
776
722
  });
777
723
  }
778
724
  /**
779
- * BashTool instance — register with Robota agent tools registry.
725
+ * Create a `Shell` tool instance — register with the Robota agent tools registry.
726
+ * The description is resolved at creation time for the host's active shell.
780
727
  */
728
+ function createShellTool(options = {}) {
729
+ return createHostShellTool("Shell", options);
730
+ }
731
+ /**
732
+ * Create a `Bash` tool instance — the model-familiar alias of the same OS-aware shell tool.
733
+ */
734
+ function createBashTool(options = {}) {
735
+ return createHostShellTool("Bash", options);
736
+ }
737
+ /** `Shell` tool instance — register with the Robota agent tools registry. */
738
+ const shellTool = createShellTool();
739
+ /** `Bash` tool instance — model-familiar alias of {@link shellTool}. */
781
740
  const bashTool = createBashTool();
782
741
  //#endregion
783
742
  //#region src/builtins/path-guard.ts
784
743
  /**
785
- * Returns a JSON-serialized TToolResult error when filePath is outside cwd.
744
+ * Returns a JSON-serialized IToolInvocationResult error when filePath is outside cwd.
786
745
  * Returns undefined when the path is within cwd or cwd is not set.
787
746
  */
788
747
  function checkPathWithinCwd(filePath, cwd) {
@@ -1317,7 +1276,7 @@ function classifyFetchError(err) {
1317
1276
  if (code === "CERT_HAS_EXPIRED" || code === "UNABLE_TO_VERIFY_LEAF_SIGNATURE") return `Network error: SSL certificate error (${code}). The server's certificate is invalid. Do not retry with the same URL.`;
1318
1277
  return `Network error: ${err.message} Check that the URL is correct and the server is reachable.`;
1319
1278
  }
1320
- async function runWebFetch(args) {
1279
+ async function runWebFetch(args, signal) {
1321
1280
  const { url, headers } = args;
1322
1281
  try {
1323
1282
  new URL(url);
@@ -1332,12 +1291,13 @@ async function runWebFetch(args) {
1332
1291
  try {
1333
1292
  const controller = new AbortController();
1334
1293
  const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS$1);
1294
+ const fetchSignal = signal ? AbortSignal.any([controller.signal, signal]) : controller.signal;
1335
1295
  const response = await fetch(url, {
1336
1296
  headers: {
1337
1297
  "User-Agent": "Robota-CLI/3.0",
1338
1298
  ...headers ?? {}
1339
1299
  },
1340
- signal: controller.signal,
1300
+ signal: fetchSignal,
1341
1301
  redirect: "follow"
1342
1302
  });
1343
1303
  clearTimeout(timeout);
@@ -1375,7 +1335,7 @@ async function runWebFetch(args) {
1375
1335
  return JSON.stringify(result);
1376
1336
  }
1377
1337
  }
1378
- const webFetchTool = createZodFunctionTool("WebFetch", "Fetch a URL and return its content as text. HTML pages are converted to plain text.", WebFetchSchema, async (params) => runWebFetch(params));
1338
+ const webFetchTool = createZodFunctionTool("WebFetch", "Fetch a URL and return its content as text. HTML pages are converted to plain text.", WebFetchSchema, async (params, context) => runWebFetch(params, context?.signal));
1379
1339
  //#endregion
1380
1340
  //#region src/builtins/web-search-tool.ts
1381
1341
  /**
@@ -1390,7 +1350,7 @@ const WebSearchSchema = zod.z.object({
1390
1350
  query: zod.z.string().describe("The search query"),
1391
1351
  limit: zod.z.number().optional().describe(`Maximum number of results to return (default: ${DEFAULT_LIMIT})`)
1392
1352
  });
1393
- async function runWebSearch(args) {
1353
+ async function runWebSearch(args, signal) {
1394
1354
  const { query, limit = DEFAULT_LIMIT } = args;
1395
1355
  const apiKey = process.env["BRAVE_API_KEY"];
1396
1356
  if (!apiKey) return JSON.stringify({
@@ -1401,6 +1361,7 @@ async function runWebSearch(args) {
1401
1361
  try {
1402
1362
  const controller = new AbortController();
1403
1363
  const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
1364
+ const fetchSignal = signal ? AbortSignal.any([controller.signal, signal]) : controller.signal;
1404
1365
  const params = new URLSearchParams({
1405
1366
  q: query,
1406
1367
  count: String(Math.min(limit, 20))
@@ -1411,7 +1372,7 @@ async function runWebSearch(args) {
1411
1372
  "Accept-Encoding": "gzip",
1412
1373
  "X-Subscription-Token": apiKey
1413
1374
  },
1414
- signal: controller.signal
1375
+ signal: fetchSignal
1415
1376
  });
1416
1377
  clearTimeout(timeout);
1417
1378
  if (!response.ok) {
@@ -1441,26 +1402,139 @@ async function runWebSearch(args) {
1441
1402
  return JSON.stringify(result);
1442
1403
  }
1443
1404
  }
1444
- const webSearchTool = createZodFunctionTool("WebSearch", "Search the web and return results with title, URL, and snippet.", WebSearchSchema, async (params) => runWebSearch(params));
1405
+ const webSearchTool = createZodFunctionTool("WebSearch", "Search the web and return results with title, URL, and snippet.", WebSearchSchema, async (params, context) => runWebSearch(params, context?.signal));
1406
+ //#endregion
1407
+ //#region src/builtins/ask-user-question-tool.ts
1408
+ /**
1409
+ * AskUserQuestionTool — let the model ask the user structured questions mid-turn (CMD-005).
1410
+ *
1411
+ * Built on the CMD-004 ask seam: each question maps onto the `IActionRequest` SSOT and is issued
1412
+ * through the injected `IToolExecutionContext.ask` port; the attached environment renders it (Ink
1413
+ * dialog, web modal, programmatic pre-answer) and the answers return as the tool result.
1414
+ *
1415
+ * Contract points (spec CMD-005):
1416
+ * - 1–4 questions per call, asked sequentially (the channel's ask queue renders one at a time).
1417
+ * - Cancellation is data, not an exception: a dismissed question yields `{ cancelled: true }` and the
1418
+ * remaining unasked questions of the same call are marked cancelled too (no per-item re-prompt).
1419
+ * - No `context.ask` (headless/automation): returns `{ unavailable: true, reason }` — never a silent
1420
+ * guess, never a thrown error, so the model can continue autonomously.
1421
+ */
1422
+ const MAX_QUESTIONS = 4;
1423
+ const QuestionSchema = zod.z.object({
1424
+ question: zod.z.string().min(1).describe("The complete question to ask the user."),
1425
+ header: zod.z.string().optional().describe("Very short topic label for the question (e.g. \"Auth method\")."),
1426
+ options: zod.z.array(zod.z.union([zod.z.string().min(1).describe("Display text of this choice."), zod.z.object({
1427
+ label: zod.z.string().min(1).describe("Display text of this choice."),
1428
+ description: zod.z.string().optional().describe("What choosing this option means.")
1429
+ })])).optional().describe("Predefined choices (strings or {label, description}). Omit for pure free text."),
1430
+ multiSelect: zod.z.boolean().optional().describe("Allow selecting multiple options (default: single select)."),
1431
+ allowFreeText: zod.z.boolean().optional().describe("Allow a typed custom answer besides the options (default: true).")
1432
+ });
1433
+ const AskUserQuestionSchema = zod.z.object({ questions: zod.z.array(QuestionSchema).min(1).max(MAX_QUESTIONS).describe(`Questions to ask the user (1-${MAX_QUESTIONS}), rendered one at a time.`) });
1434
+ const ASK_USER_QUESTION_DESCRIPTION = [
1435
+ "Ask the user one or more structured questions and wait for their answers.",
1436
+ "",
1437
+ "Use this when you are blocked on a decision only the user can make — ambiguous requirements,",
1438
+ "mutually exclusive approaches, or choices with real trade-offs. Do not use it for decisions with",
1439
+ "a conventional default or facts you can verify yourself.",
1440
+ "",
1441
+ `Provide 1-${MAX_QUESTIONS} questions. Each question offers predefined options and/or free text:`,
1442
+ " - options + default: user picks one option (or types a custom answer unless allowFreeText: false)",
1443
+ " - multiSelect: true: user may pick several options",
1444
+ " - no options: pure free-text entry",
1445
+ "",
1446
+ "The result is a JSON array with one entry per question: the selected option labels in `values`",
1447
+ "and/or the typed answer in `text`, or `cancelled: true` if the user dismissed the question.",
1448
+ "If no interactive user is attached (headless run), the result is `{ unavailable: true }` —",
1449
+ "continue autonomously with your best judgment and say what you assumed."
1450
+ ].join("\n");
1451
+ function toActionRequest(question) {
1452
+ const options = (question.options ?? []).map((option) => typeof option === "string" ? { label: option } : option);
1453
+ const multi = question.multiSelect === true && options.length > 1;
1454
+ return {
1455
+ id: `ask_${(0, node_crypto.randomUUID)()}`,
1456
+ title: question.question,
1457
+ ...question.header !== void 0 ? { description: question.header } : {},
1458
+ ...options.length > 0 ? { options: options.map((o) => ({
1459
+ value: o.label,
1460
+ label: o.label,
1461
+ ...o.description !== void 0 ? { description: o.description } : {}
1462
+ })) } : {},
1463
+ minSelect: options.length > 0 ? 1 : 0,
1464
+ maxSelect: multi ? options.length : 1,
1465
+ allowFreeText: question.allowFreeText !== false || options.length === 0
1466
+ };
1467
+ }
1468
+ async function askQuestions(args, ask) {
1469
+ const answers = [];
1470
+ let dismissed = false;
1471
+ for (const question of args.questions) {
1472
+ if (dismissed) {
1473
+ answers.push({
1474
+ question: question.question,
1475
+ cancelled: true
1476
+ });
1477
+ continue;
1478
+ }
1479
+ const response = await ask(toActionRequest(question));
1480
+ if (response.type === "cancelled") {
1481
+ dismissed = true;
1482
+ answers.push({
1483
+ question: question.question,
1484
+ cancelled: true
1485
+ });
1486
+ continue;
1487
+ }
1488
+ answers.push({
1489
+ question: question.question,
1490
+ values: [...response.values],
1491
+ ...response.text !== void 0 ? { text: response.text } : {}
1492
+ });
1493
+ }
1494
+ return { answers };
1495
+ }
1496
+ /**
1497
+ * Create an `AskUserQuestion` tool instance — register with the Robota agent tools registry.
1498
+ */
1499
+ function createAskUserQuestionTool() {
1500
+ return createZodFunctionTool("AskUserQuestion", ASK_USER_QUESTION_DESCRIPTION, AskUserQuestionSchema, async (params, context) => {
1501
+ const args = params;
1502
+ const ask = context?.ask;
1503
+ const output = ask ? await askQuestions(args, ask) : {
1504
+ unavailable: true,
1505
+ reason: "no interactive user attached"
1506
+ };
1507
+ const result = {
1508
+ success: true,
1509
+ output: JSON.stringify(output)
1510
+ };
1511
+ return JSON.stringify(result);
1512
+ });
1513
+ }
1514
+ /** `AskUserQuestion` tool instance — register with the Robota agent tools registry. */
1515
+ const askUserQuestionTool = createAskUserQuestionTool();
1445
1516
  //#endregion
1446
1517
  exports.E2BSandboxClient = E2BSandboxClient;
1447
1518
  exports.FunctionTool = FunctionTool;
1448
1519
  exports.InMemorySandboxClient = InMemorySandboxClient;
1449
1520
  exports.ToolRegistry = ToolRegistry;
1450
1521
  exports.applyWorkspaceManifest = applyWorkspaceManifest;
1522
+ exports.askUserQuestionTool = askUserQuestionTool;
1451
1523
  exports.bashTool = bashTool;
1524
+ exports.createAskUserQuestionTool = createAskUserQuestionTool;
1452
1525
  exports.createBashTool = createBashTool;
1453
1526
  exports.createEditTool = createEditTool;
1454
1527
  exports.createFunctionTool = createFunctionTool;
1455
1528
  exports.createReadTool = createReadTool;
1529
+ exports.createShellTool = createShellTool;
1456
1530
  exports.createWriteTool = createWriteTool;
1457
1531
  exports.createZodFunctionTool = createZodFunctionTool;
1458
1532
  exports.editTool = editTool;
1459
1533
  exports.globTool = globTool;
1460
1534
  exports.grepTool = grepTool;
1461
1535
  exports.readTool = readTool;
1536
+ exports.shellTool = shellTool;
1462
1537
  exports.validateWorkspaceManifestPath = validateWorkspaceManifestPath;
1463
1538
  exports.webFetchTool = webFetchTool;
1464
1539
  exports.webSearchTool = webSearchTool;
1465
1540
  exports.writeTool = writeTool;
1466
- exports.zodToJsonSchema = zodToJsonSchema;
@@ -1,10 +1,11 @@
1
1
  import { IEventService, IFunctionTool, IParameterValidationResult, ITool, IToolExecutionContext, IToolRegistry, IToolResult, IToolSchema, TToolExecutor, TToolParameters, TUniversalValue } from "@robota-sdk/agent-core";
2
+ import { TypeOf, ZodType } from "zod";
2
3
 
3
4
  //#region src/types/tool-result.d.ts
4
5
  /**
5
6
  * Result returned by a CLI tool invocation
6
7
  */
7
- interface TToolResult {
8
+ interface IToolInvocationResult {
8
9
  success: boolean;
9
10
  output: string;
10
11
  error?: string;
@@ -233,70 +234,6 @@ declare class ToolRegistry implements IToolRegistry {
233
234
  private validateToolSchema;
234
235
  }
235
236
  //#endregion
236
- //#region src/implementations/function-tool/types.d.ts
237
- /**
238
- * Zod schema compatibility types
239
- *
240
- * Widened to `unknown` so that actual Zod schemas (ZodObject<...>) are structurally
241
- * assignable without `as unknown as IZodSchema` casts at call sites.
242
- */
243
- interface IZodParseResult {
244
- success: boolean;
245
- data?: unknown;
246
- error?: unknown;
247
- }
248
- interface IZodSchemaDef {
249
- typeName?: string;
250
- innerType?: IZodSchema;
251
- valueType?: IZodSchema;
252
- checks?: Array<{
253
- kind: string;
254
- value?: TUniversalValue;
255
- }>;
256
- shape?: () => Record<string, IZodSchema>;
257
- type?: IZodSchema;
258
- values?: TUniversalValue[];
259
- description?: string;
260
- unknownKeys?: 'passthrough' | 'strip' | 'strict';
261
- }
262
- interface IZodSchema {
263
- parse(value: unknown): unknown;
264
- safeParse(value: unknown): IZodParseResult;
265
- _def?: IZodSchemaDef;
266
- }
267
- /**
268
- * Parameter type validation options
269
- */
270
- interface IFunctionToolValidationOptions {
271
- strict?: boolean;
272
- allowUnknown?: boolean;
273
- validateTypes?: boolean;
274
- }
275
- /**
276
- * Schema conversion options
277
- */
278
- interface ISchemaConversionOptions {
279
- includeDescription?: boolean;
280
- strictTypes?: boolean;
281
- allowAdditionalProperties?: boolean;
282
- }
283
- /**
284
- * Tool execution metadata
285
- */
286
- interface IFunctionToolExecutionMetadata {
287
- executionTime: number;
288
- toolName: string;
289
- parameters: TToolParameters;
290
- }
291
- /**
292
- * Tool result with metadata
293
- */
294
- interface IFunctionToolResult {
295
- success: boolean;
296
- data: TUniversalValue;
297
- metadata?: IFunctionToolExecutionMetadata;
298
- }
299
- //#endregion
300
237
  //#region src/implementations/function-tool.d.ts
301
238
  /**
302
239
  * Function tool implementation
@@ -348,22 +285,47 @@ declare function createFunctionTool(name: string, description: string, parameter
348
285
  /**
349
286
  * Helper function to create a function tool from Zod schema
350
287
  */
351
- declare function createZodFunctionTool(name: string, description: string, zodSchema: IZodSchema, fn: TToolExecutor): FunctionTool;
288
+ declare function createZodFunctionTool<S extends ZodType>(name: string, description: string, zodSchema: S, fn: TToolExecutor<TypeOf<S>>): FunctionTool;
352
289
  //#endregion
353
- //#region src/implementations/function-tool/schema-converter.d.ts
290
+ //#region src/implementations/function-tool/types.d.ts
291
+ /**
292
+ * Parameter type validation options
293
+ */
294
+ interface IFunctionToolValidationOptions {
295
+ strict?: boolean;
296
+ allowUnknown?: boolean;
297
+ validateTypes?: boolean;
298
+ }
354
299
  /**
355
- * Convert Zod schema to JSON Schema format with safe undefined handling
300
+ * Tool execution metadata
356
301
  */
357
- declare function zodToJsonSchema(schema: IZodSchema, options?: ISchemaConversionOptions): IToolSchema['parameters'];
302
+ interface IFunctionToolExecutionMetadata {
303
+ executionTime: number;
304
+ toolName: string;
305
+ parameters: TToolParameters;
306
+ }
307
+ /**
308
+ * Tool result with metadata
309
+ */
310
+ interface IFunctionToolResult {
311
+ success: boolean;
312
+ data: TUniversalValue;
313
+ metadata?: IFunctionToolExecutionMetadata;
314
+ }
358
315
  //#endregion
359
- //#region src/builtins/bash-tool.d.ts
316
+ //#region src/builtins/shell-tool.d.ts
360
317
  /**
361
- * Create a BashTool instance — register with Robota agent tools registry.
318
+ * Create a `Shell` tool instance — register with the Robota agent tools registry.
319
+ * The description is resolved at creation time for the host's active shell.
362
320
  */
363
- declare function createBashTool(options?: ISandboxToolOptions): FunctionTool;
321
+ declare function createShellTool(options?: ISandboxToolOptions): FunctionTool;
364
322
  /**
365
- * BashTool instance — register with Robota agent tools registry.
323
+ * Create a `Bash` tool instance — the model-familiar alias of the same OS-aware shell tool.
366
324
  */
325
+ declare function createBashTool(options?: ISandboxToolOptions): FunctionTool;
326
+ /** `Shell` tool instance — register with the Robota agent tools registry. */
327
+ declare const shellTool: FunctionTool;
328
+ /** `Bash` tool instance — model-familiar alias of {@link shellTool}. */
367
329
  declare const bashTool: FunctionTool;
368
330
  //#endregion
369
331
  //#region src/builtins/read-tool.d.ts
@@ -436,5 +398,13 @@ declare const webFetchTool: FunctionTool;
436
398
  */
437
399
  declare const webSearchTool: FunctionTool;
438
400
  //#endregion
439
- export { E2BSandboxClient, FunctionTool, type IE2BSandboxAdapter, type IE2BSandboxClientOptions, type IFunctionToolExecutionMetadata, type IFunctionToolResult, type IFunctionToolValidationOptions, type IInMemorySandboxClientOptions, type ISandboxClient, type ISandboxRunOptions, type ISandboxRunResult, type ISandboxToolOptions, type ISchemaConversionOptions, type IWorkspaceManifest, type IWorkspaceManifestAppliedEntry, type IWorkspaceManifestApplyOptions, type IWorkspaceManifestApplyResult, type IWorkspaceManifestAzureBlobMountEntry, type IWorkspaceManifestDirectoryEntry, type IWorkspaceManifestFileEntry, type IWorkspaceManifestGcsMountEntry, type IWorkspaceManifestGitRepositoryEntry, type IWorkspaceManifestLocalDirectoryEntry, type IWorkspaceManifestLocalFileEntry, type IWorkspaceManifestPermissions, type IWorkspaceManifestR2MountEntry, type IWorkspaceManifestS3MountEntry, type IZodParseResult, type IZodSchema, type IZodSchemaDef, InMemorySandboxClient, type TInMemorySandboxRunHandler, type TToolResult, type TWorkspaceManifestApplyStatus, type TWorkspaceManifestEntry, ToolRegistry, applyWorkspaceManifest, bashTool, createBashTool, createEditTool, createFunctionTool, createReadTool, createWriteTool, createZodFunctionTool, editTool, globTool, grepTool, readTool, validateWorkspaceManifestPath, webFetchTool, webSearchTool, writeTool, zodToJsonSchema };
401
+ //#region src/builtins/ask-user-question-tool.d.ts
402
+ /**
403
+ * Create an `AskUserQuestion` tool instance — register with the Robota agent tools registry.
404
+ */
405
+ declare function createAskUserQuestionTool(): FunctionTool;
406
+ /** `AskUserQuestion` tool instance — register with the Robota agent tools registry. */
407
+ declare const askUserQuestionTool: FunctionTool;
408
+ //#endregion
409
+ export { E2BSandboxClient, FunctionTool, type IE2BSandboxAdapter, type IE2BSandboxClientOptions, type IFunctionToolExecutionMetadata, type IFunctionToolResult, type IFunctionToolValidationOptions, type IInMemorySandboxClientOptions, type ISandboxClient, type ISandboxRunOptions, type ISandboxRunResult, type ISandboxToolOptions, type IToolInvocationResult, type IWorkspaceManifest, type IWorkspaceManifestAppliedEntry, type IWorkspaceManifestApplyOptions, type IWorkspaceManifestApplyResult, type IWorkspaceManifestAzureBlobMountEntry, type IWorkspaceManifestDirectoryEntry, type IWorkspaceManifestFileEntry, type IWorkspaceManifestGcsMountEntry, type IWorkspaceManifestGitRepositoryEntry, type IWorkspaceManifestLocalDirectoryEntry, type IWorkspaceManifestLocalFileEntry, type IWorkspaceManifestPermissions, type IWorkspaceManifestR2MountEntry, type IWorkspaceManifestS3MountEntry, InMemorySandboxClient, type TInMemorySandboxRunHandler, type TWorkspaceManifestApplyStatus, type TWorkspaceManifestEntry, ToolRegistry, applyWorkspaceManifest, askUserQuestionTool, bashTool, createAskUserQuestionTool, createBashTool, createEditTool, createFunctionTool, createReadTool, createShellTool, createWriteTool, createZodFunctionTool, editTool, globTool, grepTool, readTool, shellTool, validateWorkspaceManifestPath, webFetchTool, webSearchTool, writeTool };
440
410
  //# sourceMappingURL=index.d.ts.map