@aigne/afs 1.1.2-beta → 1.2.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +359 -0
- package/lib/cjs/afs.d.ts +9 -9
- package/lib/cjs/afs.js +31 -27
- package/lib/cjs/index.d.ts +0 -2
- package/lib/cjs/index.js +0 -2
- package/lib/cjs/type.d.ts +16 -5
- package/lib/dts/afs.d.ts +9 -9
- package/lib/dts/index.d.ts +0 -2
- package/lib/dts/type.d.ts +16 -5
- package/lib/esm/afs.d.ts +9 -9
- package/lib/esm/afs.js +31 -27
- package/lib/esm/index.d.ts +0 -2
- package/lib/esm/index.js +0 -2
- package/lib/esm/type.d.ts +16 -5
- package/package.json +3 -5
- package/lib/cjs/history/index.d.ts +0 -20
- package/lib/cjs/history/index.js +0 -47
- package/lib/cjs/storage/index.d.ts +0 -24
- package/lib/cjs/storage/index.js +0 -72
- package/lib/cjs/storage/migrate.d.ts +0 -3
- package/lib/cjs/storage/migrate.js +0 -31
- package/lib/cjs/storage/migrations/001-init.d.ts +0 -2
- package/lib/cjs/storage/migrations/001-init.js +0 -25
- package/lib/cjs/storage/models/entries.d.ts +0 -199
- package/lib/cjs/storage/models/entries.js +0 -28
- package/lib/cjs/storage/type.d.ts +0 -23
- package/lib/cjs/storage/type.js +0 -2
- package/lib/dts/history/index.d.ts +0 -20
- package/lib/dts/storage/index.d.ts +0 -24
- package/lib/dts/storage/migrate.d.ts +0 -3
- package/lib/dts/storage/migrations/001-init.d.ts +0 -2
- package/lib/dts/storage/models/entries.d.ts +0 -199
- package/lib/dts/storage/type.d.ts +0 -23
- package/lib/esm/history/index.d.ts +0 -20
- package/lib/esm/history/index.js +0 -43
- package/lib/esm/storage/index.d.ts +0 -24
- package/lib/esm/storage/index.js +0 -67
- package/lib/esm/storage/migrate.d.ts +0 -3
- package/lib/esm/storage/migrate.js +0 -28
- package/lib/esm/storage/migrations/001-init.d.ts +0 -2
- package/lib/esm/storage/migrations/001-init.js +0 -22
- package/lib/esm/storage/models/entries.d.ts +0 -199
- package/lib/esm/storage/models/entries.js +0 -23
- package/lib/esm/storage/type.d.ts +0 -23
- package/lib/esm/storage/type.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.2.0-beta](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.1.2...afs-v1.2.0-beta) (2025-11-14)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* support mount mcp agent into AFS ([#740](https://github.com/AIGNE-io/aigne-framework/issues/740)) ([6d474fc](https://github.com/AIGNE-io/aigne-framework/commit/6d474fc05845a15e2c3e8fa97727b409bdd70945))
|
|
9
|
+
|
|
10
|
+
## [1.1.2](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.1.2-beta...afs-v1.1.2) (2025-11-12)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Dependencies
|
|
14
|
+
|
|
15
|
+
* The following workspace dependencies were updated
|
|
16
|
+
* dependencies
|
|
17
|
+
* @aigne/sqlite bumped to 0.4.4
|
|
18
|
+
|
|
3
19
|
## [1.1.2-beta](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.1.1...afs-v1.1.2-beta) (2025-11-12)
|
|
4
20
|
|
|
5
21
|
|
package/README.md
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# @aigne/afs
|
|
2
|
+
|
|
3
|
+
**@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.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Virtual File System**: Hierarchical path-based structure with `/modules` root directory
|
|
12
|
+
- **Module System**: Pluggable architecture for custom storage backends
|
|
13
|
+
- **Unified API**: Consistent interface for list, read, write, search, and exec operations
|
|
14
|
+
- **Event System**: Event-driven architecture for module communication
|
|
15
|
+
- **AI Agent Integration**: Seamless integration with AIGNE agents
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @aigne/afs
|
|
21
|
+
# or
|
|
22
|
+
yarn add @aigne/afs
|
|
23
|
+
# or
|
|
24
|
+
pnpm add @aigne/afs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { AFS } from "@aigne/afs";
|
|
31
|
+
import { AFSHistory } from "@aigne/afs-history";
|
|
32
|
+
|
|
33
|
+
// Create AFS instance
|
|
34
|
+
const afs = new AFS();
|
|
35
|
+
|
|
36
|
+
// Mount history module (optional)
|
|
37
|
+
afs.mount(new AFSHistory({
|
|
38
|
+
storage: { url: "file:./memory.sqlite3" }
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
// All modules are mounted under /modules
|
|
42
|
+
// List modules
|
|
43
|
+
const modules = await afs.listModules();
|
|
44
|
+
|
|
45
|
+
// List entries in a module
|
|
46
|
+
const { list } = await afs.list('/modules/history');
|
|
47
|
+
|
|
48
|
+
// Read an entry
|
|
49
|
+
const { result } = await afs.read('/modules/history/some-id');
|
|
50
|
+
|
|
51
|
+
// Write an entry (if module supports write)
|
|
52
|
+
await afs.write('/modules/history/notes', {
|
|
53
|
+
content: 'My notes',
|
|
54
|
+
summary: 'Personal notes'
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Search for content
|
|
58
|
+
const { list: results } = await afs.search('/modules/history', 'search query');
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Core Concepts
|
|
62
|
+
|
|
63
|
+
### AFSEntry
|
|
64
|
+
|
|
65
|
+
All data in AFS is represented as `AFSEntry` objects:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
interface AFSEntry {
|
|
69
|
+
id: string; // Unique identifier
|
|
70
|
+
path: string; // Full path in AFS
|
|
71
|
+
content?: any; // File/data content
|
|
72
|
+
summary?: string; // Optional summary
|
|
73
|
+
metadata?: Record<string, any>; // Custom metadata
|
|
74
|
+
createdAt?: Date; // Creation timestamp
|
|
75
|
+
updatedAt?: Date; // Last update timestamp
|
|
76
|
+
userId?: string; // Associated user
|
|
77
|
+
sessionId?: string; // Associated session
|
|
78
|
+
linkTo?: string; // Link to another entry
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Modules
|
|
83
|
+
|
|
84
|
+
Modules are pluggable components that implement storage backends. All modules are automatically mounted under the `/modules` path prefix:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface AFSModule {
|
|
88
|
+
name: string; // Module name (used as mount path)
|
|
89
|
+
description?: string; // Description for AI agents
|
|
90
|
+
|
|
91
|
+
// Operations (all optional)
|
|
92
|
+
list?(path: string, options?: AFSListOptions): Promise<{ list: AFSEntry[]; message?: string }>;
|
|
93
|
+
read?(path: string): Promise<{ result?: AFSEntry; message?: string }>;
|
|
94
|
+
write?(path: string, entry: AFSWriteEntryPayload): Promise<{ result: AFSEntry; message?: string }>;
|
|
95
|
+
search?(path: string, query: string, options?: AFSSearchOptions): Promise<{ list: AFSEntry[]; message?: string }>;
|
|
96
|
+
exec?(path: string, args: Record<string, any>, options: { context: any }): Promise<{ result: Record<string, any> }>;
|
|
97
|
+
|
|
98
|
+
// Lifecycle
|
|
99
|
+
onMount?(afs: AFSRoot): void;
|
|
100
|
+
onUnmount?(): void;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Mount Path Convention**: When you mount a module with name `"my-module"`, it will be accessible at `/modules/my-module`.
|
|
105
|
+
|
|
106
|
+
## API Reference
|
|
107
|
+
|
|
108
|
+
### AFS Class
|
|
109
|
+
|
|
110
|
+
#### Constructor
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
new AFS(options?: AFSOptions)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Options:
|
|
117
|
+
- `modules`: Optional array of modules to mount on initialization
|
|
118
|
+
|
|
119
|
+
#### Methods
|
|
120
|
+
|
|
121
|
+
##### mount(module: AFSModule)
|
|
122
|
+
##### mount(path: string, module: AFSModule)
|
|
123
|
+
|
|
124
|
+
Mount a module. The module will be accessible under `/modules/{module.name}` or `/modules/{path}`:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Mount using module's name
|
|
128
|
+
afs.mount(new CustomModule());
|
|
129
|
+
|
|
130
|
+
// Mount with custom path (advanced usage)
|
|
131
|
+
afs.mount("/custom-path", new CustomModule());
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
##### listModules()
|
|
135
|
+
|
|
136
|
+
Get all mounted modules:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const modules = await afs.listModules();
|
|
140
|
+
// Returns: [{ name: string, path: string, description?: string, module: AFSModule }]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
##### list(path: string, options?: AFSListOptions)
|
|
144
|
+
|
|
145
|
+
List entries in a directory:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const { list, message } = await afs.list('/modules/history', {
|
|
149
|
+
maxDepth: 2
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Options:
|
|
154
|
+
- `maxDepth`: Maximum recursion depth (default: 1)
|
|
155
|
+
|
|
156
|
+
##### read(path: string)
|
|
157
|
+
|
|
158
|
+
Read a specific entry:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const { result, message } = await afs.read('/modules/history/uuid-123');
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
##### write(path: string, content: AFSWriteEntryPayload)
|
|
165
|
+
|
|
166
|
+
Write or update an entry:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
const { result, message } = await afs.write('/modules/my-module/file.txt', {
|
|
170
|
+
content: 'Hello, world!',
|
|
171
|
+
summary: 'Greeting file',
|
|
172
|
+
metadata: { type: 'greeting' }
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
##### search(path: string, query: string, options?: AFSSearchOptions)
|
|
177
|
+
|
|
178
|
+
Search for content:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const { list, message } = await afs.search('/modules/history', 'authentication');
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
##### exec(path: string, args: Record<string, any>, options: { context: any })
|
|
185
|
+
|
|
186
|
+
Execute a module-specific operation:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const { result } = await afs.exec('/modules/my-module/action', { param: 'value' }, { context });
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Events
|
|
193
|
+
|
|
194
|
+
AFS uses an event system for module communication:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Modules can listen to events
|
|
198
|
+
afs.on('agentSucceed', ({ input, output }) => {
|
|
199
|
+
console.log('Agent succeeded:', input, output);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Modules can emit custom events
|
|
203
|
+
afs.emit('customEvent', { data: 'value' });
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Common events from `AFSRootEvents`:
|
|
207
|
+
- `agentSucceed`: Emitted when an agent successfully completes
|
|
208
|
+
- `agentFail`: Emitted when an agent fails
|
|
209
|
+
|
|
210
|
+
## Built-in Modules
|
|
211
|
+
|
|
212
|
+
### AFSHistory
|
|
213
|
+
|
|
214
|
+
The history module tracks conversation history. It is available as a separate package: `@aigne/afs-history`.
|
|
215
|
+
|
|
216
|
+
**Features:**
|
|
217
|
+
- Listens to `agentSucceed` events and records agent interactions
|
|
218
|
+
- Stores input/output pairs with UUID paths
|
|
219
|
+
- Supports list and read operations
|
|
220
|
+
- Can be extended with search capabilities
|
|
221
|
+
- Persistent SQLite storage
|
|
222
|
+
|
|
223
|
+
**Installation:**
|
|
224
|
+
```bash
|
|
225
|
+
npm install @aigne/afs-history
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Usage:**
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { AFS } from "@aigne/afs";
|
|
232
|
+
import { AFSHistory } from "@aigne/afs-history";
|
|
233
|
+
|
|
234
|
+
const afs = new AFS();
|
|
235
|
+
afs.mount(new AFSHistory({
|
|
236
|
+
storage: { url: "file:./memory.sqlite3" }
|
|
237
|
+
}));
|
|
238
|
+
|
|
239
|
+
// History entries are accessible at /modules/history
|
|
240
|
+
const { list } = await afs.list('/modules/history');
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Configuration:**
|
|
244
|
+
- `storage`: Storage configuration (e.g., `{ url: "file:./memory.sqlite3" }`) or a SharedAFSStorage instance
|
|
245
|
+
|
|
246
|
+
**Note:** History is NOT automatically mounted. You must explicitly mount it if needed.
|
|
247
|
+
|
|
248
|
+
**Documentation:** See [@aigne/afs-history](../history/README.md) for detailed documentation.
|
|
249
|
+
|
|
250
|
+
## Creating Custom Modules
|
|
251
|
+
|
|
252
|
+
Create a custom module by implementing the `AFSModule` interface:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { AFSModule, AFSEntry, AFSListOptions } from "@aigne/afs";
|
|
256
|
+
|
|
257
|
+
export class CustomModule implements AFSModule {
|
|
258
|
+
readonly name = "custom-module";
|
|
259
|
+
readonly description = "My custom storage";
|
|
260
|
+
|
|
261
|
+
async list(path: string, options?: AFSListOptions): Promise<{ list: AFSEntry[]; message?: string }> {
|
|
262
|
+
// path is the subpath within your module
|
|
263
|
+
// Implement your list logic
|
|
264
|
+
return { list: [] };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async read(path: string): Promise<{ result?: AFSEntry; message?: string }> {
|
|
268
|
+
// Implement your read logic
|
|
269
|
+
return { result: undefined };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async write(path: string, content: AFSWriteEntryPayload): Promise<{ result: AFSEntry; message?: string }> {
|
|
273
|
+
// Implement your write logic
|
|
274
|
+
const entry: AFSEntry = { id: 'id', path, ...content };
|
|
275
|
+
return { result: entry };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async search(path: string, query: string, options?: AFSSearchOptions): Promise<{ list: AFSEntry[]; message?: string }> {
|
|
279
|
+
// Implement your search logic
|
|
280
|
+
return { list: [] };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
onMount(afs: AFSRoot) {
|
|
284
|
+
console.log(`${this.name} mounted`);
|
|
285
|
+
|
|
286
|
+
// Listen to events
|
|
287
|
+
afs.on('agentSucceed', (data) => {
|
|
288
|
+
// Handle event
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Mount the module
|
|
294
|
+
afs.mount(new CustomModule());
|
|
295
|
+
// Now accessible at /modules/custom-module
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Module Path Resolution
|
|
299
|
+
|
|
300
|
+
When a module is mounted, AFS handles path resolution automatically:
|
|
301
|
+
|
|
302
|
+
1. Module mounted with name `"my-module"` → accessible at `/modules/my-module`
|
|
303
|
+
2. When listing `/modules`, AFS shows all mounted modules
|
|
304
|
+
3. When accessing `/modules/my-module/foo`, the module receives `"/foo"` as the path parameter
|
|
305
|
+
|
|
306
|
+
This allows modules to focus on their internal logic without worrying about mount paths.
|
|
307
|
+
|
|
308
|
+
## Integration with AI Agents
|
|
309
|
+
|
|
310
|
+
When an agent has AFS configured, these tools are automatically registered:
|
|
311
|
+
|
|
312
|
+
- **afs_list**: Browse directory contents
|
|
313
|
+
- **afs_read**: Read file contents
|
|
314
|
+
- **afs_write**: Write/create files
|
|
315
|
+
- **afs_search**: Search for content
|
|
316
|
+
- **afs_exec**: Execute module operations
|
|
317
|
+
|
|
318
|
+
Example:
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { AIAgent, AIGNE } from "@aigne/core";
|
|
322
|
+
import { AFS } from "@aigne/afs";
|
|
323
|
+
import { AFSHistory } from "@aigne/afs-history";
|
|
324
|
+
|
|
325
|
+
const afs = new AFS();
|
|
326
|
+
afs.mount(new AFSHistory({
|
|
327
|
+
storage: { url: "file:./memory.sqlite3" }
|
|
328
|
+
}));
|
|
329
|
+
|
|
330
|
+
const agent = AIAgent.from({
|
|
331
|
+
name: "assistant",
|
|
332
|
+
afs: afs
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
const context = aigne.newContext();
|
|
336
|
+
const result = await context.invoke(agent, {
|
|
337
|
+
message: "What's in my history?"
|
|
338
|
+
});
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Related Packages
|
|
342
|
+
|
|
343
|
+
- [@aigne/afs-history](../history/README.md) - History tracking module
|
|
344
|
+
- [@aigne/afs-local-fs](../local-fs/README.md) - Local file system module
|
|
345
|
+
- [@aigne/afs-user-profile-memory](../user-profile-memory/README.md) - User profile memory module
|
|
346
|
+
|
|
347
|
+
## Examples
|
|
348
|
+
|
|
349
|
+
- [AFS Memory Example](../../examples/afs-memory/README.md) - Conversational memory with user profiles
|
|
350
|
+
- [AFS LocalFS Example](../../examples/afs-local-fs/README.md) - File system access with AI agents
|
|
351
|
+
- [AFS MCP Server Example](../../examples/afs-mcp-server/README.md) - Mount MCP servers as AFS modules
|
|
352
|
+
|
|
353
|
+
## TypeScript Support
|
|
354
|
+
|
|
355
|
+
This package includes full TypeScript type definitions.
|
|
356
|
+
|
|
357
|
+
## License
|
|
358
|
+
|
|
359
|
+
[Elastic-2.0](../../LICENSE.md)
|
package/lib/cjs/afs.d.ts
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { Emitter } from "strict-event-emitter";
|
|
2
|
-
import { SharedAFSStorage, type SharedAFSStorageOptions } from "./storage/index.js";
|
|
3
|
-
import type { AFSStorage } from "./storage/type.js";
|
|
4
2
|
import type { AFSEntry, AFSListOptions, AFSModule, AFSRoot, AFSRootEvents, AFSSearchOptions, AFSWriteEntryPayload } from "./type.js";
|
|
5
3
|
export interface AFSOptions {
|
|
6
|
-
storage?: SharedAFSStorage | SharedAFSStorageOptions;
|
|
7
4
|
modules?: AFSModule[];
|
|
8
5
|
}
|
|
9
6
|
export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
10
|
-
|
|
11
|
-
path: string;
|
|
7
|
+
name: string;
|
|
12
8
|
constructor(options?: AFSOptions);
|
|
13
|
-
private _storage;
|
|
14
|
-
storage(module: AFSModule): AFSStorage;
|
|
15
9
|
private modules;
|
|
16
|
-
|
|
10
|
+
mount(module: AFSModule): this;
|
|
17
11
|
listModules(): Promise<{
|
|
18
|
-
|
|
12
|
+
name: string;
|
|
19
13
|
path: string;
|
|
20
14
|
description?: string;
|
|
15
|
+
module: AFSModule;
|
|
21
16
|
}[]>;
|
|
22
17
|
list(path: string, options?: AFSListOptions): Promise<{
|
|
23
18
|
list: AFSEntry[];
|
|
@@ -36,4 +31,9 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
36
31
|
message?: string;
|
|
37
32
|
}>;
|
|
38
33
|
private findModules;
|
|
34
|
+
exec(path: string, args: Record<string, any>, options: {
|
|
35
|
+
context: any;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
result: Record<string, any>;
|
|
38
|
+
}>;
|
|
39
39
|
}
|
package/lib/cjs/afs.js
CHANGED
|
@@ -3,38 +3,36 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.AFS = void 0;
|
|
4
4
|
const strict_event_emitter_1 = require("strict-event-emitter");
|
|
5
5
|
const ufo_1 = require("ufo");
|
|
6
|
-
const index_js_1 = require("./history/index.js");
|
|
7
|
-
const index_js_2 = require("./storage/index.js");
|
|
8
6
|
const DEFAULT_MAX_DEPTH = 1;
|
|
7
|
+
const MODULES_ROOT_DIR = "/modules";
|
|
9
8
|
class AFS extends strict_event_emitter_1.Emitter {
|
|
10
|
-
|
|
11
|
-
path = "/";
|
|
9
|
+
name = "AFSRoot";
|
|
12
10
|
constructor(options) {
|
|
13
11
|
super();
|
|
14
|
-
this._storage =
|
|
15
|
-
options?.storage instanceof index_js_2.SharedAFSStorage
|
|
16
|
-
? options.storage
|
|
17
|
-
: new index_js_2.SharedAFSStorage(options?.storage);
|
|
18
|
-
this.use(new index_js_1.AFSHistory());
|
|
19
12
|
for (const module of options?.modules ?? []) {
|
|
20
|
-
this.
|
|
13
|
+
this.mount(module);
|
|
21
14
|
}
|
|
22
15
|
}
|
|
23
|
-
_storage;
|
|
24
|
-
storage(module) {
|
|
25
|
-
return this._storage.withModule(module);
|
|
26
|
-
}
|
|
27
16
|
modules = new Map();
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
mount(module) {
|
|
18
|
+
let path = (0, ufo_1.joinURL)("/", module.name);
|
|
19
|
+
if (!/^\/[^/]+$/.test(path)) {
|
|
20
|
+
throw new Error(`Invalid mount path: ${path}. Must start with '/' and contain no other '/'`);
|
|
21
|
+
}
|
|
22
|
+
if (this.modules.has(path)) {
|
|
23
|
+
throw new Error(`Module already mounted at path: ${path}`);
|
|
24
|
+
}
|
|
25
|
+
path = (0, ufo_1.joinURL)(MODULES_ROOT_DIR, path);
|
|
26
|
+
this.modules.set(path, module);
|
|
30
27
|
module.onMount?.(this);
|
|
31
28
|
return this;
|
|
32
29
|
}
|
|
33
30
|
async listModules() {
|
|
34
31
|
return Array.from(this.modules.entries()).map(([path, module]) => ({
|
|
35
|
-
moduleId: module.moduleId,
|
|
36
32
|
path,
|
|
33
|
+
name: module.name,
|
|
37
34
|
description: module.description,
|
|
35
|
+
module,
|
|
38
36
|
}));
|
|
39
37
|
}
|
|
40
38
|
async list(path, options) {
|
|
@@ -46,7 +44,7 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
46
44
|
const matches = this.findModules(path, options);
|
|
47
45
|
for (const matched of matches) {
|
|
48
46
|
const moduleEntry = {
|
|
49
|
-
id: matched.module.
|
|
47
|
+
id: matched.module.name,
|
|
50
48
|
path: matched.remainedModulePath,
|
|
51
49
|
summary: matched.module.description,
|
|
52
50
|
};
|
|
@@ -64,7 +62,7 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
64
62
|
if (list.length) {
|
|
65
63
|
results.push(...list.map((entry) => ({
|
|
66
64
|
...entry,
|
|
67
|
-
path: (0, ufo_1.joinURL)(matched.
|
|
65
|
+
path: (0, ufo_1.joinURL)(matched.modulePath, entry.path),
|
|
68
66
|
})));
|
|
69
67
|
}
|
|
70
68
|
else {
|
|
@@ -74,21 +72,21 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
74
72
|
messages.push(message);
|
|
75
73
|
}
|
|
76
74
|
catch (error) {
|
|
77
|
-
console.error(`Error listing from module at ${matched.
|
|
75
|
+
console.error(`Error listing from module at ${matched.modulePath}`, error);
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
78
|
return { list: results, message: messages.join("; ").trim() || undefined };
|
|
81
79
|
}
|
|
82
80
|
async read(path) {
|
|
83
81
|
const modules = this.findModules(path, { exactMatch: true });
|
|
84
|
-
for (const { module, subpath } of modules) {
|
|
82
|
+
for (const { module, modulePath, subpath } of modules) {
|
|
85
83
|
const res = await module.read?.(subpath);
|
|
86
84
|
if (res?.result) {
|
|
87
85
|
return {
|
|
88
86
|
...res,
|
|
89
87
|
result: {
|
|
90
88
|
...res.result,
|
|
91
|
-
path: (0, ufo_1.joinURL)(
|
|
89
|
+
path: (0, ufo_1.joinURL)(modulePath, res.result.path),
|
|
92
90
|
},
|
|
93
91
|
};
|
|
94
92
|
}
|
|
@@ -104,27 +102,27 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
104
102
|
...res,
|
|
105
103
|
result: {
|
|
106
104
|
...res.result,
|
|
107
|
-
path: (0, ufo_1.joinURL)(module.
|
|
105
|
+
path: (0, ufo_1.joinURL)(module.modulePath, res.result.path),
|
|
108
106
|
},
|
|
109
107
|
};
|
|
110
108
|
}
|
|
111
109
|
async search(path, query, options) {
|
|
112
110
|
const results = [];
|
|
113
111
|
const messages = [];
|
|
114
|
-
for (const { module, subpath } of this.findModules(path)) {
|
|
112
|
+
for (const { module, modulePath, subpath } of this.findModules(path)) {
|
|
115
113
|
if (!module.search)
|
|
116
114
|
continue;
|
|
117
115
|
try {
|
|
118
116
|
const { list, message } = await module.search(subpath, query, options);
|
|
119
117
|
results.push(...list.map((entry) => ({
|
|
120
118
|
...entry,
|
|
121
|
-
path: (0, ufo_1.joinURL)(
|
|
119
|
+
path: (0, ufo_1.joinURL)(modulePath, entry.path),
|
|
122
120
|
})));
|
|
123
121
|
if (message)
|
|
124
122
|
messages.push(message);
|
|
125
123
|
}
|
|
126
124
|
catch (error) {
|
|
127
|
-
console.error(`Error searching in module at ${
|
|
125
|
+
console.error(`Error searching in module at ${modulePath}`, error);
|
|
128
126
|
}
|
|
129
127
|
}
|
|
130
128
|
return { list: results, message: messages.join("; ") };
|
|
@@ -153,9 +151,15 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
153
151
|
}
|
|
154
152
|
if (newMaxDepth < 0)
|
|
155
153
|
continue;
|
|
156
|
-
matched.push({ module, maxDepth: newMaxDepth, subpath, remainedModulePath });
|
|
154
|
+
matched.push({ module, modulePath, maxDepth: newMaxDepth, subpath, remainedModulePath });
|
|
157
155
|
}
|
|
158
156
|
return matched;
|
|
159
157
|
}
|
|
158
|
+
async exec(path, args, options) {
|
|
159
|
+
const module = this.findModules(path)[0];
|
|
160
|
+
if (!module?.module.exec)
|
|
161
|
+
throw new Error(`No module found for path: ${path}`);
|
|
162
|
+
return await module.module.exec(module.subpath, args, options);
|
|
163
|
+
}
|
|
160
164
|
}
|
|
161
165
|
exports.AFS = AFS;
|
package/lib/cjs/index.d.ts
CHANGED
package/lib/cjs/index.js
CHANGED
|
@@ -15,6 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./afs.js"), exports);
|
|
18
|
-
__exportStar(require("./history/index.js"), exports);
|
|
19
|
-
__exportStar(require("./storage/index.js"), exports);
|
|
20
18
|
__exportStar(require("./type.js"), exports);
|
package/lib/cjs/type.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Emitter } from "strict-event-emitter";
|
|
2
|
-
import type { AFSStorage } from "./storage/type.js";
|
|
3
2
|
export interface AFSListOptions {
|
|
4
3
|
filter?: {
|
|
5
4
|
userId?: string;
|
|
@@ -16,8 +15,7 @@ export interface AFSSearchOptions {
|
|
|
16
15
|
export interface AFSWriteEntryPayload extends Omit<AFSEntry, "id" | "path"> {
|
|
17
16
|
}
|
|
18
17
|
export interface AFSModule {
|
|
19
|
-
readonly
|
|
20
|
-
readonly path: string;
|
|
18
|
+
readonly name: string;
|
|
21
19
|
readonly description?: string;
|
|
22
20
|
onMount?(root: AFSRoot): void;
|
|
23
21
|
list?(path: string, options?: AFSListOptions): Promise<{
|
|
@@ -36,6 +34,11 @@ export interface AFSModule {
|
|
|
36
34
|
list: AFSEntry[];
|
|
37
35
|
message?: string;
|
|
38
36
|
}>;
|
|
37
|
+
exec?(path: string, args: Record<string, any>, options: {
|
|
38
|
+
context: any;
|
|
39
|
+
}): Promise<{
|
|
40
|
+
result: Record<string, any>;
|
|
41
|
+
}>;
|
|
39
42
|
}
|
|
40
43
|
export type AFSRootEvents = {
|
|
41
44
|
agentSucceed: [{
|
|
@@ -47,7 +50,14 @@ export type AFSRootEvents = {
|
|
|
47
50
|
}];
|
|
48
51
|
};
|
|
49
52
|
export interface AFSRoot extends Emitter<AFSRootEvents>, AFSModule {
|
|
50
|
-
|
|
53
|
+
}
|
|
54
|
+
export interface AFSEntryMetadata extends Record<string, any> {
|
|
55
|
+
execute?: {
|
|
56
|
+
name: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
inputSchema?: Record<string, any>;
|
|
59
|
+
outputSchema?: Record<string, any>;
|
|
60
|
+
};
|
|
51
61
|
}
|
|
52
62
|
export interface AFSEntry<T = any> {
|
|
53
63
|
id: string;
|
|
@@ -57,7 +67,8 @@ export interface AFSEntry<T = any> {
|
|
|
57
67
|
userId?: string | null;
|
|
58
68
|
sessionId?: string | null;
|
|
59
69
|
summary?: string | null;
|
|
60
|
-
|
|
70
|
+
description?: string | null;
|
|
71
|
+
metadata?: AFSEntryMetadata | null;
|
|
61
72
|
linkTo?: string | null;
|
|
62
73
|
content?: T;
|
|
63
74
|
}
|
package/lib/dts/afs.d.ts
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { Emitter } from "strict-event-emitter";
|
|
2
|
-
import { SharedAFSStorage, type SharedAFSStorageOptions } from "./storage/index.js";
|
|
3
|
-
import type { AFSStorage } from "./storage/type.js";
|
|
4
2
|
import type { AFSEntry, AFSListOptions, AFSModule, AFSRoot, AFSRootEvents, AFSSearchOptions, AFSWriteEntryPayload } from "./type.js";
|
|
5
3
|
export interface AFSOptions {
|
|
6
|
-
storage?: SharedAFSStorage | SharedAFSStorageOptions;
|
|
7
4
|
modules?: AFSModule[];
|
|
8
5
|
}
|
|
9
6
|
export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
10
|
-
|
|
11
|
-
path: string;
|
|
7
|
+
name: string;
|
|
12
8
|
constructor(options?: AFSOptions);
|
|
13
|
-
private _storage;
|
|
14
|
-
storage(module: AFSModule): AFSStorage;
|
|
15
9
|
private modules;
|
|
16
|
-
|
|
10
|
+
mount(module: AFSModule): this;
|
|
17
11
|
listModules(): Promise<{
|
|
18
|
-
|
|
12
|
+
name: string;
|
|
19
13
|
path: string;
|
|
20
14
|
description?: string;
|
|
15
|
+
module: AFSModule;
|
|
21
16
|
}[]>;
|
|
22
17
|
list(path: string, options?: AFSListOptions): Promise<{
|
|
23
18
|
list: AFSEntry[];
|
|
@@ -36,4 +31,9 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
36
31
|
message?: string;
|
|
37
32
|
}>;
|
|
38
33
|
private findModules;
|
|
34
|
+
exec(path: string, args: Record<string, any>, options: {
|
|
35
|
+
context: any;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
result: Record<string, any>;
|
|
38
|
+
}>;
|
|
39
39
|
}
|
package/lib/dts/index.d.ts
CHANGED