@townco/agent 0.1.106 → 0.1.108

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.
@@ -5,7 +5,7 @@ import { tool } from "langchain";
5
5
  import { z } from "zod";
6
6
  import { createLogger } from "../../../logger.js";
7
7
  import { getSessionSandbox } from "../../e2b-sandbox-manager";
8
- import { getSessionContext, getToolOutputDir, hasSessionContext, } from "../../session-context";
8
+ import { getEmitUpdate, getSessionContext, getToolOutputDir, hasSessionContext, } from "../../session-context";
9
9
  const logger = createLogger("e2b-tools");
10
10
  // Cached API key from Town proxy
11
11
  let _cachedApiKey = null;
@@ -13,7 +13,7 @@ let _apiKeyFetchPromise = null;
13
13
  /**
14
14
  * Get E2B API key from Town proxy (with caching).
15
15
  */
16
- async function getTownE2BApiKey() {
16
+ export async function getTownE2BApiKey() {
17
17
  if (_cachedApiKey) {
18
18
  return _cachedApiKey;
19
19
  }
@@ -89,7 +89,17 @@ function makeE2BToolsInternal(getSandbox) {
89
89
  if (result.error) {
90
90
  if (output)
91
91
  output += "\n";
92
- output += `[error] ${result.error.name}: ${result.error.value}`;
92
+ // Include the full traceback if available
93
+ // E2B's ExecutionError has name, value, and traceback properties
94
+ const traceback = result.error.traceback;
95
+ if (traceback?.trim()) {
96
+ // Traceback includes full error with line numbers
97
+ output += `[error]\n${traceback}`;
98
+ }
99
+ else {
100
+ // Fallback: construct a basic error message
101
+ output += `[error] ${result.error.name}: ${result.error.value}`;
102
+ }
93
103
  }
94
104
  // Handle result value (charts, images, etc.)
95
105
  if (result.results && result.results.length > 0) {
@@ -116,6 +126,21 @@ function makeE2BToolsInternal(getSandbox) {
116
126
  }
117
127
  }
118
128
  }
129
+ // Emit file change notification (code might have created/modified files)
130
+ const emitUpdate = getEmitUpdate();
131
+ if (emitUpdate) {
132
+ logger.debug("Emitting sandbox_files_changed event from RunCode");
133
+ emitUpdate({
134
+ sessionUpdate: "sandbox_files_changed",
135
+ _meta: {
136
+ source: "tool",
137
+ toolName: "Sandbox_RunCode",
138
+ },
139
+ });
140
+ }
141
+ else {
142
+ logger.warn("emitUpdate not available in RunCode - file change event not sent");
143
+ }
119
144
  return output.trim() || "(no output)";
120
145
  }
121
146
  catch (error) {
@@ -164,10 +189,38 @@ function makeE2BToolsInternal(getSandbox) {
164
189
  if (result.exitCode !== 0) {
165
190
  output += `\n[exit code: ${result.exitCode}]`;
166
191
  }
192
+ // Emit file change notification (bash commands might have created/modified files)
193
+ const emitUpdate = getEmitUpdate();
194
+ if (emitUpdate) {
195
+ emitUpdate({
196
+ sessionUpdate: "sandbox_files_changed",
197
+ _meta: {
198
+ source: "tool",
199
+ toolName: "Sandbox_RunBash",
200
+ },
201
+ });
202
+ }
167
203
  return output.trim() || "(no output)";
168
204
  }
169
205
  catch (error) {
170
206
  logger.error("Error executing bash command", { error });
207
+ // E2B may throw with stdout/stderr attached to the error
208
+ const e = error;
209
+ let output = "";
210
+ if (e.stdout) {
211
+ output += e.stdout;
212
+ }
213
+ if (e.stderr) {
214
+ if (output)
215
+ output += "\n";
216
+ output += `[stderr]\n${e.stderr}`;
217
+ }
218
+ if (e.exitCode !== undefined) {
219
+ output += `\n[exit code: ${e.exitCode}]`;
220
+ }
221
+ if (output) {
222
+ return output.trim();
223
+ }
171
224
  return `Error executing command: ${error instanceof Error ? error.message : String(error)}`;
172
225
  }
173
226
  }, {
@@ -217,6 +270,24 @@ function makeE2BToolsInternal(getSandbox) {
217
270
  const sandbox = await getSandbox();
218
271
  try {
219
272
  await sandbox.files.write(filePath, content);
273
+ // Emit file change notification
274
+ const emitUpdate = getEmitUpdate();
275
+ if (emitUpdate) {
276
+ logger.debug("Emitting sandbox_files_changed event", { filePath });
277
+ emitUpdate({
278
+ sessionUpdate: "sandbox_files_changed",
279
+ paths: [filePath],
280
+ _meta: {
281
+ source: "tool",
282
+ toolName: "Sandbox_WriteFile",
283
+ },
284
+ });
285
+ }
286
+ else {
287
+ logger.warn("emitUpdate not available - file change event not sent", {
288
+ filePath,
289
+ });
290
+ }
220
291
  return `Successfully wrote ${content.length} bytes to ${filePath}`;
221
292
  }
222
293
  catch (error) {
@@ -236,62 +307,110 @@ function makeE2BToolsInternal(getSandbox) {
236
307
  writeSandboxFile.prettyName = "Write Sandbox File";
237
308
  // biome-ignore lint/suspicious/noExplicitAny: Need to add custom properties to LangChain tool
238
309
  writeSandboxFile.icon = "Edit";
239
- // Tool 5: Download File from Sandbox to Artifacts
240
- const downloadFromSandbox = tool(async ({ sandboxPath, fileName }) => {
310
+ // Tool 5: Share File from Sandbox (download to artifacts, upload to Supabase)
311
+ const shareSandboxFile = tool(async ({ sandboxPath, fileName }) => {
241
312
  if (!hasSessionContext()) {
242
- throw new Error("Sandbox_DownloadFile requires session context");
313
+ throw new Error("Sandbox_Share requires session context");
243
314
  }
244
315
  const sandbox = await getSandbox();
316
+ const { sessionId } = getSessionContext();
245
317
  const toolOutputDir = getToolOutputDir("E2B");
246
318
  try {
247
- // Read file from sandbox
248
- const content = await sandbox.files.read(sandboxPath);
249
- // Determine output filename
319
+ // Step 1: Download from sandbox to local artifacts
320
+ // Use base64 encoding to safely transfer binary data
321
+ const result = await sandbox.commands.run(`base64 ${sandboxPath}`);
322
+ if (result.exitCode !== 0) {
323
+ throw new Error(`Failed to read file: ${result.stderr}`);
324
+ }
250
325
  const outputFileName = fileName || path.basename(sandboxPath);
251
326
  const outputPath = path.join(toolOutputDir, outputFileName);
252
- // Ensure directory exists
253
327
  await fs.mkdir(toolOutputDir, { recursive: true });
254
- // Write to artifacts
255
- await fs.writeFile(outputPath, content);
256
- // Generate URL for display
257
- const { sessionId } = getSessionContext();
258
- const port = process.env.PORT || "3100";
259
- const hostname = process.env.BIND_HOST || "localhost";
260
- const baseUrl = process.env.AGENT_BASE_URL || `http://${hostname}:${port}`;
261
- const fileUrl = `${baseUrl}/static/.sessions/${sessionId}/artifacts/tool-E2B/${outputFileName}`;
262
- return `Downloaded ${sandboxPath} to artifacts.\nURL: ${fileUrl}`;
328
+ // Decode base64 and write binary file
329
+ const fileBuffer = Buffer.from(result.stdout.trim(), "base64");
330
+ await fs.writeFile(outputPath, fileBuffer);
331
+ // Step 2: Upload to Supabase Storage
332
+ const shedAuth = getShedAuth();
333
+ if (!shedAuth) {
334
+ // Fallback to local URL if not authenticated
335
+ const port = process.env.PORT || "3100";
336
+ const hostname = process.env.BIND_HOST || "localhost";
337
+ const baseUrl = process.env.AGENT_BASE_URL || `http://${hostname}:${port}`;
338
+ const localUrl = `${baseUrl}/static/.sessions/${sessionId}/artifacts/tool-E2B/${outputFileName}`;
339
+ return `File saved locally: ${localUrl}\n\n(Login with 'town login' to enable public sharing via Supabase)`;
340
+ }
341
+ // Get signed upload URL from Shed
342
+ const storagePath = `shared/${outputFileName}`;
343
+ const uploadUrlResponse = await fetch(`${shedAuth.shedUrl}/api/artifacts/url?key=${encodeURIComponent(storagePath)}&upload=true&kind=user`, {
344
+ headers: {
345
+ "Content-Type": "application/json",
346
+ "x-api-key": shedAuth.accessToken,
347
+ },
348
+ });
349
+ if (!uploadUrlResponse.ok) {
350
+ throw new Error(`Failed to get upload URL: ${await uploadUrlResponse.text()}`);
351
+ }
352
+ const { url: uploadUrl } = await uploadUrlResponse.json();
353
+ // Upload file to Supabase
354
+ const fileContent = await fs.readFile(outputPath);
355
+ const uploadResponse = await fetch(uploadUrl, {
356
+ method: "PUT",
357
+ body: fileContent,
358
+ headers: {
359
+ "Content-Type": "application/octet-stream",
360
+ },
361
+ });
362
+ if (!uploadResponse.ok) {
363
+ throw new Error(`Upload failed: ${await uploadResponse.text()}`);
364
+ }
365
+ // Get public signed URL
366
+ const publicUrlResponse = await fetch(`${shedAuth.shedUrl}/api/artifacts/url?key=${encodeURIComponent(storagePath)}&kind=user`, {
367
+ headers: {
368
+ "x-api-key": shedAuth.accessToken,
369
+ },
370
+ });
371
+ if (!publicUrlResponse.ok) {
372
+ throw new Error(`Failed to get public URL: ${await publicUrlResponse.text()}`);
373
+ }
374
+ const { url: publicUrl } = await publicUrlResponse.json();
375
+ return `File shared successfully!\n\nPublic URL: ${publicUrl}`;
263
376
  }
264
377
  catch (error) {
265
- logger.error("Error downloading file from sandbox", {
266
- error,
378
+ const errorMessage = error instanceof Error ? error.message : String(error);
379
+ const errorStack = error instanceof Error ? error.stack : undefined;
380
+ logger.error("Error sharing file from sandbox", {
381
+ error: errorMessage,
382
+ stack: errorStack,
267
383
  sandboxPath,
268
384
  });
269
- return `Error downloading file: ${error instanceof Error ? error.message : String(error)}`;
385
+ return `Error sharing file: ${errorMessage}`;
270
386
  }
271
387
  }, {
272
- name: "Sandbox_DownloadFile",
273
- description: "Download a file from the cloud sandbox to the session's artifacts directory. " +
274
- "Use to save generated files, plots, or outputs for the user to access.",
388
+ name: "Sandbox_Share",
389
+ description: "Share a file from the sandbox by uploading to Supabase Storage. " +
390
+ "Returns a public URL that can be shared with others. " +
391
+ "Files are downloaded from sandbox to local artifacts, then uploaded to cloud storage.",
275
392
  schema: z.object({
276
- sandboxPath: z.string().describe("Path to the file in the sandbox"),
393
+ sandboxPath: z
394
+ .string()
395
+ .describe("Path to file in sandbox (e.g., /home/user/output.png)"),
277
396
  fileName: z
278
397
  .string()
279
398
  .optional()
280
- .describe("Optional output filename (defaults to original name)"),
399
+ .describe("Optional filename for shared file (defaults to original name)"),
281
400
  }),
282
401
  });
283
402
  // biome-ignore lint/suspicious/noExplicitAny: Need to add custom properties to LangChain tool
284
- downloadFromSandbox.prettyName = "Download from Sandbox";
403
+ shareSandboxFile.prettyName = "Share from Sandbox";
285
404
  // biome-ignore lint/suspicious/noExplicitAny: Need to add custom properties to LangChain tool
286
- downloadFromSandbox.icon = "Download";
405
+ shareSandboxFile.icon = "Share";
287
406
  // Tool 6: Upload Library Document to Sandbox
288
407
  const uploadLibraryDocument = tool(async ({ document_id }) => {
289
408
  const sandbox = await getSandbox();
290
409
  try {
291
410
  const libraryApiUrl = process.env.LIBRARY_API_URL;
292
- const libraryApiKey = process.env.LIBRARY_ROOT_API_KEY;
411
+ const libraryApiKey = process.env.LIBRARY_API_KEY;
293
412
  if (!libraryApiUrl || !libraryApiKey) {
294
- throw new Error("LIBRARY_API_URL and LIBRARY_ROOT_API_KEY environment variables are required");
413
+ throw new Error("LIBRARY_API_URL and LIBRARY_API_KEY environment variables are required");
295
414
  }
296
415
  const response = await fetch(`${libraryApiUrl}/sandbox/upload_document_to_sandbox`, {
297
416
  method: "POST",
@@ -338,13 +457,185 @@ function makeE2BToolsInternal(getSandbox) {
338
457
  past: "Uploaded document {document_id}",
339
458
  paramKey: "document_id",
340
459
  };
460
+ // Tool 7: Generate Image in Sandbox
461
+ const generateImage = tool(async ({ prompt }) => {
462
+ const sandbox = await getSandbox();
463
+ try {
464
+ // JavaScript script to call Gemini API using @google/genai
465
+ const escapedPrompt = prompt
466
+ .replace(/\\/g, "\\\\")
467
+ .replace(/"/g, '\\"')
468
+ .replace(/\n/g, "\\n");
469
+ const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || "";
470
+ if (!apiKey) {
471
+ return "Error: GEMINI_API_KEY or GOOGLE_API_KEY environment variable is required for image generation";
472
+ }
473
+ const escapedApiKey = apiKey
474
+ .replace(/\\/g, "\\\\")
475
+ .replace(/"/g, '\\"');
476
+ const script = `
477
+ const { GoogleGenAI } = require('@google/genai');
478
+
479
+ async function generateImage() {
480
+ try {
481
+ const client = new GoogleGenAI({ apiKey: "${escapedApiKey}" });
482
+
483
+ const response = await client.models.generateContent({
484
+ model: "gemini-3-pro-image-preview",
485
+ contents: [{ text: "${escapedPrompt}" }],
486
+ config: {
487
+ responseModalities: ["TEXT", "IMAGE"],
488
+ },
489
+ });
490
+
491
+ if (!response.candidates || response.candidates.length === 0) {
492
+ console.log(JSON.stringify({ error: "No response from the model" }));
493
+ process.exit(1);
494
+ }
495
+
496
+ const candidate = response.candidates[0];
497
+ if (!candidate.content || !candidate.content.parts) {
498
+ console.log(JSON.stringify({ error: "No content parts in response" }));
499
+ process.exit(1);
500
+ }
501
+
502
+ let imageData = null;
503
+ let mimeType = "image/png";
504
+
505
+ // Debug: log the structure we're getting
506
+ console.error("DEBUG parts:", JSON.stringify(candidate.content.parts.map(p => ({
507
+ hasText: !!p.text,
508
+ hasInlineData: !!p.inlineData,
509
+ inlineDataKeys: p.inlineData ? Object.keys(p.inlineData) : []
510
+ }))));
511
+
512
+ for (const part of candidate.content.parts) {
513
+ if (part.inlineData && part.inlineData.data) {
514
+ imageData = part.inlineData.data;
515
+ mimeType = part.inlineData.mimeType || "image/png";
516
+ console.error("DEBUG found image, mimeType:", mimeType);
517
+ console.error("DEBUG imageData type:", typeof imageData);
518
+ console.error("DEBUG imageData isBuffer:", Buffer.isBuffer(imageData));
519
+ console.error("DEBUG imageData length:", imageData.length);
520
+ console.error("DEBUG first 50 chars:", imageData.toString().substring(0, 50));
521
+ break;
522
+ }
523
+ }
524
+
525
+ if (!imageData) {
526
+ console.log(JSON.stringify({
527
+ error: "No image in response",
528
+ parts: candidate.content.parts
529
+ }));
530
+ process.exit(1);
531
+ }
532
+
533
+ // Save image
534
+ const fs = require('fs');
535
+ const ext = mimeType === 'image/jpeg' ? 'jpg' : 'png';
536
+ const path = \`/home/user/generated_image.\${ext}\`;
537
+ const buffer = Buffer.from(imageData, 'base64');
538
+ fs.writeFileSync(path, buffer);
539
+ console.error("DEBUG wrote file, size:", buffer.length);
540
+
541
+ console.log(JSON.stringify({ success: true, path }));
542
+ } catch (error) {
543
+ console.log(JSON.stringify({
544
+ error: error.message,
545
+ stack: error.stack
546
+ }));
547
+ process.exit(1);
548
+ }
549
+ }
550
+
551
+ generateImage();
552
+ `;
553
+ await sandbox.files.write("/home/user/gen_img.js", script);
554
+ // Install @google/genai if not already installed (should be pre-installed in template)
555
+ await sandbox.commands.run("cd /home/user && npm install @google/genai");
556
+ const result = await sandbox.commands.run("cd /home/user && node gen_img.js");
557
+ logger.info("Image generation command result", {
558
+ exitCode: result.exitCode,
559
+ stdout: result.stdout,
560
+ stderr: result.stderr,
561
+ });
562
+ if (result.exitCode !== 0) {
563
+ // Try to parse JSON error from stderr (where our script outputs errors)
564
+ try {
565
+ const errorOutput = JSON.parse(result.stderr);
566
+ logger.error("Image generation failed (parsed)", { errorOutput });
567
+ const errorMsg = errorOutput.error || "Unknown error";
568
+ const traceback = errorOutput.traceback
569
+ ? `\n\nTraceback:\n${errorOutput.traceback}`
570
+ : "";
571
+ return `Image generation failed: ${errorMsg}${traceback}`;
572
+ }
573
+ catch {
574
+ // If JSON parsing fails, try stdout, then show raw output
575
+ try {
576
+ const errorOutput = JSON.parse(result.stdout);
577
+ logger.error("Image generation failed (parsed from stdout)", {
578
+ errorOutput,
579
+ });
580
+ return `Image generation failed: ${errorOutput.error || "Unknown error"}`;
581
+ }
582
+ catch {
583
+ // Show raw output
584
+ logger.error("Image generation failed (raw)", {
585
+ stdout: result.stdout,
586
+ stderr: result.stderr,
587
+ });
588
+ return `Image generation failed (exit code ${result.exitCode}):\nStderr: ${result.stderr}\nStdout: ${result.stdout}`;
589
+ }
590
+ }
591
+ }
592
+ const output = JSON.parse(result.stdout);
593
+ if (output.error) {
594
+ logger.error("Image generation returned error", {
595
+ error: output.error,
596
+ });
597
+ return `Image generation failed: ${output.error}`;
598
+ }
599
+ logger.info("Image generated successfully", { path: output.path });
600
+ return `Image generated successfully at ${output.path}. Use Sandbox_Share to download and share it.`;
601
+ }
602
+ catch (error) {
603
+ logger.error("Error generating image (exception)", {
604
+ error,
605
+ message: error instanceof Error ? error.message : String(error),
606
+ stack: error instanceof Error ? error.stack : undefined,
607
+ });
608
+ return `Error generating image: ${error instanceof Error ? error.message : String(error)}`;
609
+ }
610
+ }, {
611
+ name: "Sandbox_GenerateImage",
612
+ description: "Generate an image using Google Gemini in the sandbox. " +
613
+ "Image is saved to sandbox filesystem at /home/user/. " +
614
+ "Use Sandbox_Share to download and share it with the user.",
615
+ schema: z.object({
616
+ prompt: z
617
+ .string()
618
+ .describe("Detailed description of the image to generate"),
619
+ }),
620
+ });
621
+ // biome-ignore lint/suspicious/noExplicitAny: Need to add custom properties to LangChain tool
622
+ generateImage.prettyName = "Generate Image";
623
+ // biome-ignore lint/suspicious/noExplicitAny: Need to add custom properties to LangChain tool
624
+ generateImage.icon = "Image";
625
+ // biome-ignore lint/suspicious/noExplicitAny: Need to add custom properties to LangChain tool
626
+ generateImage.verbiage = {
627
+ active: "Generating image",
628
+ past: "Generated image",
629
+ paramKey: "prompt",
630
+ };
341
631
  return [
342
632
  runCode,
343
633
  runBash,
344
634
  readSandboxFile,
345
635
  writeSandboxFile,
346
- downloadFromSandbox,
636
+ shareSandboxFile,
347
637
  uploadLibraryDocument,
638
+ generateImage,
348
639
  ];
349
640
  }
350
641
  /**
@@ -1,3 +1,4 @@
1
+ import type { SessionUpdateNotification } from "./agent-runner.js";
1
2
  /**
2
3
  * Session context available to tools during agent execution.
3
4
  * This provides deterministic, session-scoped file storage.
@@ -10,6 +11,11 @@ export interface SessionContext {
10
11
  /** Artifacts directory: <agentDir>/.sessions/<sessionId>/artifacts */
11
12
  artifactsDir: string;
12
13
  }
14
+ /**
15
+ * EmitUpdate callback context for tools to emit session updates.
16
+ * Tools can access this to emit events like sandbox file changes.
17
+ */
18
+ type EmitUpdateCallback = (update: SessionUpdateNotification) => void;
13
19
  /**
14
20
  * Run a function with an abort signal available via AsyncLocalStorage.
15
21
  * Tools can access the signal using getAbortSignal().
@@ -30,6 +36,16 @@ export declare function getAbortSignal(): AbortSignal | undefined;
30
36
  * Returns false if no abort signal is available.
31
37
  */
32
38
  export declare function isAborted(): boolean;
39
+ /**
40
+ * Get the current emitUpdate callback.
41
+ * Returns undefined if called outside of an emitUpdate context.
42
+ */
43
+ export declare function getEmitUpdate(): EmitUpdateCallback | undefined;
44
+ /**
45
+ * Bind an async generator to an emitUpdate callback context so that every iteration
46
+ * runs with the emitUpdate callback available.
47
+ */
48
+ export declare function bindGeneratorToEmitUpdate<T, R, N = unknown>(emitUpdate: EmitUpdateCallback, generator: AsyncGenerator<T, R, N>): AsyncGenerator<T, R, N>;
33
49
  /**
34
50
  * Run a function with session context available via AsyncLocalStorage.
35
51
  * Tools can access the context using getSessionContext().
@@ -58,3 +74,4 @@ export declare function hasSessionContext(): boolean;
58
74
  * @returns Absolute path to the tool's output directory
59
75
  */
60
76
  export declare function getToolOutputDir(toolName: string): string;
77
+ export {};
@@ -6,6 +6,7 @@ const sessionStorage = new AsyncLocalStorage();
6
6
  * Tools can access this to check if the current operation has been cancelled.
7
7
  */
8
8
  const abortSignalStorage = new AsyncLocalStorage();
9
+ const emitUpdateStorage = new AsyncLocalStorage();
9
10
  /**
10
11
  * Run a function with an abort signal available via AsyncLocalStorage.
11
12
  * Tools can access the signal using getAbortSignal().
@@ -55,6 +56,40 @@ export function isAborted() {
55
56
  const signal = abortSignalStorage.getStore();
56
57
  return signal?.aborted ?? false;
57
58
  }
59
+ /**
60
+ * Get the current emitUpdate callback.
61
+ * Returns undefined if called outside of an emitUpdate context.
62
+ */
63
+ export function getEmitUpdate() {
64
+ return emitUpdateStorage.getStore();
65
+ }
66
+ /**
67
+ * Bind an async generator to an emitUpdate callback context so that every iteration
68
+ * runs with the emitUpdate callback available.
69
+ */
70
+ export function bindGeneratorToEmitUpdate(emitUpdate, generator) {
71
+ const boundNext = (value) => emitUpdateStorage.run(emitUpdate, () => generator.next(value));
72
+ const boundReturn = generator.return
73
+ ? (value) => emitUpdateStorage.run(emitUpdate, () => generator.return?.(value))
74
+ : undefined;
75
+ const boundThrow = generator.throw
76
+ ? (e) => emitUpdateStorage.run(emitUpdate, () => generator.throw?.(e))
77
+ : undefined;
78
+ const boundGenerator = {
79
+ next: boundNext,
80
+ return: boundReturn,
81
+ throw: boundThrow,
82
+ [Symbol.asyncIterator]() {
83
+ return this;
84
+ },
85
+ [Symbol.asyncDispose]: async () => {
86
+ if (Symbol.asyncDispose in generator) {
87
+ await generator[Symbol.asyncDispose]();
88
+ }
89
+ },
90
+ };
91
+ return boundGenerator;
92
+ }
58
93
  /**
59
94
  * Run a function with session context available via AsyncLocalStorage.
60
95
  * Tools can access the context using getSessionContext().
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  /** Built-in tool types. */
3
- export declare const zBuiltInToolType: z.ZodUnion<readonly [z.ZodLiteral<"artifacts">, z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"town_web_search">, z.ZodLiteral<"filesystem">, z.ZodLiteral<"generate_image">, z.ZodLiteral<"town_generate_image">, z.ZodLiteral<"browser">, z.ZodLiteral<"document_extract">, z.ZodLiteral<"code_sandbox">]>;
3
+ export declare const zBuiltInToolType: z.ZodUnion<readonly [z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"town_web_search">, z.ZodLiteral<"browser">, z.ZodLiteral<"document_extract">, z.ZodLiteral<"code_sandbox">]>;
4
4
  /** Subagent configuration schema for Task tools. */
5
5
  export declare const zSubagentConfig: z.ZodObject<{
6
6
  agentName: z.ZodString;
@@ -23,12 +23,9 @@ declare const zDirectTool: z.ZodObject<{
23
23
  }, z.core.$strip>>>;
24
24
  }, z.core.$strip>;
25
25
  /** Tool type - can be a built-in tool string or custom tool object. */
26
- export declare const zToolType: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"artifacts">, z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"town_web_search">, z.ZodLiteral<"filesystem">, z.ZodLiteral<"generate_image">, z.ZodLiteral<"town_generate_image">, z.ZodLiteral<"browser">, z.ZodLiteral<"document_extract">, z.ZodLiteral<"code_sandbox">]>, z.ZodObject<{
26
+ export declare const zToolType: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"town_web_search">, z.ZodLiteral<"browser">, z.ZodLiteral<"document_extract">, z.ZodLiteral<"code_sandbox">]>, z.ZodObject<{
27
27
  type: z.ZodLiteral<"custom">;
28
28
  modulePath: z.ZodString;
29
- }, z.core.$strip>, z.ZodObject<{
30
- type: z.ZodLiteral<"filesystem">;
31
- working_directory: z.ZodOptional<z.ZodString>;
32
29
  }, z.core.$strip>, z.ZodObject<{
33
30
  type: z.ZodLiteral<"direct">;
34
31
  name: z.ZodString;
@@ -1,14 +1,10 @@
1
1
  import { z } from "zod";
2
2
  /** Built-in tool types. */
3
3
  export const zBuiltInToolType = z.union([
4
- z.literal("artifacts"),
5
4
  z.literal("todo_write"),
6
5
  z.literal("get_weather"),
7
6
  z.literal("web_search"),
8
7
  z.literal("town_web_search"),
9
- z.literal("filesystem"),
10
- z.literal("generate_image"),
11
- z.literal("town_generate_image"),
12
8
  z.literal("browser"),
13
9
  z.literal("document_extract"),
14
10
  z.literal("code_sandbox"),
@@ -18,11 +14,6 @@ const zCustomTool = z.object({
18
14
  type: z.literal("custom"),
19
15
  modulePath: z.string(),
20
16
  });
21
- /** Filesystem tool schema. */
22
- const zFilesystemTool = z.object({
23
- type: z.literal("filesystem"),
24
- working_directory: z.string().optional(),
25
- });
26
17
  /** Subagent configuration schema for Task tools. */
27
18
  export const zSubagentConfig = z.object({
28
19
  agentName: z.string(),
@@ -42,9 +33,4 @@ const zDirectTool = z.object({
42
33
  subagentConfigs: z.array(zSubagentConfig).optional(),
43
34
  });
44
35
  /** Tool type - can be a built-in tool string or custom tool object. */
45
- export const zToolType = z.union([
46
- zBuiltInToolType,
47
- zCustomTool,
48
- zFilesystemTool,
49
- zDirectTool,
50
- ]);
36
+ export const zToolType = z.union([zBuiltInToolType, zCustomTool, zDirectTool]);