Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publishConfig": {
"access": "public"
},
"version": "1.3.8",
"version": "1.3.9",
"description": "Generic bash tool for AI agents, compatible with AI SDK",
"type": "module",
"main": "dist/index.js",
Expand Down
1 change: 1 addition & 0 deletions src/files/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export async function* streamFiles(
export async function getFilePaths(
options: LoadFilesOptions,
): Promise<string[]> {
"use step";
const paths: string[] = [];

if (options.uploadDirectory) {
Expand Down
2 changes: 2 additions & 0 deletions src/sandbox/just-bash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export interface JustBashLike {
readFile: (path: string) => Promise<string>;
writeFile: (path: string, content: string) => Promise<void>;
};
limits: unknown;
state: unknown;
}

/**
Expand Down
37 changes: 32 additions & 5 deletions src/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,21 @@ import { getFilePaths, streamFiles } from "./files/loader.js";
import {
createJustBashSandbox,
isJustBash,
JustBashLike,
wrapJustBash,
} from "./sandbox/just-bash.js";
import { isVercelSandbox, wrapVercelSandbox } from "./sandbox/vercel.js";
import { createBashExecuteTool } from "./tools/bash.js";
import { createReadFileTool } from "./tools/read-file.js";
import { createWriteFileTool } from "./tools/write-file.js";
import { createToolPrompt } from "./tools-prompt.js";
import type { BashToolkit, CreateBashToolOptions, Sandbox } from "./types.js";
import type {
BashToolkit,
CommandResult,
CreateBashToolOptions,
Sandbox,
} from "./types.js";
import { ToolExecuteFunction } from "ai";

const DEFAULT_DESTINATION = "/workspace";
const VERCEL_SANDBOX_DESTINATION = "/vercel/sandbox/workspace";
Expand Down Expand Up @@ -44,8 +51,28 @@ const DEFAULT_MAX_FILES = 1000;
* ```
*/
export async function createBashTool(
options: CreateBashToolOptions = {},
options: CreateBashToolOptions = {}
): Promise<BashToolkit> {
const tools = await createBashToolStep(options);
const bashStep = tools.bash.execute!;
tools.bash.execute = async (input, toolOptions) => {
const result = (await bashStep(input, toolOptions)) as CommandResult;
// For just-bash we need to copy the FS from the returned sandbox
if (isJustBash(result.sandbox) && isJustBash(options.sandbox)) {
const sandbox = options.sandbox as JustBashLike;
sandbox.fs = result.sandbox.fs;
sandbox.limits = result.sandbox.limits;
sandbox.state = result.sandbox.state;
}
return result;
};
return tools;
}

export async function createBashToolStep(
options: CreateBashToolOptions = {}
): Promise<BashToolkit> {
"use step";
// Determine default destination based on sandbox type
const defaultDestination =
options.sandbox && isVercelSandbox(options.sandbox)
Expand Down Expand Up @@ -86,7 +113,7 @@ export async function createBashTool(
throw new Error(
`Too many files to upload: ${fileList.length} files exceeds the limit of ${maxFiles}. ` +
`Either increase maxFiles, use a more restrictive include pattern in uploadDirectory, ` +
`or write files to the sandbox yourself before calling createBashTool.`,
`or write files to the sandbox yourself before calling createBashTool.`
);
}

Expand Down Expand Up @@ -135,7 +162,7 @@ export async function createBashTool(
if (maxFiles > 0 && fileList.length > maxFiles) {
throw new Error(
`Too many files: ${fileList.length} files exceeds the limit of ${maxFiles}. ` +
`Either increase maxFiles or use a more restrictive include pattern in uploadDirectory.`,
`Either increase maxFiles or use a more restrictive include pattern in uploadDirectory.`
);
}

Expand Down Expand Up @@ -166,7 +193,7 @@ export async function createBashTool(
throw new Error(
`Too many files to load: ${fileList.length} files exceeds the limit of ${maxFiles}. ` +
`Either increase maxFiles, use a more restrictive include pattern in uploadDirectory, ` +
`or provide your own sandbox with files already written.`,
`or provide your own sandbox with files already written.`
);
}

Expand Down
2 changes: 2 additions & 0 deletions src/tools/bash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export function createBashExecuteTool(options: CreateBashToolOptions) {
description: generateDescription(options),
inputSchema: bashSchema,
execute: async ({ command: originalCommand }) => {
"use step";
// Allow modification of command before execution
let command = originalCommand;
if (onBeforeBashCall) {
Expand All @@ -134,6 +135,7 @@ export function createBashExecuteTool(options: CreateBashToolOptions) {
...result,
stdout: truncateOutput(result.stdout, maxOutputLength, "stdout"),
stderr: truncateOutput(result.stderr, maxOutputLength, "stderr"),
sandbox,
};

// Allow modification of result after execution
Expand Down
1 change: 1 addition & 0 deletions src/tools/read-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function createReadFileTool(options: CreateReadFileToolOptions) {
description: "Read the contents of a file from the sandbox.",
inputSchema: readFileSchema,
execute: async ({ path }) => {
"use step";
const resolvedPath = nodePath.posix.resolve(cwd, path);
const content = await sandbox.readFile(resolvedPath);
return { content };
Expand Down
1 change: 1 addition & 0 deletions src/tools/write-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export function createWriteFileTool(options: CreateWriteFileToolOptions) {
"Write content to a file in the sandbox. Creates parent directories if needed.",
inputSchema: writeFileSchema,
execute: async ({ path, content }) => {
"use step";
const resolvedPath = nodePath.posix.resolve(cwd, path);
await sandbox.writeFiles([{ path: resolvedPath, content }]);
return { success: true };
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface CommandResult {
stdout: string;
stderr: string;
exitCode: number;
sandbox: Sandbox;
}

export interface Sandbox {
Expand Down
Loading