FileSystem Backend
π‘Package: github.com/cloudwego/eino/adk/filesystem
Background and Purpose
AI Agents need to interact with file systems (read, search, edit, execute commands), but access methods vary significantly across different runtime environments: local disk, remote sandboxes, in-memory simulation, object storage, etc. If file operation logic is implemented separately for each environment, it couples Middleware/Agent code to the underlying storage.
The filesystem.Backend interface solves this problem β serving as a unified file system operation protocol:
- Decouples storage from business logic β Middleware depends only on the interface, not the underlying implementation
- Pluggable replacement β Switch Backend to run in different environments without modifying business code
- Easy to test β Built-in
InMemoryBackendrequires no real disk I/O - Forward compatible β All methods use struct parameters; new fields don’t break existing implementations
Backend Interface
type Backend interface {
LsInfo(ctx context.Context, req *LsInfoRequest) ([]FileInfo, error)
Read(ctx context.Context, req *ReadRequest) (*FileContent, error)
GrepRaw(ctx context.Context, req *GrepRequest) ([]GrepMatch, error)
GlobInfo(ctx context.Context, req *GlobInfoRequest) ([]FileInfo, error)
Write(ctx context.Context, req *WriteRequest) error
Edit(ctx context.Context, req *EditRequest) error
}
| Method | Function | Returns |
LsInfo | List files and directories at the specified path | []FileInfo |
Read | Read file content, supports line-based pagination (offset + limit) | *FileContent |
GrepRaw | Search for content matching a pattern in files | []GrepMatch |
GlobInfo | Find matching files based on a glob pattern | []FileInfo |
Write | Write to or create a file | error |
Edit | Replace string content in a file | error |
Extension Interfaces
Shell / StreamingShell
Backends can optionally implement command execution capabilities. When a Backend also implements Shell or StreamingShell, the Filesystem Middleware will additionally register an execute tool. These two are mutually exclusive and cannot be configured simultaneously.
type Shell interface {
Execute(ctx context.Context, input *ExecuteRequest) (result *ExecuteResponse, err error)
}
type StreamingShell interface {
ExecuteStreaming(ctx context.Context, input *ExecuteRequest) (result *schema.StreamReader[*ExecuteResponse], err error)
}
MultiModalReader
An optional extension interface that supports multi-modal file reading (images, PDFs, etc.), returning structured MultiFileContent.
type MultiModalReader interface {
MultiModalRead(ctx context.Context, req *MultiModalReadRequest) (*MultiFileContent, error)
}
When the Backend implements this interface and the Middleware has UseMultiModalRead = true configured, the read_file tool will use multi-modal reading.
Core Data Types
Request Types
| Type | Fields | Description |
LsInfoRequest | Path string | Directory path to list |
ReadRequest | FilePath string Offset int Limit int | File path; starting line number (1-based, <1 treated as 1); maximum lines to read (0=all) |
MultiModalReadRequest | Embeds ReadRequest Pages string | Inherits all ReadRequest fields; Pages specifies PDF page range (e.g., "1-5", "3") |
GrepRequest | Pattern string Path string Glob string FileType string CaseInsensitive bool EnableMultiline bool AfterLines int BeforeLines int | Regex search pattern (ripgrep syntax); search directory; glob file filter; file type filter (e.g., "go", "py"); case insensitive; enable multiline matching; show N lines after match; show N lines before match |
GlobInfoRequest | Pattern string Path string | Glob expression (supports *, **, ?, [abc]); search starting directory |
WriteRequest | FilePath string Content string | Target file path; content to write |
EditRequest | FilePath string OldString string NewString string ReplaceAll bool | File path; exact string to replace (non-empty); replacement string; when false, requires OldString to appear only once in the file |
ExecuteRequest | Command string RunInBackendGround bool | Command string to execute; whether to run in background |
Response Types
| Type | Fields | Description |
FileInfo | Path string IsDir bool Size int64 ModifiedAt string | File/directory path; whether it is a directory; file size (bytes); last modification time (ISO 8601 format) |
FileContent | Content string | Plain text content of the file |
MultiFileContent | *FileContent Parts []FileContentPart | Embeds FileContent; multi-modal output parts. Parts and FileContent are mutually exclusive: when Parts is non-empty, FileContent is ignored |
FileContentPart | Type FileContentPartType MIMEType string Data []byte | Content type ("image"or "pdf"); MIME type (e.g., "image/png"); raw binary data |
GrepMatch | Content string Path string Line int | Matched line content; file path; 1-based line number |
ExecuteResponse | Output string ExitCode *int Truncated bool | Command output; exit code (pointer, may be nil); whether output was truncated |
Constants
type FileContentPartType string
const (
FileContentPartTypeImage FileContentPartType = "image"
FileContentPartTypePDF FileContentPartType = "pdf"
)
Built-in Implementation: InMemoryBackend
InMemoryBackend stores files in an in-memory map, primarily used for:
- Unit testing β Test Agent/Middleware file operation logic without a real file system
- Lightweight scenarios β Temporary file operations that don’t require persistence
- Tool result offloading β The Filesystem Middleware’s large tool result offloading feature uses InMemoryBackend by default
Constructor
func NewInMemoryBackend() *InMemoryBackend
Zero-parameter constructor that returns an empty in-memory file system.
Usage Example
backend := filesystem.NewInMemoryBackend()
ctx := context.Background()
// Write
_ = backend.Write(ctx, &filesystem.WriteRequest{
FilePath: "/example/test.txt",
Content: "Hello, World!\nLine 2\nLine 3",
})
// Read (paginated)
content, _ := backend.Read(ctx, &filesystem.ReadRequest{
FilePath: "/example/test.txt",
Offset: 1,
Limit: 10,
})
// List directory
files, _ := backend.LsInfo(ctx, &filesystem.LsInfoRequest{Path: "/example"})
// Search (regex)
matches, _ := backend.GrepRaw(ctx, &filesystem.GrepRequest{
Pattern: "Hello",
Path: "/example",
CaseInsensitive: true,
})
// Edit
_ = backend.Edit(ctx, &filesystem.EditRequest{
FilePath: "/example/test.txt",
OldString: "Hello",
NewString: "Hi",
ReplaceAll: false,
})
Implementation Characteristics
- Thread-safe β Based on
sync.RWMutex, read operations use read locks, write operations use write locks - GrepRaw parallel processing β Launches up to 10 workers for parallel matching during multi-file searches
- Regex support β Supports full regex, case-insensitive (
(?i)prefix), and multiline mode - Context lines β GrepRaw supports BeforeLines/AfterLines to show context around matches
- Glob matching β Uses the
doublestarlibrary for**recursive matching - FileType mapping β Built-in mapping table of 70+ file types to extensions (go, py, ts, rust, etc.)
- Does not implement Shell β InMemoryBackend does not implement the Shell/StreamingShell interface
External Implementations
The following Backend implementations are located in the eino-ext repository:
- Local Backend (
github.com/cloudwego/eino-ext/adk/backend/local) β Local file system implementation that directly operates on the local disk - Ark Agentkit Sandbox (
github.com/cloudwego/eino-ext/adk/backend/agentkit) β Volcengine Agentkit remote sandbox implementation
Implementation Comparison
| Feature | InMemory | Local | Agentkit Sandbox |
| Execution model | In-memory | Local direct | Remote sandbox |
| Network dependency | None | None | Required |
| Configuration complexity | Zero config | Zero config | Requires credentials |
| Persistence | No | Yes | Yes |
| Shell support | No | Shell + StreamingShell | Shell |
| MultiModalReader | No | Depends on implementation | Depends on implementation |
| Use case | Testing / temporary storage | Development / local environment | Multi-tenant / production |
Custom Implementation
Implement the Backend interface to integrate with custom storage. For command execution, additionally implement Shell or StreamingShell; for multi-modal reading, implement MultiModalReader.
type MyBackend struct { /* ... */ }
func (b *MyBackend) LsInfo(ctx context.Context, req *filesystem.LsInfoRequest) ([]filesystem.FileInfo, error) {
// Custom implementation
}
func (b *MyBackend) Read(ctx context.Context, req *filesystem.ReadRequest) (*filesystem.FileContent, error) {
// Custom implementation
}
func (b *MyBackend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]filesystem.GrepMatch, error) {
// Custom implementation
}
func (b *MyBackend) GlobInfo(ctx context.Context, req *filesystem.GlobInfoRequest) ([]filesystem.FileInfo, error) {
// Custom implementation
}
func (b *MyBackend) Write(ctx context.Context, req *filesystem.WriteRequest) error {
// Custom implementation
}
func (b *MyBackend) Edit(ctx context.Context, req *filesystem.EditRequest) error {
// Custom implementation
}
// Optional: implement Shell
func (b *MyBackend) Execute(ctx context.Context, input *filesystem.ExecuteRequest) (*filesystem.ExecuteResponse, error) {
// Custom implementation
}
// Optional: implement MultiModalReader
func (b *MyBackend) MultiModalRead(ctx context.Context, req *filesystem.MultiModalReadRequest) (*filesystem.MultiFileContent, error) {
// Custom implementation
}