@robota-sdk/agent-cli 3.0.0-beta.1 → 3.0.0-beta.11

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
  // src/cli.ts
2
2
  import { parseArgs } from "util";
3
- import { readFileSync as readFileSync2 } from "fs";
3
+ import { readFileSync as readFileSync2, existsSync as existsSync2, mkdirSync, writeFileSync, unlinkSync } from "fs";
4
4
  import { join as join2, dirname } from "path";
5
5
  import { fileURLToPath } from "url";
6
6
  import * as readline from "readline";
@@ -8,30 +8,12 @@ import {
8
8
  loadConfig,
9
9
  loadContext,
10
10
  detectProject,
11
- Session as Session2,
11
+ createSession as createSession2,
12
12
  SessionStore,
13
- buildSystemPrompt
13
+ FileSessionLogger as FileSessionLogger2,
14
+ projectPaths as projectPaths2
14
15
  } from "@robota-sdk/agent-sdk";
15
-
16
- // src/permissions/permission-prompt.ts
17
- import chalk from "chalk";
18
- var PERMISSION_OPTIONS = ["Allow", "Deny"];
19
- var ALLOW_INDEX = 0;
20
- function formatArgs(toolArgs) {
21
- const entries = Object.entries(toolArgs);
22
- if (entries.length === 0) {
23
- return "(no arguments)";
24
- }
25
- return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
26
- }
27
- async function promptForApproval(terminal, toolName, toolArgs) {
28
- terminal.writeLine("");
29
- terminal.writeLine(chalk.yellow(`[Permission Required] Tool: ${toolName}`));
30
- terminal.writeLine(chalk.dim(` ${formatArgs(toolArgs)}`));
31
- terminal.writeLine("");
32
- const selected = await terminal.select(PERMISSION_OPTIONS, ALLOW_INDEX);
33
- return selected === ALLOW_INDEX;
34
- }
16
+ import { promptForApproval } from "@robota-sdk/agent-sdk";
35
17
 
36
18
  // src/ui/render.tsx
37
19
  import { render } from "ink";
@@ -39,7 +21,7 @@ import { render } from "ink";
39
21
  // src/ui/App.tsx
40
22
  import { useState as useState4, useCallback as useCallback2, useRef as useRef2 } from "react";
41
23
  import { Box as Box6, Text as Text8, useApp, useInput as useInput4 } from "ink";
42
- import { Session } from "@robota-sdk/agent-sdk";
24
+ import { createSession, FileSessionLogger, projectPaths } from "@robota-sdk/agent-sdk";
43
25
 
44
26
  // src/commands/command-registry.ts
45
27
  var CommandRegistry = class {
@@ -101,6 +83,7 @@ function createBuiltinCommands() {
101
83
  { name: "cost", description: "Show session info", source: "builtin" },
102
84
  { name: "context", description: "Context window info", source: "builtin" },
103
85
  { name: "permissions", description: "Permission rules", source: "builtin" },
86
+ { name: "reset", description: "Delete settings and exit", source: "builtin" },
104
87
  { name: "exit", description: "Exit CLI", source: "builtin" }
105
88
  ];
106
89
  }
@@ -152,7 +135,8 @@ function scanSkillsDir(skillsDir) {
152
135
  commands.push({
153
136
  name: frontmatter?.name ?? entry.name,
154
137
  description: frontmatter?.description ?? `Skill: ${entry.name}`,
155
- source: "skill"
138
+ source: "skill",
139
+ skillContent: content
156
140
  });
157
141
  }
158
142
  return commands;
@@ -306,7 +290,7 @@ import { Box as Box4, Text as Text6, useInput as useInput2 } from "ink";
306
290
  import { useRef, useState } from "react";
307
291
  import { Text as Text3, useInput, useCursor } from "ink";
308
292
  import stringWidth from "string-width";
309
- import chalk2 from "chalk";
293
+ import chalk from "chalk";
310
294
  import { jsx as jsx3 } from "react/jsx-runtime";
311
295
  function CjkTextInput({
312
296
  value,
@@ -328,71 +312,81 @@ function CjkTextInput({
328
312
  }
329
313
  useInput(
330
314
  (input, key) => {
331
- if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
332
- return;
333
- }
334
- if (key.return) {
335
- onSubmit?.(valueRef.current);
336
- return;
337
- }
338
- if (key.leftArrow) {
339
- if (cursorRef.current > 0) {
340
- cursorRef.current -= 1;
341
- forceRender((n) => n + 1);
315
+ try {
316
+ if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
317
+ return;
342
318
  }
343
- return;
344
- }
345
- if (key.rightArrow) {
346
- if (cursorRef.current < valueRef.current.length) {
347
- cursorRef.current += 1;
348
- forceRender((n) => n + 1);
319
+ if (key.return) {
320
+ onSubmit?.(valueRef.current);
321
+ return;
349
322
  }
350
- return;
351
- }
352
- if (key.backspace || key.delete) {
353
- if (cursorRef.current > 0) {
354
- const v2 = valueRef.current;
355
- const next2 = v2.slice(0, cursorRef.current - 1) + v2.slice(cursorRef.current);
356
- cursorRef.current -= 1;
357
- valueRef.current = next2;
358
- onChange(next2);
323
+ if (key.leftArrow) {
324
+ if (cursorRef.current > 0) {
325
+ cursorRef.current -= 1;
326
+ forceRender((n) => n + 1);
327
+ }
328
+ return;
359
329
  }
360
- return;
330
+ if (key.rightArrow) {
331
+ if (cursorRef.current < valueRef.current.length) {
332
+ cursorRef.current += 1;
333
+ forceRender((n) => n + 1);
334
+ }
335
+ return;
336
+ }
337
+ if (key.backspace || key.delete) {
338
+ if (cursorRef.current > 0) {
339
+ const v2 = valueRef.current;
340
+ const next2 = v2.slice(0, cursorRef.current - 1) + v2.slice(cursorRef.current);
341
+ cursorRef.current -= 1;
342
+ valueRef.current = next2;
343
+ onChange(next2);
344
+ }
345
+ return;
346
+ }
347
+ if (!input || input.length === 0) return;
348
+ const printable = input.replace(/[\x00-\x1f\x7f]/g, "");
349
+ if (printable.length === 0) return;
350
+ const v = valueRef.current;
351
+ const c = cursorRef.current;
352
+ const next = v.slice(0, c) + printable + v.slice(c);
353
+ cursorRef.current = c + printable.length;
354
+ valueRef.current = next;
355
+ onChange(next);
356
+ } catch {
361
357
  }
362
- const v = valueRef.current;
363
- const c = cursorRef.current;
364
- const next = v.slice(0, c) + input + v.slice(c);
365
- cursorRef.current = c + input.length;
366
- valueRef.current = next;
367
- onChange(next);
368
358
  },
369
359
  { isActive: focus }
370
360
  );
371
361
  if (showCursor && focus) {
372
- const textBeforeCursor = [...valueRef.current].slice(0, cursorRef.current).join("");
373
- const cursorX = 4 + stringWidth(textBeforeCursor);
374
- setCursorPosition({ x: cursorX, y: 0 });
362
+ try {
363
+ const textBeforeCursor = [...valueRef.current].slice(0, cursorRef.current).join("");
364
+ const cursorX = 4 + stringWidth(textBeforeCursor);
365
+ setCursorPosition({ x: cursorX, y: 0 });
366
+ } catch {
367
+ setCursorPosition({ x: 4, y: 0 });
368
+ }
375
369
  }
376
370
  return /* @__PURE__ */ jsx3(Text3, { children: renderWithCursor(valueRef.current, cursorRef.current, placeholder, showCursor && focus) });
377
371
  }
378
372
  function renderWithCursor(value, cursorOffset, placeholder, showCursor) {
379
373
  if (!showCursor) {
380
- return value.length > 0 ? value : placeholder ? chalk2.gray(placeholder) : "";
374
+ return value.length > 0 ? value : placeholder ? chalk.gray(placeholder) : "";
381
375
  }
382
376
  if (value.length === 0) {
383
377
  if (placeholder.length > 0) {
384
- return chalk2.inverse(placeholder[0]) + chalk2.gray(placeholder.slice(1));
378
+ return chalk.inverse(placeholder[0]) + chalk.gray(placeholder.slice(1));
385
379
  }
386
- return chalk2.inverse(" ");
380
+ return chalk.inverse(" ");
387
381
  }
388
382
  const chars = [...value];
389
383
  let rendered = "";
390
384
  for (let i = 0; i < chars.length; i++) {
391
385
  const char = chars[i] ?? "";
392
- rendered += i === cursorOffset ? chalk2.inverse(char) : char;
386
+ rendered += i === cursorOffset ? chalk.inverse(char) : char;
393
387
  }
394
388
  if (cursorOffset >= chars.length) {
395
- rendered += chalk2.inverse(" ");
389
+ rendered += chalk.inverse(" ");
396
390
  }
397
391
  return rendered;
398
392
  }
@@ -607,8 +601,8 @@ function InputArea({ onSubmit, isDisabled, registry }) {
607
601
  import React4 from "react";
608
602
  import { Box as Box5, Text as Text7, useInput as useInput3 } from "ink";
609
603
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
610
- var OPTIONS = ["Allow", "Deny"];
611
- function formatArgs2(args) {
604
+ var OPTIONS = ["Allow", "Allow always (this session)", "Deny"];
605
+ function formatArgs(args) {
612
606
  const entries = Object.entries(args);
613
607
  if (entries.length === 0) return "(no arguments)";
614
608
  return entries.map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`).join(", ");
@@ -623,10 +617,12 @@ function PermissionPrompt({ request }) {
623
617
  setSelected(0);
624
618
  }
625
619
  const doResolve = React4.useCallback(
626
- (allowed) => {
620
+ (index) => {
627
621
  if (resolvedRef.current) return;
628
622
  resolvedRef.current = true;
629
- request.resolve(allowed);
623
+ if (index === 0) request.resolve(true);
624
+ else if (index === 1) request.resolve("allow-session");
625
+ else request.resolve(false);
630
626
  },
631
627
  [request]
632
628
  );
@@ -637,11 +633,13 @@ function PermissionPrompt({ request }) {
637
633
  } else if (key.downArrow || key.rightArrow) {
638
634
  setSelected((prev) => prev < OPTIONS.length - 1 ? prev + 1 : prev);
639
635
  } else if (key.return) {
640
- doResolve(selected === 0);
641
- } else if (input === "y" || input === "a" || input === "1") {
642
- doResolve(true);
643
- } else if (input === "n" || input === "d" || input === "2") {
644
- doResolve(false);
636
+ doResolve(selected);
637
+ } else if (input === "y" || input === "1") {
638
+ doResolve(0);
639
+ } else if (input === "a" || input === "2") {
640
+ doResolve(1);
641
+ } else if (input === "n" || input === "d" || input === "3") {
642
+ doResolve(2);
645
643
  }
646
644
  });
647
645
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
@@ -653,7 +651,7 @@ function PermissionPrompt({ request }) {
653
651
  ] }),
654
652
  /* @__PURE__ */ jsxs5(Text7, { dimColor: true, children: [
655
653
  " ",
656
- formatArgs2(request.toolArgs)
654
+ formatArgs(request.toolArgs)
657
655
  ] }),
658
656
  /* @__PURE__ */ jsx7(Box5, { marginTop: 1, children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsx7(Box5, { marginRight: 2, children: /* @__PURE__ */ jsxs5(Text7, { color: i === selected ? "cyan" : void 0, bold: i === selected, children: [
659
657
  i === selected ? "> " : " ",
@@ -701,11 +699,11 @@ function useSession(props) {
701
699
  setPermissionRequest({
702
700
  toolName: next.toolName,
703
701
  toolArgs: next.toolArgs,
704
- resolve: (allowed) => {
702
+ resolve: (result) => {
705
703
  permissionQueueRef.current.shift();
706
704
  processingRef.current = false;
707
705
  setPermissionRequest(null);
708
- next.resolve(allowed);
706
+ next.resolve(result);
709
707
  setTimeout(() => processNextPermission(), 0);
710
708
  }
711
709
  });
@@ -721,10 +719,12 @@ function useSession(props) {
721
719
  const onTextDelta = (delta) => {
722
720
  setStreamingText((prev) => prev + delta);
723
721
  };
724
- sessionRef.current = new Session({
722
+ const paths = projectPaths(props.cwd ?? process.cwd());
723
+ sessionRef.current = createSession({
725
724
  config: props.config,
726
725
  context: props.context,
727
726
  terminal: NOOP_TERMINAL,
727
+ sessionLogger: new FileSessionLogger(paths.logs),
728
728
  projectInfo: props.projectInfo,
729
729
  sessionStore: props.sessionStore,
730
730
  permissionMode: props.permissionMode,
@@ -750,6 +750,7 @@ var HELP_TEXT = [
750
750
  " /compact [instr] \u2014 Compact context (optional focus instructions)",
751
751
  " /mode [m] \u2014 Show/change permission mode",
752
752
  " /cost \u2014 Show session info",
753
+ " /reset \u2014 Delete settings and exit",
753
754
  " /exit \u2014 Exit CLI"
754
755
  ].join("\n");
755
756
  function handleModeCommand(arg, session, addMessage) {
@@ -795,6 +796,39 @@ async function executeSlashCommand(cmd, parts, session, addMessage, setMessages,
795
796
  Messages: ${session.getMessageCount()}`
796
797
  });
797
798
  return true;
799
+ case "permissions": {
800
+ const mode = session.getPermissionMode();
801
+ const sessionAllowed = session.getSessionAllowedTools();
802
+ const lines = [`Permission mode: ${mode}`];
803
+ if (sessionAllowed.length > 0) {
804
+ lines.push(`Session-approved tools: ${sessionAllowed.join(", ")}`);
805
+ } else {
806
+ lines.push("No session-approved tools.");
807
+ }
808
+ addMessage({ role: "system", content: lines.join("\n") });
809
+ return true;
810
+ }
811
+ case "context": {
812
+ const ctx = session.getContextState();
813
+ addMessage({
814
+ role: "system",
815
+ content: `Context: ${ctx.usedTokens.toLocaleString()} / ${ctx.maxTokens.toLocaleString()} tokens (${Math.round(ctx.usedPercentage)}%)`
816
+ });
817
+ return true;
818
+ }
819
+ case "reset": {
820
+ const { existsSync: exists, unlinkSync: unlink } = await import("fs");
821
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
822
+ const settingsPath = `${home}/.robota/settings.json`;
823
+ if (exists(settingsPath)) {
824
+ unlink(settingsPath);
825
+ addMessage({ role: "system", content: `Deleted ${settingsPath}. Exiting...` });
826
+ } else {
827
+ addMessage({ role: "system", content: "No user settings found." });
828
+ }
829
+ setTimeout(() => exit(), 500);
830
+ return true;
831
+ }
798
832
  case "exit":
799
833
  exit();
800
834
  return true;
@@ -835,15 +869,42 @@ function StreamingIndicator({ text }) {
835
869
  async function runSessionPrompt(prompt, session, addMessage, clearStreamingText, setIsThinking, setContextPercentage) {
836
870
  setIsThinking(true);
837
871
  clearStreamingText();
872
+ const historyBefore = session.getHistory().length;
838
873
  try {
839
874
  const response = await session.run(prompt);
840
875
  clearStreamingText();
876
+ const history = session.getHistory();
877
+ const toolLines = [];
878
+ for (let i = historyBefore; i < history.length; i++) {
879
+ const msg = history[i];
880
+ if (msg.role === "assistant" && msg.toolCalls) {
881
+ for (const tc of msg.toolCalls) {
882
+ let value = "";
883
+ try {
884
+ const parsed = JSON.parse(tc.function.arguments);
885
+ const firstVal = Object.values(parsed)[0];
886
+ value = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal);
887
+ } catch {
888
+ value = tc.function.arguments;
889
+ }
890
+ const truncated = value.length > 80 ? value.slice(0, 77) + "..." : value;
891
+ toolLines.push(`${tc.function.name}(${truncated})`);
892
+ }
893
+ }
894
+ }
895
+ if (toolLines.length > 0) {
896
+ addMessage({ role: "tool", content: toolLines.join("\n"), toolName: `${toolLines.length} tools` });
897
+ }
841
898
  addMessage({ role: "assistant", content: response || "(empty response)" });
842
899
  setContextPercentage(session.getContextState().usedPercentage);
843
900
  } catch (err) {
844
901
  clearStreamingText();
845
- const errMsg = err instanceof Error ? err.message : String(err);
846
- addMessage({ role: "system", content: `Error: ${errMsg}` });
902
+ if (err instanceof DOMException && err.name === "AbortError") {
903
+ addMessage({ role: "system", content: "Cancelled." });
904
+ } else {
905
+ const errMsg = err instanceof Error ? err.message : String(err);
906
+ addMessage({ role: "system", content: `Error: ${errMsg}` });
907
+ }
847
908
  } finally {
848
909
  setIsThinking(false);
849
910
  }
@@ -854,7 +915,15 @@ function buildSkillPrompt(input, registry) {
854
915
  const skillCmd = registry.getCommands().find((c) => c.name === cmd && c.source === "skill");
855
916
  if (!skillCmd) return null;
856
917
  const args = parts.slice(1).join(" ").trim();
857
- return args ? `Use the "${cmd}" skill: ${args}` : `Use the "${cmd}" skill: ${skillCmd.description}`;
918
+ const userInstruction = args || skillCmd.description;
919
+ if (skillCmd.skillContent) {
920
+ return `<skill name="${cmd}">
921
+ ${skillCmd.skillContent}
922
+ </skill>
923
+
924
+ Execute the "${cmd}" skill: ${userInstruction}`;
925
+ }
926
+ return `Use the "${cmd}" skill: ${userInstruction}`;
858
927
  }
859
928
  function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamingText, setIsThinking, setContextPercentage, registry) {
860
929
  return useCallback2(
@@ -927,8 +996,9 @@ function App(props) {
927
996
  useInput4(
928
997
  (_input, key) => {
929
998
  if (key.ctrl && _input === "c") exit();
999
+ if (key.escape && isThinking) session.abort();
930
1000
  },
931
- { isActive: !permissionRequest && !isThinking }
1001
+ { isActive: !permissionRequest }
932
1002
  );
933
1003
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
934
1004
  /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
@@ -1048,7 +1118,8 @@ function parseCliArgs() {
1048
1118
  model: { type: "string" },
1049
1119
  "permission-mode": { type: "string" },
1050
1120
  "max-turns": { type: "string" },
1051
- version: { type: "boolean", default: false }
1121
+ version: { type: "boolean", default: false },
1122
+ reset: { type: "boolean", default: false }
1052
1123
  }
1053
1124
  });
1054
1125
  return {
@@ -1059,7 +1130,8 @@ function parseCliArgs() {
1059
1130
  model: values["model"],
1060
1131
  permissionMode: parsePermissionMode(values["permission-mode"]),
1061
1132
  maxTurns: parseMaxTurns(values["max-turns"]),
1062
- version: values["version"] ?? false
1133
+ version: values["version"] ?? false,
1134
+ reset: values["reset"] ?? false
1063
1135
  };
1064
1136
  }
1065
1137
  var PrintTerminal = class {
@@ -1110,6 +1182,83 @@ var PrintTerminal = class {
1110
1182
  } };
1111
1183
  }
1112
1184
  };
1185
+ function getUserSettingsPath() {
1186
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "/";
1187
+ return join2(home, ".robota", "settings.json");
1188
+ }
1189
+ async function ensureConfig(cwd) {
1190
+ const userPath = getUserSettingsPath();
1191
+ const projectPath = join2(cwd, ".robota", "settings.json");
1192
+ const localPath = join2(cwd, ".robota", "settings.local.json");
1193
+ if (existsSync2(userPath) || existsSync2(projectPath) || existsSync2(localPath)) {
1194
+ return;
1195
+ }
1196
+ process.stdout.write("\n");
1197
+ process.stdout.write(" Welcome to Robota CLI!\n");
1198
+ process.stdout.write(" No configuration found. Let's set up your API key.\n");
1199
+ process.stdout.write("\n");
1200
+ const apiKey = await new Promise((resolve) => {
1201
+ process.stdout.write(" Anthropic API key: ");
1202
+ let input = "";
1203
+ const stdin = process.stdin;
1204
+ const wasRaw = stdin.isRaw;
1205
+ stdin.setRawMode(true);
1206
+ stdin.resume();
1207
+ stdin.setEncoding("utf8");
1208
+ const onData = (data) => {
1209
+ for (const ch of data) {
1210
+ if (ch === "\r" || ch === "\n") {
1211
+ stdin.removeListener("data", onData);
1212
+ stdin.setRawMode(wasRaw ?? false);
1213
+ stdin.pause();
1214
+ process.stdout.write("\n");
1215
+ resolve(input.trim());
1216
+ return;
1217
+ } else if (ch === "\x7F" || ch === "\b") {
1218
+ if (input.length > 0) {
1219
+ input = input.slice(0, -1);
1220
+ process.stdout.write("\b \b");
1221
+ }
1222
+ } else if (ch === "") {
1223
+ process.stdout.write("\n");
1224
+ process.exit(0);
1225
+ } else if (ch.charCodeAt(0) >= 32) {
1226
+ input += ch;
1227
+ process.stdout.write("*");
1228
+ }
1229
+ }
1230
+ };
1231
+ stdin.on("data", onData);
1232
+ });
1233
+ if (!apiKey) {
1234
+ process.stderr.write("\n No API key provided. Exiting.\n");
1235
+ process.exit(1);
1236
+ }
1237
+ const settingsDir = dirname(userPath);
1238
+ mkdirSync(settingsDir, { recursive: true });
1239
+ const settings = {
1240
+ provider: {
1241
+ name: "anthropic",
1242
+ model: "claude-sonnet-4-6",
1243
+ apiKey
1244
+ }
1245
+ };
1246
+ writeFileSync(userPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
1247
+ process.stdout.write(`
1248
+ Config saved to ${userPath}
1249
+
1250
+ `);
1251
+ }
1252
+ function resetConfig() {
1253
+ const userPath = getUserSettingsPath();
1254
+ if (existsSync2(userPath)) {
1255
+ unlinkSync(userPath);
1256
+ process.stdout.write(`Deleted ${userPath}
1257
+ `);
1258
+ } else {
1259
+ process.stdout.write("No user settings found.\n");
1260
+ }
1261
+ }
1113
1262
  async function startCli() {
1114
1263
  const args = parseCliArgs();
1115
1264
  if (args.version) {
@@ -1117,7 +1266,12 @@ async function startCli() {
1117
1266
  `);
1118
1267
  return;
1119
1268
  }
1269
+ if (args.reset) {
1270
+ resetConfig();
1271
+ return;
1272
+ }
1120
1273
  const cwd = process.cwd();
1274
+ await ensureConfig(cwd);
1121
1275
  const [config, context, projectInfo] = await Promise.all([
1122
1276
  loadConfig(cwd),
1123
1277
  loadContext(cwd),
@@ -1134,13 +1288,14 @@ async function startCli() {
1134
1288
  process.exit(1);
1135
1289
  }
1136
1290
  const terminal = new PrintTerminal();
1137
- const session = new Session2({
1291
+ const paths = projectPaths2(cwd);
1292
+ const session = createSession2({
1138
1293
  config,
1139
1294
  context,
1140
1295
  terminal,
1296
+ sessionLogger: new FileSessionLogger2(paths.logs),
1141
1297
  projectInfo,
1142
1298
  permissionMode: args.permissionMode,
1143
- systemPromptBuilder: buildSystemPrompt,
1144
1299
  promptForApproval
1145
1300
  });
1146
1301
  const response = await session.run(prompt);