@aigne/afs
@aigne/afs is the core package of the Agentic File System (AFS), providing a virtual file system abstraction layer that enables AI agents to access various storage backends through a unified, path-based API.
Overview
AFS Core provides the foundational infrastructure for building virtual file systems that can integrate with different storage backends. It includes the base AFS implementation, module mounting system, and event-driven architecture for building modular storage solutions.
Features
- Virtual File System: Hierarchical path-based structure with
/modules root directory
- Module System: Pluggable architecture for custom storage backends
- Unified API: Consistent interface for list, read, write, search, and exec operations
- Event System: Event-driven architecture for module communication
- AI Agent Integration: Seamless integration with AIGNE agents
Installation
npm install @aigne/afs
yarn add @aigne/afs
pnpm add @aigne/afs
Quick Start
import { AFS } from "@aigne/afs";
import { AFSHistory } from "@aigne/afs-history";
const afs = new AFS();
afs.mount(new AFSHistory({
storage: { url: "file:./memory.sqlite3" }
}));
const modules = await afs.listModules();
const { list } = await afs.list('/modules/history');
const { result } = await afs.read('/modules/history/some-id');
await afs.write('/modules/history/notes', {
content: 'My notes',
summary: 'Personal notes'
});
const { list: results } = await afs.search('/modules/history', 'search query');
Core Concepts
AFSEntry
All data in AFS is represented as AFSEntry objects:
interface AFSEntry {
id: string;
path: string;
content?: any;
summary?: string;
metadata?: Record<string, any>;
createdAt?: Date;
updatedAt?: Date;
userId?: string;
sessionId?: string;
linkTo?: string;
}
Modules
Modules are pluggable components that implement storage backends. All modules are automatically mounted under the /modules path prefix:
interface AFSModule {
name: string;
description?: string;
list?(path: string, options?: AFSListOptions): Promise<{ list: AFSEntry[]; message?: string }>;
read?(path: string): Promise<{ result?: AFSEntry; message?: string }>;
write?(path: string, entry: AFSWriteEntryPayload): Promise<{ result: AFSEntry; message?: string }>;
search?(path: string, query: string, options?: AFSSearchOptions): Promise<{ list: AFSEntry[]; message?: string }>;
exec?(path: string, args: Record<string, any>, options: { context: any }): Promise<{ result: Record<string, any> }>;
onMount?(afs: AFSRoot): void;
onUnmount?(): void;
}
Mount Path Convention: When you mount a module with name "my-module", it will be accessible at /modules/my-module.
API Reference
AFS Class
Constructor
new AFS(options?: AFSOptions)
Options:
modules: Optional array of modules to mount on initialization
Methods
mount(module: AFSModule)
mount(path: string, module: AFSModule)
Mount a module. The module will be accessible under /modules/{module.name} or /modules/{path}:
afs.mount(new CustomModule());
afs.mount("/custom-path", new CustomModule());
listModules()
Get all mounted modules:
const modules = await afs.listModules();
list(path: string, options?: AFSListOptions)
List entries in a directory:
const { list, message } = await afs.list('/modules/history', {
maxDepth: 2
});
Options:
maxDepth: Maximum recursion depth (default: 1)
read(path: string)
Read a specific entry:
const { result, message } = await afs.read('/modules/history/uuid-123');
write(path: string, content: AFSWriteEntryPayload)
Write or update an entry:
const { result, message } = await afs.write('/modules/my-module/file.txt', {
content: 'Hello, world!',
summary: 'Greeting file',
metadata: { type: 'greeting' }
});
search(path: string, query: string, options?: AFSSearchOptions)
Search for content:
const { list, message } = await afs.search('/modules/history', 'authentication');
exec(path: string, args: Record<string, any>, options: { context: any })
Execute a module-specific operation:
const { result } = await afs.exec('/modules/my-module/action', { param: 'value' }, { context });
Events
AFS uses an event system for module communication:
afs.on('agentSucceed', ({ input, output }) => {
console.log('Agent succeeded:', input, output);
});
afs.emit('customEvent', { data: 'value' });
Common events from AFSRootEvents:
agentSucceed: Emitted when an agent successfully completes
agentFail: Emitted when an agent fails
Built-in Modules
AFSHistory
The history module tracks conversation history. It is available as a separate package: @aigne/afs-history.
Features:
- Listens to
agentSucceed events and records agent interactions
- Stores input/output pairs with UUID paths
- Supports list and read operations
- Can be extended with search capabilities
- Persistent SQLite storage
Installation:
npm install @aigne/afs-history
Usage:
import { AFS } from "@aigne/afs";
import { AFSHistory } from "@aigne/afs-history";
const afs = new AFS();
afs.mount(new AFSHistory({
storage: { url: "file:./memory.sqlite3" }
}));
const { list } = await afs.list('/modules/history');
Configuration:
storage: Storage configuration (e.g., { url: "file:./memory.sqlite3" }) or a SharedAFSStorage instance
Note: History is NOT automatically mounted. You must explicitly mount it if needed.
Documentation: See @aigne/afs-history for detailed documentation.
Creating Custom Modules
Create a custom module by implementing the AFSModule interface:
import { AFSModule, AFSEntry, AFSListOptions } from "@aigne/afs";
export class CustomModule implements AFSModule {
readonly name = "custom-module";
readonly description = "My custom storage";
async list(path: string, options?: AFSListOptions): Promise<{ list: AFSEntry[]; message?: string }> {
return { list: [] };
}
async read(path: string): Promise<{ result?: AFSEntry; message?: string }> {
return { result: undefined };
}
async write(path: string, content: AFSWriteEntryPayload): Promise<{ result: AFSEntry; message?: string }> {
const entry: AFSEntry = { id: 'id', path, ...content };
return { result: entry };
}
async search(path: string, query: string, options?: AFSSearchOptions): Promise<{ list: AFSEntry[]; message?: string }> {
return { list: [] };
}
onMount(afs: AFSRoot) {
console.log(`${this.name} mounted`);
afs.on('agentSucceed', (data) => {
});
}
}
afs.mount(new CustomModule());
Module Path Resolution
When a module is mounted, AFS handles path resolution automatically:
- Module mounted with name
"my-module" â accessible at /modules/my-module
- When listing
/modules, AFS shows all mounted modules
- When accessing
/modules/my-module/foo, the module receives "/foo" as the path parameter
This allows modules to focus on their internal logic without worrying about mount paths.
Integration with AI Agents
When an agent has AFS configured, these tools are automatically registered:
- afs_list: Browse directory contents
- afs_read: Read file contents
- afs_write: Write/create files
- afs_search: Search for content
- afs_exec: Execute module operations
Example:
import { AIAgent, AIGNE } from "@aigne/core";
import { AFS } from "@aigne/afs";
import { AFSHistory } from "@aigne/afs-history";
const afs = new AFS();
afs.mount(new AFSHistory({
storage: { url: "file:./memory.sqlite3" }
}));
const agent = AIAgent.from({
name: "assistant",
afs: afs
});
const context = aigne.newContext();
const result = await context.invoke(agent, {
message: "What's in my history?"
});
Related Packages
Examples
TypeScript Support
This package includes full TypeScript type definitions.
License
Elastic-2.0