Filesystem API Reference
Complete API documentation for AG-Kit filesystem tools, including method signatures, input/output schemas, and practical usage examples.API Overview
The filesystem API provides tools that work across multiple execution backends with consistent interfaces and type safety.Available Tools
Individual Tools
- ReadTool - Read file contents with encoding support
- WriteTool - Write content to files with directory creation
- EditTool - Make targeted edits to existing files
- GlobTool - Find files using glob patterns
- GrepTool - Search file contents with regex patterns
- LsTool - List directory contents with detailed information
Comprehensive Tool
- StrReplaceEditor - Advanced multi-operation file editor for AI coding workflows
Quick Comparison
| Feature | Local | In-Memory | Sandbox |
|---|---|---|---|
| Performance | ✅ Maximum | ✅ High | ⚠️ Network overhead |
| Security | ⚠️ Full access | ✅ Isolated | ✅ Sandboxed |
| Persistence | ✅ Permanent | ❌ Temporary | ✅ Session-based |
| Testing | ⚠️ Side effects | ✅ Perfect | ⚠️ Complex setup |
Setup
Local File Operator
Copy
import { LocalFileOperator } from '@ag-kit/tools/fs';
const context = {
workingDirectory: process.cwd(),
fsOperator: new LocalFileOperator()
};
In-Memory File Operator
Copy
import { InMemoryFileOperator } from '@ag-kit/tools/fs';
import { fs } from 'memfs';
const context = {
workingDirectory: '/virtual',
fsOperator: new InMemoryFileOperator(fs)
};
Sandbox File Operator
Copy
import { SandboxFileOperator } from '@ag-kit/tools/fs';
const context = {
workingDirectory: '/home/user',
fsOperator: new SandboxFileOperator({ sandbox })
};
Transaction Support
Transaction support allows you to group multiple file operations and roll them back if needed. TheTransactionFileOperator wraps any base operator (Local, In-Memory, or Sandbox) to provide atomic operations.
Basic Usage
Copy
import { TransactionFileOperator, TransactionExecutor } from '@ag-kit/tools/fs/transaction';
import { LocalFileOperator } from '@ag-kit/tools/fs';
// Wrap any base operator with transaction support
const baseOperator = new LocalFileOperator(); // or InMemoryFileOperator, SandboxFileOperator
const transactionOperator = new TransactionFileOperator(baseOperator);
const context = {
workingDirectory: process.cwd(),
fsOperator: transactionOperator
};
Manual Transaction Control
Copy
await transactionOperator.beginTransaction();
try {
await writeTool.invoke({
file_path: 'config.json',
content: '{"version": "2.0"}'
});
await editTool.invoke({
file_path: 'package.json',
old_string: '"version": "1.0.0"',
new_string: '"version": "2.0.0"'
});
await transactionOperator.commitTransaction();
} catch (error) {
await transactionOperator.rollbackTransaction(); // All changes reverted
}
Executor Pattern (Recommended)
Copy
import { TransactionExecutor, createTransactionExecutor, withTransaction } from '@ag-kit/tools/fs/transaction';
// Method 1: Using TransactionExecutor class
const executor = new TransactionExecutor(baseOperator);
const result = await executor.executeInTransaction(async (transactionOperator) => {
// All operations are automatically transactional
await writeTool.invoke({
file_path: 'data.json',
content: JSON.stringify(data)
});
await editTool.invoke({
file_path: 'config.ts',
old_string: 'DEBUG = false',
new_string: 'DEBUG = true'
});
// If this throws, all operations are automatically rolled back
if (!validateData(data)) {
throw new Error('Validation failed');
}
return { filesModified: 2 };
});
// Method 2: Using convenience function
const result2 = await withTransaction(baseOperator, async (transactionOperator) => {
// Same operations as above
return { success: true };
});
// Method 3: Using builder pattern
const executor2 = createTransactionExecutor(baseOperator);
const builderResult = await executor2
.writeFile('config.json', JSON.stringify(config))
.mkdir('logs', { recursive: true })
.custom(async (op) => {
// Custom operation
await op.writeFile('logs/app.log', 'Application started');
})
.execute();
if (builderResult.success) {
console.log('All operations completed successfully');
} else {
console.error('Transaction failed:', builderResult.error);
}
Practical Examples
Safe Configuration Update
Copy
async function updateConfig(newConfig: Config) {
const executor = new TransactionExecutor(transactionOperator);
return await executor.execute(async () => {
// Update main config
await writeTool.invoke({
file_path: 'config.json',
content: JSON.stringify(newConfig, null, 2)
});
// Update package.json version
await editTool.invoke({
file_path: 'package.json',
old_string: `"version": "${oldConfig.version}"`,
new_string: `"version": "${newConfig.version}"`
});
// Validate - rolls back if this fails
if (!isValidConfig(newConfig)) {
throw new Error('Invalid configuration');
}
return { updated: true };
});
}
Batch File Processing
Copy
async function processFiles(files: string[]) {
const executor = new TransactionExecutor(transactionOperator);
return await executor.execute(async () => {
for (const file of files) {
const content = await readTool.invoke({ file_path: file });
const processed = processContent(content);
await writeTool.invoke({
file_path: file,
content: processed
});
}
return { processed: files.length };
});
}
Individual Tools Usage
ReadTool
Copy
import { createReadTool } from '@ag-kit/tools/fs';
const readTool = createReadTool(context);
// Read entire file
const result = await readTool.invoke({
file_path: 'src/config.json'
});
// Read with line range
const partialResult = await readTool.invoke({
file_path: 'large-file.txt',
start_line: 100,
end_line: 200
});
WriteTool
Copy
import { createWriteTool } from '@ag-kit/tools/fs';
const writeTool = createWriteTool(context);
const result = await writeTool.invoke({
file_path: 'output/data.json',
content: JSON.stringify({ message: 'Hello World' }, null, 2),
create_directories: true
});
EditTool
Copy
import { createEditTool } from '@ag-kit/tools/fs';
const editTool = createEditTool(context);
const result = await editTool.invoke({
file_path: 'src/config.ts',
old_string: 'const API_URL = "http://localhost"',
new_string: 'const API_URL = "https://api.production.com"',
expected_replacements: 1 // Optional: validate exact number of replacements
});
GlobTool
Copy
import { createGlobTool } from '@ag-kit/tools/fs';
const globTool = createGlobTool(context);
const result = await globTool.invoke({
pattern: '**/*.ts',
exclude_patterns: ['node_modules/**', 'dist/**']
});
GrepTool
Copy
import { createGrepTool } from '@ag-kit/tools/fs';
const grepTool = createGrepTool(context);
const result = await grepTool.invoke({
pattern: 'TODO|FIXME',
file_pattern: '**/*.{ts,js}',
case_sensitive: false
});
LsTool
Copy
import { createLsTool } from '@ag-kit/tools/fs';
const lsTool = createLsTool(context);
const result = await lsTool.invoke({
directory_path: 'src',
recursive: true,
show_hidden: false
});
StrReplaceEditor
Advanced file editing tool designed for AI coding workflows:Copy
import { createStrReplaceEditor } from '@ag-kit/tools/fs';
const editor = createStrReplaceEditor(context);
// Replace text
await editor.invoke({
command: 'str_replace',
path: 'src/app.ts',
old_str: 'old implementation',
new_str: 'new implementation'
});
// View file contents
await editor.invoke({
command: 'view',
path: 'file.ts',
view_range: [1, 50] // Optional line range
});
// Create new file
await editor.invoke({
command: 'create',
path: 'new-file.ts',
file_text: 'export const config = {};'
});
API Reference
Common Interfaces
Copy
interface ExecutionContext {
workingDirectory: string;
fsOperator: BaseFileOperator;
messageHandler?: any;
}
interface ToolResponse {
success: boolean;
error?: string;
error_type?: 'validation' | 'security' | 'file_not_found' | 'permission' | 'execution';
[key: string]: any;
}
FilesystemToolkit Configuration
Copy
/**
* Configuration options for FilesystemToolkit
*/
interface FilesystemToolkitConfig {
/**
* Mode for file editing operations
* - 'integrated': Use str-replace-editor tool (single tool for read/write/edit operations)
* - 'atomic': Use separate read, write, and edit tools
* - 'enhanced': Use atomic tools plus multi-edit tool for batch operations
*/
mode: "integrated" | "atomic" | "enhanced";
}
interface FilesystemToolkitOptions extends IToolkitOptions {
context: ExecutionContext;
config?: FilesystemToolkitConfig;
}
class FilesystemToolkit extends BaseToolkit {
constructor(options: FilesystemToolkitOptions);
// Get tools by category
getFileOperationTools(): BaseTool[];
getUtilityTools(): BaseTool[];
// Configuration management
getConfig(): FilesystemToolkitConfig;
switchMode(mode: "integrated" | "atomic"): void;
// Statistics
getStats(): { mode: string };
}
// Usage examples
const toolkit = new FilesystemToolkit({
context: {
workingDirectory: process.cwd(),
fsOperator: new LocalFileOperator()
},
config: {
mode: "enhanced" // Use atomic tools + multi-edit
}
});
// Switch modes dynamically
toolkit.switchMode("integrated"); // Switch to str-replace-editor
toolkit.switchMode("enhanced"); // Switch back to enhanced mode
Tool Parameters
Copy
// ReadTool
interface ReadToolParams {
file_path: string;
start_line?: number;
end_line?: number;
encoding?: BufferEncoding;
}
// WriteTool
interface WriteToolParams {
file_path: string;
content: string;
create_directories?: boolean;
encoding?: BufferEncoding;
}
// EditTool
interface EditToolParams {
file_path: string;
old_string: string;
new_string: string;
expected_replacements?: number;
}
// GlobTool
interface GlobToolParams {
pattern: string;
exclude_patterns?: string[];
include_directories?: boolean;
max_results?: number;
}
// GrepTool
interface GrepToolParams {
pattern: string;
file_pattern?: string;
case_sensitive?: boolean;
max_results?: number;
context_lines?: number;
}
// LsTool
interface LsToolParams {
directory_path: string;
recursive?: boolean;
show_hidden?: boolean;
include_stats?: boolean;
}
Transaction Interfaces
Copy
// Transaction wrapper for any base operator
class TransactionFileOperator extends BaseFileOperator {
constructor(baseOperator: BaseFileOperator, operatorType?: EOperatorType);
// Transaction management
beginTransaction(): Promise<void>;
commitTransaction(): Promise<void>;
rollbackTransaction(): Promise<void>;
resetTransactionState(): void;
// Status and configuration
isTransactionActive(): boolean;
getTransactionOperations(): readonly TransactionOperation[];
setConfig(config: Partial<ITransactionFileOperatorConfig>): void;
getConfig(): ITransactionFileOperatorConfig;
// All BaseFileOperator methods are available
// (readFile, writeFile, mkdir, unlink, etc.)
}
// Transaction executor for convenient operation management
class TransactionExecutor {
constructor(baseOperator: BaseFileOperator);
// Get the underlying transaction operator
getOperator(): TransactionFileOperator;
// Builder pattern methods
writeFile(path: string, data: string | Buffer, options?: any): TransactionExecutor;
mkdir(path: string, options?: any): TransactionExecutor;
custom(operation: (op: TransactionFileOperator) => Promise<void>): TransactionExecutor;
// Execution methods
execute(): Promise<{ success: boolean; error?: Error }>;
executeInTransaction<T>(operation: (operator: TransactionFileOperator) => Promise<T>): Promise<T>;
createTransaction(): Promise<TransactionController>;
}
// Manual transaction control
class TransactionController {
constructor(transactionOperator: TransactionFileOperator);
getOperator(): TransactionFileOperator;
commit(): Promise<void>;
rollback(): Promise<void>;
isTransactionCompleted(): boolean;
getOperationHistory(): readonly TransactionOperation[];
}
// Configuration interfaces
interface ITransactionFileOperatorConfig {
batchSize: number;
maxConcurrency: number;
enableLazyLoading: boolean;
}
enum EOperatorType {
LOCAL = "local",
MEMORY = "memory",
SANDBOX = "sandbox"
}
interface TransactionOperation {
type: "write" | "mkdir" | "unlink" | "rmdir" | "rename";
path: string;
oldPath?: string;
timestamp: number;
}
interface FileState {
exists: boolean;
isDirectory: boolean;
contentLoader?: () => Promise<Buffer>;
}
// Utility functions
function createTransactionExecutor(baseOperator: BaseFileOperator): TransactionExecutor;
function withTransaction<T>(
baseOperator: BaseFileOperator,
operation: (operator: TransactionFileOperator) => Promise<T>
): Promise<T>;
Advanced Usage
Multi-File Refactoring with MultiEditTool
Copy
import { createMultieditTool, createGrepTool } from '@ag-kit/tools/fs';
const multieditTool = createMultieditTool(context);
const grepTool = createGrepTool(context);
// Find all files that need refactoring
const searchResult = await grepTool.invoke({
pattern: 'oldApiFunction|OLD_CONSTANT',
file_pattern: '**/*.{ts,js}',
case_sensitive: false
});
// Apply consistent refactoring to each file
for (const match of searchResult.data.matches) {
const refactorResult = await multieditTool.invoke({
file_path: match.file,
edits: [
{
old_string: 'oldApiFunction',
new_string: 'newApiFunction',
expected_replacements: 1
},
{
old_string: 'OLD_CONSTANT',
new_string: 'NEW_CONSTANT',
expected_replacements: 1
},
{
old_string: '// TODO: Update this',
new_string: '// DONE: Updated to new API',
expected_replacements: 1
}
]
});
if (refactorResult.success) {
console.log(`✓ Refactored ${match.file}: ${refactorResult.data.total_replacements} changes`);
} else {
console.log(`✗ Failed to refactor ${match.file}`);
}
}
Transactional File Operations
Copy
import { withTransaction, TransactionExecutor } from '@ag-kit/tools/fs/transaction';
import { LocalFileOperator } from '@ag-kit/tools/fs';
const baseOperator = new LocalFileOperator();
// Method 1: Simple transaction wrapper
const result = await withTransaction(baseOperator, async (transactionOp) => {
// Create multiple related files atomically
await transactionOp.mkdir('project/src', { recursive: true });
await transactionOp.mkdir('project/tests', { recursive: true });
await transactionOp.writeFile('project/package.json', JSON.stringify({
name: 'my-project',
version: '1.0.0'
}, null, 2));
await transactionOp.writeFile('project/src/index.ts', 'export const main = () => console.log("Hello");');
await transactionOp.writeFile('project/tests/index.test.ts', 'import { main } from "../src/index";');
// If any operation fails, all changes are rolled back
return { projectCreated: true };
});
// Method 2: Manual transaction control
const executor = new TransactionExecutor(baseOperator);
const transaction = await executor.createTransaction();
try {
const operator = transaction.getOperator();
// Perform operations
await operator.writeFile('config.json', JSON.stringify(config));
await operator.writeFile('backup.json', JSON.stringify(backup));
// Validate before committing
if (await validateConfiguration(config)) {
await transaction.commit();
console.log('Configuration updated successfully');
} else {
await transaction.rollback();
console.log('Configuration validation failed, changes rolled back');
}
} catch (error) {
if (!transaction.isTransactionCompleted()) {
await transaction.rollback();
}
throw error;
}
Multi-Backend Workflow
Copy
function createFileOperator() {
const env = process.env.NODE_ENV;
switch (env) {
case 'test':
return new InMemoryFileOperator(fs);
case 'production':
return new SandboxFileOperator({ sandbox });
default:
return new LocalFileOperator();
}
}
const context = {
workingDirectory: process.cwd(),
fsOperator: createFileOperator()
};
Batch Operations
Copy
const files = ['config.json', 'package.json', 'tsconfig.json'];
const results = await Promise.all(
files.map(file => readTool.invoke({ file_path: file }))
);
Error Handling
Copy
try {
const result = await readTool.invoke({ file_path: 'nonexistent.txt' });
if (!result.success) {
switch (result.error_type) {
case 'file_not_found':
console.log('File does not exist');
break;
case 'permission':
console.log('Permission denied');
break;
case 'security':
console.log('Security violation');
break;
default:
console.log('Unknown error:', result.error);
}
}
} catch (error) {
console.error('Tool execution failed:', error);
}
Security Features
Path Validation
All tools automatically validate paths to prevent directory traversal attacks:Copy
// ✅ Safe - relative paths within workspace
{ file_path: 'src/config.ts' }
// ❌ Blocked - directory traversal
{ file_path: '../../../etc/passwd' }
Production Recommendations
- Use Sandbox File Operator for untrusted code
- Use In-Memory File Operator for testing
- Use Local File Operator only for trusted environments
Examples
Development Workflow
Copy
// Read configuration
const config = await readTool.invoke({ file_path: 'config.json' });
// Update configuration
await editTool.invoke({
file_path: 'config.json',
old_string: '"debug": false',
new_string: '"debug": true'
});
// Find all TypeScript files
const tsFiles = await globTool.invoke({
pattern: '**/*.ts',
exclude_patterns: ['node_modules/**']
});
// Search for TODOs
const todos = await grepTool.invoke({
pattern: 'TODO|FIXME',
file_pattern: '**/*.{ts,js}'
});
Safe Configuration Migration
Copy
import { withTransaction } from '@ag-kit/tools/fs/transaction';
import { createMultieditTool, createReadTool, createWriteTool, createGrepTool } from '@ag-kit/tools/fs';
async function migrateConfiguration(oldConfigPath: string, newConfigPath: string) {
const readTool = createReadTool(context);
const writeTool = createWriteTool(context);
const multieditTool = createMultieditTool(context);
const grepTool = createGrepTool(context);
return await withTransaction(context.fsOperator, async (transactionOp) => {
// Read old configuration
const oldConfig = await readTool.invoke({ file_path: oldConfigPath });
const configData = JSON.parse(oldConfig.data.content);
// Transform configuration structure
const newConfigData = {
version: '2.0',
settings: {
api: {
baseUrl: configData.apiUrl,
timeout: configData.timeout || 5000
},
features: {
debug: configData.debug || false,
logging: configData.enableLogging || true
}
}
};
// Write new configuration
await writeTool.invoke({
file_path: newConfigPath,
content: JSON.stringify(newConfigData, null, 2),
create_directories: true
});
// Update all files that reference the old config
const configReferences = await grepTool.invoke({
pattern: oldConfigPath.replace(/\./g, '\\.'),
file_pattern: '**/*.{ts,js,json}'
});
for (const ref of configReferences.data.matches) {
await multieditTool.invoke({
file_path: ref.file,
edits: [
{
old_string: oldConfigPath,
new_string: newConfigPath,
expected_replacements: 1
}
]
});
}
// Archive old configuration
await transactionOp.rename(oldConfigPath, `${oldConfigPath}.backup`);
return {
migrated: true,
newConfigPath,
referencesUpdated: configReferences.data.matches.length
};
});
}
// Usage
const migrationResult = await migrateConfiguration('old-config.json', 'config/app.json');
if (migrationResult.migrated) {
console.log(`Configuration migrated successfully to ${migrationResult.newConfigPath}`);
console.log(`Updated ${migrationResult.referencesUpdated} file references`);
}
Batch File Processing with Error Recovery
Copy
import { TransactionExecutor } from '@ag-kit/tools/fs/transaction';
async function processFilesWithRecovery(filePatterns: string[]) {
const executor = new TransactionExecutor(context.fsOperator);
const results = [];
for (const pattern of filePatterns) {
const transaction = await executor.createTransaction();
try {
const operator = transaction.getOperator();
// Find files matching pattern
const files = await globTool.invoke({ pattern });
// Process each file
for (const file of files.data.matches) {
const content = await readTool.invoke({ file_path: file.path });
// Apply transformations
const processedContent = await processFileContent(content.data.content);
// Write back processed content
await operator.writeFile(file.path, processedContent);
}
// Commit if all files processed successfully
await transaction.commit();
results.push({ pattern, success: true, filesProcessed: files.data.matches.length });
} catch (error) {
// Rollback on any error
await transaction.rollback();
results.push({ pattern, success: false, error: error.message });
}
}
return results;
}
async function processFileContent(content: string): Promise<string> {
// Example: Remove console.log statements and add proper logging
return content
.replace(/console\.log\([^)]+\);?\n?/g, '')
.replace(/\/\/ TODO:/g, '// DONE:')
.replace(/var /g, 'const ');
}
Key Features Summary
New in This Version
MultiEditTool
- Purpose: Perform multiple sequential edits on a single file
- Benefits: Atomic batch operations, consistent error handling, detailed results
- Use Cases: Configuration updates, code refactoring, batch replacements
Transaction Support
- Purpose: Group multiple file operations with rollback capability
- Benefits: Data consistency, error recovery, atomic operations
- Strategies: Local (file backup), Memory (snapshot), Sandbox (content tracking)
Enhanced Toolkit Mode
- Purpose: Combine atomic tools with multi-edit capabilities
- Benefits: Flexibility for different use cases, optimal tool selection
- Configuration:
mode: "enhanced"in FilesystemToolkit
Best Practices
- Use MultiEditTool for multiple changes to the same file
- Use Transactions for operations that must succeed or fail together
- Use Enhanced Mode when you need both atomic and batch operations
- Validate expected_replacements to catch unexpected changes
- Handle errors gracefully with proper rollback mechanisms
Migration Guide
From EditTool to MultiEditTool
Copy
// Before: Multiple EditTool calls
await editTool.invoke({ file_path: 'config.ts', old_string: 'A', new_string: 'B' });
await editTool.invoke({ file_path: 'config.ts', old_string: 'C', new_string: 'D' });
// After: Single MultiEditTool call
await multieditTool.invoke({
file_path: 'config.ts',
edits: [
{ old_string: 'A', new_string: 'B' },
{ old_string: 'C', new_string: 'D' }
]
});
Adding Transaction Support
Copy
// Before: Direct operations
await writeTool.invoke({ file_path: 'file1.txt', content: 'data1' });
await writeTool.invoke({ file_path: 'file2.txt', content: 'data2' });
// After: Transactional operations
await withTransaction(baseOperator, async (transactionOp) => {
await transactionOp.writeFile('file1.txt', 'data1');
await transactionOp.writeFile('file2.txt', 'data2');
// Both succeed or both are rolled back
});