@robota-sdk/agent-tools 3.0.0-beta.60 → 3.0.0-beta.61

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.
@@ -30,17 +30,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ E2BSandboxClient: () => E2BSandboxClient,
33
34
  FunctionTool: () => FunctionTool,
35
+ InMemorySandboxClient: () => InMemorySandboxClient,
34
36
  OpenAPITool: () => OpenAPITool,
35
37
  ToolRegistry: () => ToolRegistry,
38
+ applyWorkspaceManifest: () => applyWorkspaceManifest,
36
39
  bashTool: () => bashTool,
40
+ createBashTool: () => createBashTool,
41
+ createEditTool: () => createEditTool,
37
42
  createFunctionTool: () => createFunctionTool,
38
43
  createOpenAPITool: () => createOpenAPITool,
44
+ createReadTool: () => createReadTool,
45
+ createWriteTool: () => createWriteTool,
39
46
  createZodFunctionTool: () => createZodFunctionTool,
40
47
  editTool: () => editTool,
41
48
  globTool: () => globTool,
42
49
  grepTool: () => grepTool,
43
50
  readTool: () => readTool,
51
+ validateWorkspaceManifestPath: () => validateWorkspaceManifestPath,
44
52
  webFetchTool: () => webFetchTool,
45
53
  webSearchTool: () => webSearchTool,
46
54
  writeTool: () => writeTool,
@@ -48,6 +56,275 @@ __export(index_exports, {
48
56
  });
49
57
  module.exports = __toCommonJS(index_exports);
50
58
 
59
+ // src/sandbox/e2b-sandbox-client.ts
60
+ var E2BSandboxClient = class {
61
+ sandbox;
62
+ connectSandbox;
63
+ createSandboxFromSnapshot;
64
+ constructor(options) {
65
+ this.sandbox = options.sandbox;
66
+ this.connectSandbox = options.connectSandbox;
67
+ this.createSandboxFromSnapshot = options.createSandboxFromSnapshot;
68
+ }
69
+ async run(command, options) {
70
+ const result = await this.sandbox.commands.run(command, {
71
+ background: false,
72
+ timeoutMs: options?.timeoutMs,
73
+ cwd: options?.workingDirectory
74
+ });
75
+ return {
76
+ stdout: result.stdout ?? "",
77
+ stderr: result.stderr ?? "",
78
+ exitCode: result.exitCode ?? result.exit_code ?? 0
79
+ };
80
+ }
81
+ async readFile(path) {
82
+ const content = await this.sandbox.files.read(path);
83
+ return typeof content === "string" ? content : Buffer.from(content).toString("utf8");
84
+ }
85
+ async writeFile(path, content) {
86
+ await this.sandbox.files.write(path, content);
87
+ }
88
+ async snapshot() {
89
+ if (this.sandbox.createSnapshot) {
90
+ const snapshot = await this.sandbox.createSnapshot();
91
+ const snapshotId = snapshot.snapshotId ?? snapshot.id;
92
+ if (!snapshotId) {
93
+ throw new Error("E2B createSnapshot() did not return a snapshot id.");
94
+ }
95
+ return snapshotId;
96
+ }
97
+ const sandboxId = this.sandbox.sandboxId;
98
+ if (!sandboxId) {
99
+ throw new Error("E2B sandboxId is required to create a resumable sandbox snapshot.");
100
+ }
101
+ if (!this.sandbox.pause) {
102
+ throw new Error("E2B sandbox adapter does not expose pause().");
103
+ }
104
+ await this.sandbox.pause();
105
+ return sandboxId;
106
+ }
107
+ async restore(snapshotId) {
108
+ if (this.createSandboxFromSnapshot) {
109
+ this.sandbox = await this.createSandboxFromSnapshot(snapshotId);
110
+ return;
111
+ }
112
+ if (this.connectSandbox) {
113
+ this.sandbox = await this.connectSandbox(snapshotId);
114
+ return;
115
+ }
116
+ if (this.sandbox.sandboxId === snapshotId && this.sandbox.connect) {
117
+ this.sandbox = await this.sandbox.connect();
118
+ return;
119
+ }
120
+ throw new Error(
121
+ "E2B sandbox restore requires connectSandbox(snapshotId) or sandbox.connect()."
122
+ );
123
+ }
124
+ };
125
+
126
+ // src/sandbox/in-memory-sandbox-client.ts
127
+ var InMemorySandboxClient = class {
128
+ files = /* @__PURE__ */ new Map();
129
+ snapshots = /* @__PURE__ */ new Map();
130
+ runHandler;
131
+ snapshotSequence = 0;
132
+ constructor(options = {}) {
133
+ for (const [path, content] of Object.entries(options.files ?? {})) {
134
+ this.files.set(path, content);
135
+ }
136
+ this.runHandler = options.runHandler;
137
+ }
138
+ async run(command, options) {
139
+ if (this.runHandler) {
140
+ return this.runHandler(command, options, this.files);
141
+ }
142
+ return { stdout: "", stderr: "", exitCode: 0 };
143
+ }
144
+ async readFile(path) {
145
+ const content = this.files.get(path);
146
+ if (content === void 0) {
147
+ throw new Error(`Sandbox file not found: ${path}`);
148
+ }
149
+ return content;
150
+ }
151
+ async writeFile(path, content) {
152
+ this.files.set(path, content);
153
+ }
154
+ async snapshot() {
155
+ const snapshotId = `snapshot-${++this.snapshotSequence}`;
156
+ this.snapshots.set(snapshotId, new Map(this.files));
157
+ return snapshotId;
158
+ }
159
+ async restore(snapshotId) {
160
+ const snapshot = this.snapshots.get(snapshotId);
161
+ if (!snapshot) {
162
+ throw new Error(`Sandbox snapshot not found: ${snapshotId}`);
163
+ }
164
+ this.files.clear();
165
+ for (const [path, content] of snapshot.entries()) {
166
+ this.files.set(path, content);
167
+ }
168
+ }
169
+ getFile(path) {
170
+ return this.files.get(path);
171
+ }
172
+ };
173
+
174
+ // src/sandbox/workspace-manifest.ts
175
+ var import_promises = require("fs/promises");
176
+ var import_node_path = require("path");
177
+ var DEFAULT_TARGET_ROOT = "/workspace";
178
+ var WINDOWS_ABSOLUTE_PATH_PATTERN = /^[A-Za-z]:[\\/]/;
179
+ var SHELL_QUOTE_PATTERN = /'/g;
180
+ async function applyWorkspaceManifest(sandboxClient, manifest, options = {}) {
181
+ if (sandboxClient.applyManifest) {
182
+ return sandboxClient.applyManifest(manifest, options);
183
+ }
184
+ const targetRoot = normalizeSandboxRoot(options.targetRoot ?? DEFAULT_TARGET_ROOT);
185
+ const appliedEntries = [];
186
+ for (const [rawPath, entry] of Object.entries(manifest.entries)) {
187
+ const path = validateWorkspaceManifestPath(rawPath);
188
+ const targetPath = joinSandboxPath(targetRoot, path);
189
+ appliedEntries.push(
190
+ await applyManifestEntry(sandboxClient, path, targetPath, targetRoot, entry, options)
191
+ );
192
+ }
193
+ return { entries: appliedEntries };
194
+ }
195
+ function validateWorkspaceManifestPath(path) {
196
+ if (path.length === 0) {
197
+ throw new Error("workspace manifest path must not be empty");
198
+ }
199
+ if (path.includes("\0")) {
200
+ throw new Error("workspace manifest path must not contain NUL bytes");
201
+ }
202
+ if (path.startsWith("/") || path.startsWith("\\") || WINDOWS_ABSOLUTE_PATH_PATTERN.test(path)) {
203
+ throw new Error("workspace manifest path must be workspace-relative");
204
+ }
205
+ const parts = path.replace(/\\/g, "/").split("/").filter(Boolean);
206
+ if (parts.length === 0) {
207
+ throw new Error("workspace manifest path must not resolve to the workspace root");
208
+ }
209
+ if (parts.some((part) => part === "..")) {
210
+ throw new Error("workspace manifest path cannot contain traversal segments");
211
+ }
212
+ const normalizedParts = parts.filter((part) => part !== ".");
213
+ if (normalizedParts.length === 0) {
214
+ throw new Error("workspace manifest path must not resolve to the workspace root");
215
+ }
216
+ return normalizedParts.join("/");
217
+ }
218
+ async function applyManifestEntry(sandboxClient, path, targetPath, targetRoot, entry, options) {
219
+ switch (entry.type) {
220
+ case "file":
221
+ await writeSandboxFile(sandboxClient, targetPath, targetRoot, entry.content);
222
+ return createAppliedEntry(path, entry.type);
223
+ case "dir":
224
+ await createSandboxDirectory(sandboxClient, targetPath);
225
+ return createAppliedEntry(path, entry.type);
226
+ case "localFile":
227
+ await copyLocalFile(sandboxClient, entry.src, targetPath, targetRoot, options);
228
+ return createAppliedEntry(path, entry.type);
229
+ case "localDir":
230
+ await copyLocalDirectory(sandboxClient, entry.src, targetPath, options);
231
+ return createAppliedEntry(path, entry.type);
232
+ case "gitRepo":
233
+ await cloneGitRepository(sandboxClient, entry, targetPath);
234
+ return createAppliedEntry(path, entry.type);
235
+ case "s3Mount":
236
+ case "gcsMount":
237
+ case "r2Mount":
238
+ case "azureBlobMount":
239
+ return {
240
+ path,
241
+ type: entry.type,
242
+ status: "unsupported",
243
+ message: `${entry.type} requires a provider-specific sandbox adapter.`
244
+ };
245
+ default:
246
+ return assertUnreachable(entry);
247
+ }
248
+ }
249
+ function createAppliedEntry(path, type) {
250
+ return { path, type, status: "applied" };
251
+ }
252
+ async function copyLocalFile(sandboxClient, source, targetPath, targetRoot, options) {
253
+ const hostSourcePath = resolveHostSourcePath(source, options.hostRoot);
254
+ const content = await (0, import_promises.readFile)(hostSourcePath, "utf8");
255
+ await writeSandboxFile(sandboxClient, targetPath, targetRoot, content);
256
+ }
257
+ async function copyLocalDirectory(sandboxClient, source, targetPath, options) {
258
+ const hostSourcePath = resolveHostSourcePath(source, options.hostRoot);
259
+ await copyLocalDirectoryRecursive(sandboxClient, hostSourcePath, targetPath);
260
+ }
261
+ async function copyLocalDirectoryRecursive(sandboxClient, sourcePath, targetPath) {
262
+ await createSandboxDirectory(sandboxClient, targetPath);
263
+ const entries = await (0, import_promises.readdir)(sourcePath, { withFileTypes: true });
264
+ for (const entry of entries) {
265
+ const childSourcePath = (0, import_node_path.join)(sourcePath, entry.name);
266
+ const childTargetPath = joinSandboxPath(targetPath, entry.name);
267
+ if (entry.isDirectory()) {
268
+ await copyLocalDirectoryRecursive(sandboxClient, childSourcePath, childTargetPath);
269
+ continue;
270
+ }
271
+ if (entry.isFile()) {
272
+ const content = await (0, import_promises.readFile)(childSourcePath, "utf8");
273
+ await sandboxClient.writeFile(childTargetPath, content);
274
+ }
275
+ }
276
+ }
277
+ async function cloneGitRepository(sandboxClient, entry, targetPath) {
278
+ const shallowArgs = entry.shallow === false ? "" : " --depth 1";
279
+ const refArgs = entry.ref ? ` --branch ${quoteShellArg(entry.ref)}` : "";
280
+ await runSandboxCommand(
281
+ sandboxClient,
282
+ `git clone${shallowArgs}${refArgs} ${quoteShellArg(entry.url)} ${quoteShellArg(targetPath)}`
283
+ );
284
+ }
285
+ async function writeSandboxFile(sandboxClient, targetPath, targetRoot, content) {
286
+ const parentPath = import_node_path.posix.dirname(targetPath);
287
+ if (parentPath !== targetRoot) {
288
+ await createSandboxDirectory(sandboxClient, parentPath);
289
+ }
290
+ await sandboxClient.writeFile(targetPath, content);
291
+ }
292
+ async function createSandboxDirectory(sandboxClient, targetPath) {
293
+ await runSandboxCommand(sandboxClient, `mkdir -p ${quoteShellArg(targetPath)}`);
294
+ }
295
+ async function runSandboxCommand(sandboxClient, command) {
296
+ const result = await sandboxClient.run(command);
297
+ if (result.exitCode !== 0) {
298
+ throw new Error(
299
+ `workspace manifest command failed: ${command}
300
+ ${result.stderr ?? result.stdout}`
301
+ );
302
+ }
303
+ }
304
+ function resolveHostSourcePath(source, hostRoot) {
305
+ return (0, import_node_path.isAbsolute)(source) ? (0, import_node_path.resolve)(source) : (0, import_node_path.resolve)(hostRoot ?? process.cwd(), source);
306
+ }
307
+ function normalizeSandboxRoot(root) {
308
+ const normalized = root.replace(/\\/g, "/").replace(/\/+$/, "");
309
+ if (!normalized.startsWith("/")) {
310
+ throw new Error("workspace manifest targetRoot must be an absolute sandbox path");
311
+ }
312
+ return normalized.length === 0 ? "/" : normalized;
313
+ }
314
+ function joinSandboxPath(root, path) {
315
+ const normalizedRoot = normalizeSandboxRoot(root);
316
+ if (normalizedRoot === "/") {
317
+ return `/${path}`;
318
+ }
319
+ return `${normalizedRoot}/${path}`;
320
+ }
321
+ function quoteShellArg(value) {
322
+ return `'${value.replace(SHELL_QUOTE_PATTERN, "'\\''")}'`;
323
+ }
324
+ function assertUnreachable(value) {
325
+ throw new Error(`unsupported workspace manifest entry: ${JSON.stringify(value)}`);
326
+ }
327
+
51
328
  // src/registry/tool-registry.ts
52
329
  var import_agent_core = require("@robota-sdk/agent-core");
53
330
  var import_agent_core2 = require("@robota-sdk/agent-core");
@@ -860,9 +1137,33 @@ var BashSchema = import_zod.z.object({
860
1137
  timeout: import_zod.z.number().optional().describe("Optional timeout in milliseconds (max 600000). Default is 120000 (2 minutes)"),
861
1138
  workingDirectory: import_zod.z.string().optional().describe("Working directory for the command. Defaults to the current working directory")
862
1139
  });
863
- async function runBash(args) {
1140
+ async function runBash(args, options = {}) {
864
1141
  const { command, timeout = DEFAULT_TIMEOUT_MS, workingDirectory } = args;
865
- return new Promise((resolve3) => {
1142
+ if (options.sandboxClient) {
1143
+ try {
1144
+ const sandboxResult = await options.sandboxClient.run(command, {
1145
+ timeoutMs: timeout,
1146
+ workingDirectory
1147
+ });
1148
+ const output = sandboxResult.stderr ? `${sandboxResult.stdout}
1149
+ stderr:
1150
+ ${sandboxResult.stderr}` : sandboxResult.stdout;
1151
+ const result = {
1152
+ success: true,
1153
+ output,
1154
+ exitCode: sandboxResult.exitCode
1155
+ };
1156
+ return JSON.stringify(result);
1157
+ } catch (err) {
1158
+ const result = {
1159
+ success: false,
1160
+ output: "",
1161
+ error: err instanceof Error ? err.message : String(err)
1162
+ };
1163
+ return JSON.stringify(result);
1164
+ }
1165
+ }
1166
+ return new Promise((resolve4) => {
866
1167
  const stdoutChunks = [];
867
1168
  const stderrChunks = [];
868
1169
  let timedOut = false;
@@ -891,7 +1192,7 @@ async function runBash(args) {
891
1192
  if (settled) return;
892
1193
  settled = true;
893
1194
  clearTimeout(timer);
894
- resolve3(JSON.stringify(result));
1195
+ resolve4(JSON.stringify(result));
895
1196
  }
896
1197
  child.on("error", (err) => {
897
1198
  settle({
@@ -924,17 +1225,20 @@ ${stderr}` : stdout;
924
1225
  });
925
1226
  });
926
1227
  }
927
- var bashTool = createZodFunctionTool(
928
- "Bash",
929
- "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.",
930
- BashSchema,
931
- async (params) => {
932
- return runBash(params);
933
- }
934
- );
1228
+ function createBashTool(options = {}) {
1229
+ return createZodFunctionTool(
1230
+ "Bash",
1231
+ "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.",
1232
+ BashSchema,
1233
+ async (params) => {
1234
+ return runBash(params, options);
1235
+ }
1236
+ );
1237
+ }
1238
+ var bashTool = createBashTool();
935
1239
 
936
1240
  // src/builtins/read-tool.ts
937
- var import_promises = require("fs/promises");
1241
+ var import_promises2 = require("fs/promises");
938
1242
  var import_zod2 = require("zod");
939
1243
  var DEFAULT_LIMIT = 2e3;
940
1244
  var ReadSchema = import_zod2.z.object({
@@ -961,94 +1265,113 @@ function formatWithLineNumbers(lines, startLine) {
961
1265
  return `${lineNum} ${line}`;
962
1266
  }).join("\n");
963
1267
  }
964
- async function readFileTool(args) {
1268
+ function formatReadResult(filePath, content, startLine, limit) {
1269
+ const allLines = content.split("\n");
1270
+ if (allLines[allLines.length - 1] === "") {
1271
+ allLines.pop();
1272
+ }
1273
+ const zeroBasedStart = startLine - 1;
1274
+ const selectedLines = allLines.slice(zeroBasedStart, zeroBasedStart + limit);
1275
+ const output = formatWithLineNumbers(selectedLines, startLine);
1276
+ const totalLines = allLines.length;
1277
+ const returnedLines = selectedLines.length;
1278
+ const header = returnedLines < totalLines ? `[File: ${filePath} (lines ${startLine}-${startLine + returnedLines - 1} of ${totalLines})]
1279
+ ` : `[File: ${filePath} (${totalLines} lines)]
1280
+ `;
1281
+ const result = {
1282
+ success: true,
1283
+ output: header + output
1284
+ };
1285
+ return JSON.stringify(result);
1286
+ }
1287
+ async function readFileTool(args, options = {}) {
965
1288
  const { filePath, offset, limit = DEFAULT_LIMIT } = args;
966
1289
  const startLine = offset !== void 0 && offset > 0 ? offset : 1;
1290
+ if (options.sandboxClient) {
1291
+ try {
1292
+ const content2 = await options.sandboxClient.readFile(filePath);
1293
+ return formatReadResult(filePath, content2, startLine, limit);
1294
+ } catch (err) {
1295
+ const result = {
1296
+ success: false,
1297
+ output: "",
1298
+ error: err instanceof Error ? err.message : String(err)
1299
+ };
1300
+ return JSON.stringify(result);
1301
+ }
1302
+ }
967
1303
  let fileStats;
968
1304
  try {
969
- fileStats = await (0, import_promises.stat)(filePath);
1305
+ fileStats = await (0, import_promises2.stat)(filePath);
970
1306
  } catch (err) {
971
- const result2 = {
1307
+ const result = {
972
1308
  success: false,
973
1309
  output: "",
974
1310
  error: `File not found: ${filePath}`
975
1311
  };
976
- return JSON.stringify(result2);
1312
+ return JSON.stringify(result);
977
1313
  }
978
1314
  if (!fileStats.isFile()) {
979
- const result2 = {
1315
+ const result = {
980
1316
  success: false,
981
1317
  output: "",
982
1318
  error: `Path is not a file: ${filePath}`
983
1319
  };
984
- return JSON.stringify(result2);
1320
+ return JSON.stringify(result);
985
1321
  }
986
1322
  let buffer;
987
1323
  try {
988
- buffer = await (0, import_promises.readFile)(filePath);
1324
+ buffer = await (0, import_promises2.readFile)(filePath);
989
1325
  } catch (err) {
990
- const result2 = {
1326
+ const result = {
991
1327
  success: false,
992
1328
  output: "",
993
1329
  error: err instanceof Error ? err.message : String(err)
994
1330
  };
995
- return JSON.stringify(result2);
1331
+ return JSON.stringify(result);
996
1332
  }
997
1333
  if (isBinary(buffer)) {
998
- const result2 = {
1334
+ const result = {
999
1335
  success: false,
1000
1336
  output: "",
1001
1337
  error: `Binary file not supported: ${filePath}`
1002
1338
  };
1003
- return JSON.stringify(result2);
1339
+ return JSON.stringify(result);
1004
1340
  }
1005
1341
  const content = buffer.toString("utf8");
1006
- const allLines = content.split("\n");
1007
- if (allLines[allLines.length - 1] === "") {
1008
- allLines.pop();
1009
- }
1010
- const zeroBasedStart = startLine - 1;
1011
- const selectedLines = allLines.slice(zeroBasedStart, zeroBasedStart + limit);
1012
- const output = formatWithLineNumbers(selectedLines, startLine);
1013
- const totalLines = allLines.length;
1014
- const returnedLines = selectedLines.length;
1015
- const header = returnedLines < totalLines ? `[File: ${filePath} (lines ${startLine}-${startLine + returnedLines - 1} of ${totalLines})]
1016
- ` : `[File: ${filePath} (${totalLines} lines)]
1017
- `;
1018
- const result = {
1019
- success: true,
1020
- output: header + output
1021
- };
1022
- return JSON.stringify(result);
1342
+ return formatReadResult(filePath, content, startLine, limit);
1023
1343
  }
1024
- var readTool = createZodFunctionTool(
1025
- "Read",
1026
- "Reads a file from the local filesystem.\n\nBy default, reads up to 2000 lines from the beginning of the file. You can optionally specify offset and limit for partial reads.\n\nResults are returned using cat -n format, with line numbers starting at 1.\n\nThe file_path parameter must be an absolute path, not a relative path.",
1027
- ReadSchema,
1028
- async (params) => {
1029
- return readFileTool(params);
1030
- }
1031
- );
1344
+ function createReadTool(options = {}) {
1345
+ return createZodFunctionTool(
1346
+ "Read",
1347
+ "Reads a file from the local filesystem.\n\nBy default, reads up to 2000 lines from the beginning of the file. You can optionally specify offset and limit for partial reads.\n\nResults are returned using cat -n format, with line numbers starting at 1.\n\nThe file_path parameter must be an absolute path, not a relative path.",
1348
+ ReadSchema,
1349
+ async (params) => {
1350
+ return readFileTool(params, options);
1351
+ }
1352
+ );
1353
+ }
1354
+ var readTool = createReadTool();
1032
1355
 
1033
1356
  // src/builtins/write-tool.ts
1034
1357
  var import_zod3 = require("zod");
1035
1358
 
1036
1359
  // src/builtins/atomic-file-write.ts
1037
1360
  var import_node_crypto = require("crypto");
1038
- var import_promises2 = require("fs/promises");
1039
- var import_node_path = require("path");
1361
+ var import_promises3 = require("fs/promises");
1362
+ var import_node_path2 = require("path");
1040
1363
  var TEMP_RANDOM_BYTES = 6;
1041
1364
  var PRESERVED_MODE_BITS = 4095;
1042
1365
  var MISSING_FILE_ERROR_CODE = "ENOENT";
1043
1366
  function createTempFilePath(filePath) {
1044
- const dir = (0, import_node_path.dirname)(filePath);
1045
- const name = (0, import_node_path.basename)(filePath);
1367
+ const dir = (0, import_node_path2.dirname)(filePath);
1368
+ const name = (0, import_node_path2.basename)(filePath);
1046
1369
  const suffix = (0, import_node_crypto.randomBytes)(TEMP_RANDOM_BYTES).toString("hex");
1047
- return (0, import_node_path.join)(dir, `.${name}.robota-tmp-${process.pid}-${Date.now()}-${suffix}`);
1370
+ return (0, import_node_path2.join)(dir, `.${name}.robota-tmp-${process.pid}-${Date.now()}-${suffix}`);
1048
1371
  }
1049
1372
  async function readExistingMode(filePath) {
1050
1373
  try {
1051
- const fileStats = await (0, import_promises2.stat)(filePath);
1374
+ const fileStats = await (0, import_promises3.stat)(filePath);
1052
1375
  return fileStats.mode & PRESERVED_MODE_BITS;
1053
1376
  } catch (error) {
1054
1377
  if (error instanceof Error && hasErrorCode(error, MISSING_FILE_ERROR_CODE)) return void 0;
@@ -1059,18 +1382,18 @@ function hasErrorCode(error, code) {
1059
1382
  return "code" in error && error.code === code;
1060
1383
  }
1061
1384
  async function atomicWriteUtf8File(filePath, content) {
1062
- const dir = (0, import_node_path.dirname)(filePath);
1063
- await (0, import_promises2.mkdir)(dir, { recursive: true });
1385
+ const dir = (0, import_node_path2.dirname)(filePath);
1386
+ await (0, import_promises3.mkdir)(dir, { recursive: true });
1064
1387
  const existingMode = await readExistingMode(filePath);
1065
1388
  const tempFilePath = createTempFilePath(filePath);
1066
1389
  try {
1067
- await (0, import_promises2.writeFile)(tempFilePath, content, "utf8");
1390
+ await (0, import_promises3.writeFile)(tempFilePath, content, "utf8");
1068
1391
  if (existingMode !== void 0) {
1069
- await (0, import_promises2.chmod)(tempFilePath, existingMode);
1392
+ await (0, import_promises3.chmod)(tempFilePath, existingMode);
1070
1393
  }
1071
- await (0, import_promises2.rename)(tempFilePath, filePath);
1394
+ await (0, import_promises3.rename)(tempFilePath, filePath);
1072
1395
  } catch (error) {
1073
- await (0, import_promises2.rm)(tempFilePath, { force: true }).catch(() => void 0);
1396
+ await (0, import_promises3.rm)(tempFilePath, { force: true }).catch(() => void 0);
1074
1397
  throw error;
1075
1398
  }
1076
1399
  }
@@ -1080,10 +1403,14 @@ var WriteSchema = import_zod3.z.object({
1080
1403
  filePath: import_zod3.z.string().describe("The absolute path to the file to write"),
1081
1404
  content: import_zod3.z.string().describe("The content to write to the file")
1082
1405
  });
1083
- async function writeFileTool(args) {
1406
+ async function writeFileTool(args, options = {}) {
1084
1407
  const { filePath, content } = args;
1085
1408
  try {
1086
- await atomicWriteUtf8File(filePath, content);
1409
+ if (options.sandboxClient) {
1410
+ await options.sandboxClient.writeFile(filePath, content);
1411
+ } else {
1412
+ await atomicWriteUtf8File(filePath, content);
1413
+ }
1087
1414
  const result = {
1088
1415
  success: true,
1089
1416
  output: `Written ${Buffer.byteLength(content, "utf8")} bytes to ${filePath}`
@@ -1098,17 +1425,20 @@ async function writeFileTool(args) {
1098
1425
  return JSON.stringify(result);
1099
1426
  }
1100
1427
  }
1101
- var writeTool = createZodFunctionTool(
1102
- "Write",
1103
- "Writes a file to the local filesystem. This will overwrite an existing file if one exists.\n\nALWAYS prefer the Edit tool for modifying existing files \u2014 it only sends the diff. Only use this tool to create new files or for complete rewrites.\n\nNEVER create documentation files (*.md) or README files unless explicitly requested by the user.",
1104
- WriteSchema,
1105
- async (params) => {
1106
- return writeFileTool(params);
1107
- }
1108
- );
1428
+ function createWriteTool(options = {}) {
1429
+ return createZodFunctionTool(
1430
+ "Write",
1431
+ "Writes a file to the local filesystem. This will overwrite an existing file if one exists.\n\nALWAYS prefer the Edit tool for modifying existing files \u2014 it only sends the diff. Only use this tool to create new files or for complete rewrites.\n\nNEVER create documentation files (*.md) or README files unless explicitly requested by the user.",
1432
+ WriteSchema,
1433
+ async (params) => {
1434
+ return writeFileTool(params, options);
1435
+ }
1436
+ );
1437
+ }
1438
+ var writeTool = createWriteTool();
1109
1439
 
1110
1440
  // src/builtins/edit-tool.ts
1111
- var import_promises3 = require("fs/promises");
1441
+ var import_promises4 = require("fs/promises");
1112
1442
  var import_zod4 = require("zod");
1113
1443
  var EditSchema = import_zod4.z.object({
1114
1444
  filePath: import_zod4.z.string().describe("The absolute path to the file to modify"),
@@ -1118,11 +1448,11 @@ var EditSchema = import_zod4.z.object({
1118
1448
  "Replace all occurrences of old_string (default: false). Useful for renaming variables"
1119
1449
  )
1120
1450
  });
1121
- async function editFileTool(args) {
1451
+ async function editFileTool(args, options = {}) {
1122
1452
  const { filePath, oldString, newString, replaceAll = false } = args;
1123
1453
  let content;
1124
1454
  try {
1125
- content = await (0, import_promises3.readFile)(filePath, "utf8");
1455
+ content = options.sandboxClient ? await options.sandboxClient.readFile(filePath) : await (0, import_promises4.readFile)(filePath, "utf8");
1126
1456
  } catch (err) {
1127
1457
  const result2 = {
1128
1458
  success: false,
@@ -1154,7 +1484,11 @@ async function editFileTool(args) {
1154
1484
  }
1155
1485
  const updated = replaceAll ? content.split(oldString).join(newString) : content.slice(0, content.indexOf(oldString)) + newString + content.slice(content.indexOf(oldString) + oldString.length);
1156
1486
  try {
1157
- await atomicWriteUtf8File(filePath, updated);
1487
+ if (options.sandboxClient) {
1488
+ await options.sandboxClient.writeFile(filePath, updated);
1489
+ } else {
1490
+ await atomicWriteUtf8File(filePath, updated);
1491
+ }
1158
1492
  } catch (err) {
1159
1493
  const result2 = {
1160
1494
  success: false,
@@ -1173,18 +1507,21 @@ async function editFileTool(args) {
1173
1507
  };
1174
1508
  return JSON.stringify(result);
1175
1509
  }
1176
- var editTool = createZodFunctionTool(
1177
- "Edit",
1178
- "Performs exact string replacements in files.\n\nYou must use the Read tool at least once before editing. When editing text from Read output, preserve the exact indentation.\n\nThe edit will FAIL if old_string is not unique in the file. Either provide more surrounding context to make it unique, or use replace_all to change every instance.\n\nALWAYS prefer editing existing files over creating new ones.",
1179
- EditSchema,
1180
- async (params) => {
1181
- return editFileTool(params);
1182
- }
1183
- );
1510
+ function createEditTool(options = {}) {
1511
+ return createZodFunctionTool(
1512
+ "Edit",
1513
+ "Performs exact string replacements in files.\n\nYou must use the Read tool at least once before editing. When editing text from Read output, preserve the exact indentation.\n\nThe edit will FAIL if old_string is not unique in the file. Either provide more surrounding context to make it unique, or use replace_all to change every instance.\n\nALWAYS prefer editing existing files over creating new ones.",
1514
+ EditSchema,
1515
+ async (params) => {
1516
+ return editFileTool(params, options);
1517
+ }
1518
+ );
1519
+ }
1520
+ var editTool = createEditTool();
1184
1521
 
1185
1522
  // src/builtins/glob-tool.ts
1186
- var import_promises4 = require("fs/promises");
1187
- var import_node_path2 = require("path");
1523
+ var import_promises5 = require("fs/promises");
1524
+ var import_node_path3 = require("path");
1188
1525
  var import_fast_glob = __toESM(require("fast-glob"), 1);
1189
1526
  var import_zod5 = require("zod");
1190
1527
  var DEFAULT_MAX_RESULTS = 1e3;
@@ -1199,7 +1536,7 @@ var GlobSchema = import_zod5.z.object({
1199
1536
  });
1200
1537
  async function globFileTool(args) {
1201
1538
  const { pattern, path: basePath } = args;
1202
- const cwd = basePath ? (0, import_node_path2.resolve)(basePath) : process.cwd();
1539
+ const cwd = basePath ? (0, import_node_path3.resolve)(basePath) : process.cwd();
1203
1540
  let matches;
1204
1541
  try {
1205
1542
  matches = await (0, import_fast_glob.default)(pattern, {
@@ -1218,9 +1555,9 @@ async function globFileTool(args) {
1218
1555
  }
1219
1556
  const withMtime = await Promise.all(
1220
1557
  matches.map(async (p) => {
1221
- const absPath = (0, import_node_path2.resolve)(cwd, p);
1558
+ const absPath = (0, import_node_path3.resolve)(cwd, p);
1222
1559
  try {
1223
- const s = await (0, import_promises4.stat)(absPath);
1560
+ const s = await (0, import_promises5.stat)(absPath);
1224
1561
  return { path: p, mtime: s.mtimeMs };
1225
1562
  } catch {
1226
1563
  return { path: p, mtime: 0 };
@@ -1255,8 +1592,8 @@ var globTool = createZodFunctionTool(
1255
1592
  );
1256
1593
 
1257
1594
  // src/builtins/grep-tool.ts
1258
- var import_promises5 = require("fs/promises");
1259
- var import_node_path3 = require("path");
1595
+ var import_promises6 = require("fs/promises");
1596
+ var import_node_path4 = require("path");
1260
1597
  var import_zod6 = require("zod");
1261
1598
  var GrepSchema = import_zod6.z.object({
1262
1599
  pattern: import_zod6.z.string().describe("The regular expression pattern to search for in file contents"),
@@ -1284,16 +1621,16 @@ async function collectFiles(dirPath, glob) {
1284
1621
  async function walk(current) {
1285
1622
  let entryNames;
1286
1623
  try {
1287
- entryNames = await (0, import_promises5.readdir)(current);
1624
+ entryNames = await (0, import_promises6.readdir)(current);
1288
1625
  } catch {
1289
1626
  return;
1290
1627
  }
1291
1628
  for (const name of entryNames) {
1292
1629
  if (name === "node_modules" || name === ".git") continue;
1293
- const fullPath = (0, import_node_path3.join)(current, name);
1630
+ const fullPath = (0, import_node_path4.join)(current, name);
1294
1631
  let fileStat;
1295
1632
  try {
1296
- fileStat = await (0, import_promises5.stat)(fullPath);
1633
+ fileStat = await (0, import_promises6.stat)(fullPath);
1297
1634
  } catch {
1298
1635
  continue;
1299
1636
  }
@@ -1349,7 +1686,7 @@ async function grepFileTool(args) {
1349
1686
  contextLines = 0,
1350
1687
  outputMode = "files_with_matches"
1351
1688
  } = args;
1352
- const targetPath = searchPath ? (0, import_node_path3.resolve)(searchPath) : process.cwd();
1689
+ const targetPath = searchPath ? (0, import_node_path4.resolve)(searchPath) : process.cwd();
1353
1690
  let regex;
1354
1691
  try {
1355
1692
  regex = new RegExp(pattern);
@@ -1363,7 +1700,7 @@ async function grepFileTool(args) {
1363
1700
  }
1364
1701
  let targetStat;
1365
1702
  try {
1366
- targetStat = await (0, import_promises5.stat)(targetPath);
1703
+ targetStat = await (0, import_promises6.stat)(targetPath);
1367
1704
  } catch {
1368
1705
  const result2 = {
1369
1706
  success: false,
@@ -1382,7 +1719,7 @@ async function grepFileTool(args) {
1382
1719
  for (const filePath of files) {
1383
1720
  let content;
1384
1721
  try {
1385
- const buffer = await (0, import_promises5.readFile)(filePath);
1722
+ const buffer = await (0, import_promises6.readFile)(filePath);
1386
1723
  const checkLen = Math.min(buffer.length, 8192);
1387
1724
  let hasBinary = false;
1388
1725
  for (let i = 0; i < checkLen; i++) {
@@ -1547,17 +1884,25 @@ var webSearchTool = createZodFunctionTool(
1547
1884
  );
1548
1885
  // Annotate the CommonJS export names for ESM import in node:
1549
1886
  0 && (module.exports = {
1887
+ E2BSandboxClient,
1550
1888
  FunctionTool,
1889
+ InMemorySandboxClient,
1551
1890
  OpenAPITool,
1552
1891
  ToolRegistry,
1892
+ applyWorkspaceManifest,
1553
1893
  bashTool,
1894
+ createBashTool,
1895
+ createEditTool,
1554
1896
  createFunctionTool,
1555
1897
  createOpenAPITool,
1898
+ createReadTool,
1899
+ createWriteTool,
1556
1900
  createZodFunctionTool,
1557
1901
  editTool,
1558
1902
  globTool,
1559
1903
  grepTool,
1560
1904
  readTool,
1905
+ validateWorkspaceManifestPath,
1561
1906
  webFetchTool,
1562
1907
  webSearchTool,
1563
1908
  writeTool,