FileSystem Backend
π‘Package: github.com/cloudwego/eino/adk/filesystem
Background and Goals
AI Agents need to interact with file systems (read, search, edit, execute commands), but different runtime environments have very different access methods: local disk, remote sandbox, in-memory simulation, object storage, etc. If each environment independently implements file operation logic, it leads to coupling between Middleware/Agent code and the underlying storage.
The filesystem.Backend interface solves this problem β as a unified file system operation protocol:
- Decouple storage from business logic β Middleware depends only on the interface, not the underlying implementation
- Pluggable replacement β Switching Backends enables running in different environments without modifying business code
- Testability β Built-in
InMemoryBackendrequires no real disk I/O - Forward compatibility β All methods use struct parameters; adding new fields does not 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 | Return |
LsInfo | List files and directory info under 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 by glob pattern | []FileInfo |
Write | Write 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 implements Shell or StreamingShell, the Filesystem Middleware additionally registers the execute tool. The 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 supporting multi-modal file reading (images, PDFs, etc.), returning structured MultiFileContent.
type MultiModalReader interface {
MultiModalRead(ctx context.Context, req *MultiModalReadRequest) (*MultiFileContent, error)
}
When a Backend implements this interface and the Middleware is configured with UseMultiModalRead = true, 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]); starting search 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, OldString must appear exactly 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 modified 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: FileContent is ignored when Parts is non-empty |
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 content; 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, 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 Features
- 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), multiline mode - Context lines β GrepRaw supports BeforeLines/AfterLines to show context around matches
- Glob matching β Uses the
doublestarlibrary to support**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 interfaces
External Implementations
The following Backend implementations reside in the eino-ext repository:
- Local Backend (
github.com/cloudwego/eino-ext/adk/backend/local) β Local file system implementation, directly operates on the host 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 | Credentials required |
| Persistence | No | Yes | Yes |
| Shell support | No | Shell + StreamingShell | Shell |
| MultiModalReader | No | Implementation-dependent | Implementation-dependent |
| Use cases | Tests / temporary storage | Development / local environment | Multi-tenant / production |
Custom Implementation
Implement the Backend interface to integrate 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
}