UNPKG

@mastra/core

Version:

Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.

359 lines (219 loc) 10.6 kB
# LocalFilesystem **Added in:** `@mastra/core@1.1.0` Stores files in a directory on the local filesystem. > **Info:** For interface details, see [WorkspaceFilesystem Interface](https://mastra.ai/reference/workspace/filesystem). ## Usage Add a `LocalFilesystem` to a workspace and assign it to an agent. The agent can then read, write, and manage files as part of its tasks: ```typescript import { Agent } from '@mastra/core/agent' import { Workspace, LocalFilesystem } from '@mastra/core/workspace' const workspace = new Workspace({ filesystem: new LocalFilesystem({ basePath: './workspace', }), }) const agent = new Agent({ id: 'file-agent', model: 'openai/gpt-5.4', workspace, }) // The agent now has filesystem tools available const response = await agent.generate('List all files in the workspace') ``` ## Constructor parameters **basePath** (`string`): Base directory path on disk. All file paths are resolved relative to this directory. **id** (`string`): Unique identifier for this filesystem instance (Default: `Auto-generated`) **contained** (`boolean`): When true, all file operations are restricted to stay within basePath. Prevents path traversal attacks and symlink escapes. See \[containment]\(/docs/workspace/filesystem#containment). (Default: `true`) **allowedPaths** (`string[]`): Additional directories the agent can access outside of \`basePath\`. (Default: `[]`) **instructions** (`string | ((opts: { defaultInstructions: string; requestContext?: RequestContext }) => string)`): Custom instructions that override the default instructions returned by getInstructions(). Pass a string to fully replace them, or a function to extend them with access to the current requestContext for per-request customization. **readOnly** (`boolean`): When true, all write operations are blocked. Read operations are still allowed. (Default: `false`) ## Properties **id** (`string`): Filesystem instance identifier **name** (`string`): Provider name ('LocalFilesystem') **provider** (`string`): Provider identifier ('local') **basePath** (`string`): The absolute base path on disk **readOnly** (`boolean | undefined`): Whether the filesystem is in read-only mode **allowedPaths** (`readonly string[]`): Current set of resolved allowed paths. These paths are permitted beyond basePath when containment is enabled. ## Methods ### `init()` Initialize the filesystem. Creates the base directory if it doesn't exist. ```typescript await filesystem.init() ``` Called by `workspace.init()`. ### Lazy initialization LocalFilesystem initializes on first operation if not already initialized, creating the base directory automatically. Calling `init()` explicitly is optional but can be useful to pre-create directories before the first operation. ### `destroy()` Clean up filesystem resources. ```typescript await filesystem.destroy() ``` Called by `workspace.destroy()`. ### `setAllowedPaths(pathsOrUpdater)` Update the allowed paths at runtime. Accepts a new paths array (replaces current) or an updater callback that receives the current paths and returns the new set. ```typescript // Set directly filesystem.setAllowedPaths(['/home/user/.config']) // Update with callback filesystem.setAllowedPaths(prev => [...prev, '/home/user/documents']) // Clear all allowed paths filesystem.setAllowedPaths([]) ``` **Parameters:** **pathsOrUpdater** (`string[] | ((current: readonly string[]) => string[])`): New allowed paths array or updater function receiving current paths ### `readFile(path, options?)` Read file contents. ```typescript const content = await filesystem.readFile('/docs/guide.md') const buffer = await filesystem.readFile('/image.png', { encoding: 'binary' }) ``` **Parameters:** **path** (`string`): File path relative to basePath **options** (`Options`): Configuration options. **options.encoding** (`'utf-8' | 'binary'`): Text or binary encoding ### `writeFile(path, content, options?)` Write content to a file. ```typescript await filesystem.writeFile('/docs/new.md', '# New Document') await filesystem.writeFile('/nested/path/file.md', content, { recursive: true }) ``` **Parameters:** **path** (`string`): File path relative to basePath **content** (`string | Buffer`): File content **options** (`Options`): Configuration options. **options.recursive** (`boolean`): Create parent directories if they don't exist **options.overwrite** (`boolean`): Overwrite existing file **options.expectedMtime** (`Date`): If provided, the write fails with a StaleFileError when the file's current modification time doesn't match. Use this for optimistic concurrency control to detect external modifications between read and write. ### `appendFile(path, content)` Append content to an existing file. ```typescript await filesystem.appendFile('/logs/app.log', 'New log entry\n') ``` **Parameters:** **path** (`string`): File path relative to basePath **content** (`string | Buffer`): Content to append ### `deleteFile(path, options?)` Delete a file. ```typescript await filesystem.deleteFile('/docs/old.md') await filesystem.deleteFile('/docs/maybe.md', { force: true }) // Don't throw if missing ``` **Parameters:** **path** (`string`): File path **options** (`Options`): Configuration options. **options.force** (`boolean`): Don't throw error if file doesn't exist ### `copyFile(src, dest, options?)` Copy a file to a new location. ```typescript await filesystem.copyFile('/docs/template.md', '/docs/new-doc.md') await filesystem.copyFile('/src/config.json', '/backup/config.json', { overwrite: false }) ``` **Parameters:** **src** (`string`): Source file path **dest** (`string`): Destination file path **options** (`Options`): Configuration options. **options.overwrite** (`boolean`): Overwrite destination if it exists ### `moveFile(src, dest, options?)` Move or rename a file. ```typescript await filesystem.moveFile('/docs/draft.md', '/docs/final.md') await filesystem.moveFile('/temp/upload.txt', '/files/document.txt') ``` **Parameters:** **src** (`string`): Source file path **dest** (`string`): Destination file path **options** (`Options`): Configuration options. **options.overwrite** (`boolean`): Overwrite destination if it exists ### `mkdir(path, options?)` Create a directory. ```typescript await filesystem.mkdir('/docs/api') await filesystem.mkdir('/deeply/nested/path', { recursive: true }) ``` **Parameters:** **path** (`string`): Directory path **options** (`Options`): Configuration options. **options.recursive** (`boolean`): Create parent directories ### `rmdir(path, options?)` Remove a directory. ```typescript await filesystem.rmdir('/docs/old') await filesystem.rmdir('/docs/nested', { recursive: true }) ``` **Parameters:** **path** (`string`): Directory path **options** (`Options`): Configuration options. **options.recursive** (`boolean`): Remove contents recursively **options.force** (`boolean`): Don't throw if directory doesn't exist ### `readdir(path, options?)` List directory contents. ```typescript const entries = await filesystem.readdir('/docs') // [{ name: 'guide.md', type: 'file' }, { name: 'api', type: 'directory' }] ``` ### `exists(path)` Check if a path exists. ```typescript const exists = await filesystem.exists('/docs/guide.md') ``` ### `stat(path)` Get file or directory metadata. ```typescript const stat = await filesystem.stat('/docs/guide.md') // { type: 'file', size: 1234, modifiedAt: Date, createdAt: Date, path: '/docs/guide.md' } ``` ### `getInfo()` Returns metadata about this filesystem instance. ```typescript const info = filesystem.getInfo() // { id: '...', name: 'LocalFilesystem', provider: 'local', basePath: '/workspace', readOnly: false } ``` ### `getInstructions(opts?)` Returns a description of how paths work in this filesystem. When assigned to an agent, this is injected into the agent's system message. ```typescript const instructions = filesystem.getInstructions() // 'Local filesystem at "/workspace". Files at workspace path "/foo" are stored at "/workspace/foo" on disk.' ``` Pass `requestContext` to enable per-request customization when the `instructions` constructor option is a function: ```typescript const instructions = filesystem.getInstructions({ requestContext }) ``` **Parameters:** **opts.requestContext** (`RequestContext`): Forwarded to the \`instructions\` function if one was provided in the constructor. **Returns:** `string` To override the default output, pass an `instructions` option to the constructor. See [constructor parameters](#constructor-parameters). ## Path resolution ### How `basePath` works The `basePath` option sets the root directory for all file operations. File paths passed to methods like `readFile()` are resolved relative to this base: - Leading slashes are stripped: `/docs/guide.md``docs/guide.md` - The path is normalized and joined with basePath - Result: `./workspace` + `docs/guide.md``./workspace/docs/guide.md` ```typescript const filesystem = new LocalFilesystem({ basePath: './workspace', }) // These all resolve to ./workspace/docs/guide.md await filesystem.readFile('/docs/guide.md') await filesystem.readFile('docs/guide.md') ``` ### Relative paths and execution context When you use a relative path for `basePath`, it resolves from `process.cwd()`. In Mastra projects, cwd varies depending on how you run your code: | Context | Working directory | `./workspace` resolves to | | -------------- | ------------------------- | ------------------------------- | | `mastra dev` | `./src/mastra/public/` | `./src/mastra/public/workspace` | | `mastra start` | `./.mastra/output/` | `./.mastra/output/workspace` | | Direct script | Where you ran the command | Relative to that location | This can cause confusion when the same relative path resolves to different locations. ### Recommended: Use absolute paths For consistent paths across all execution contexts, use an environment variable with an absolute path: ```typescript import { LocalFilesystem } from '@mastra/core/workspace' const filesystem = new LocalFilesystem({ basePath: process.env.WORKSPACE_PATH!, }) ``` Set `WORKSPACE_PATH` in your environment to an absolute path like `/home/user/my-project/workspace`. This ensures the workspace path is consistent regardless of how you run your code. ## Related - [WorkspaceFilesystem interface](https://mastra.ai/reference/workspace/filesystem) - [Workspace class](https://mastra.ai/reference/workspace/workspace-class) - [Workspace overview](https://mastra.ai/docs/workspace/overview)