@aigne/example-afs-git 0.0.0
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/.env.local.example +44 -0
- package/LICENSE.md +93 -0
- package/README.md +441 -0
- package/index.test.ts +11 -0
- package/index.ts +64 -0
- package/package.json +35 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Change the name of this file to .env.local and fill in the following values
|
|
2
|
+
|
|
3
|
+
# Uncomment the lines below to enable debug logging
|
|
4
|
+
# DEBUG="aigne:*"
|
|
5
|
+
|
|
6
|
+
# Use different Models
|
|
7
|
+
|
|
8
|
+
# OpenAI
|
|
9
|
+
# MODEL="openai/gpt-4.1"
|
|
10
|
+
# OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
|
|
11
|
+
|
|
12
|
+
# Anthropic claude
|
|
13
|
+
# MODEL="anthropic/claude-3-7-sonnet-latest"
|
|
14
|
+
# ANTHROPIC_API_KEY=""
|
|
15
|
+
|
|
16
|
+
# Gemini
|
|
17
|
+
MODEL="google/gemini-2.5-pro"
|
|
18
|
+
# GEMINI_API_KEY=""
|
|
19
|
+
|
|
20
|
+
# Bedrock nova
|
|
21
|
+
# MODEL=bedrock:us.amazon.nova-premier-v1:0
|
|
22
|
+
# AWS_ACCESS_KEY_ID=""
|
|
23
|
+
# AWS_SECRET_ACCESS_KEY=""
|
|
24
|
+
# AWS_REGION=us-west-2
|
|
25
|
+
|
|
26
|
+
# DeepSeek
|
|
27
|
+
# MODEL="deepseek/deepseek-chat"
|
|
28
|
+
# DEEPSEEK_API_KEY=""
|
|
29
|
+
|
|
30
|
+
# OpenRouter
|
|
31
|
+
# MODEL="openrouter/openai/gpt-4o"
|
|
32
|
+
# OPEN_ROUTER_API_KEY=""
|
|
33
|
+
|
|
34
|
+
# xAI
|
|
35
|
+
# MODEL="xai/grok-2-latest"
|
|
36
|
+
# XAI_API_KEY=""
|
|
37
|
+
|
|
38
|
+
# Ollama
|
|
39
|
+
# MODEL="ollama/llama3.2"
|
|
40
|
+
# OLLAMA_DEFAULT_BASE_URL="http://localhost:11434/v1";
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# Setup proxy if needed
|
|
44
|
+
# HTTPS_PROXY=http://localhost:7890
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Elastic License 2.0
|
|
2
|
+
|
|
3
|
+
URL: https://www.elastic.co/licensing/elastic-license
|
|
4
|
+
|
|
5
|
+
## Acceptance
|
|
6
|
+
|
|
7
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
8
|
+
|
|
9
|
+
## Copyright License
|
|
10
|
+
|
|
11
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
|
12
|
+
non-sublicensable, non-transferable license to use, copy, distribute, make
|
|
13
|
+
available, and prepare derivative works of the software, in each case subject to
|
|
14
|
+
the limitations and conditions below.
|
|
15
|
+
|
|
16
|
+
## Limitations
|
|
17
|
+
|
|
18
|
+
You may not provide the software to third parties as a hosted or managed
|
|
19
|
+
service, where the service provides users with access to any substantial set of
|
|
20
|
+
the features or functionality of the software.
|
|
21
|
+
|
|
22
|
+
You may not move, change, disable, or circumvent the license key functionality
|
|
23
|
+
in the software, and you may not remove or obscure any functionality in the
|
|
24
|
+
software that is protected by the license key.
|
|
25
|
+
|
|
26
|
+
You may not alter, remove, or obscure any licensing, copyright, or other notices
|
|
27
|
+
of the licensor in the software. Any use of the licensor’s trademarks is subject
|
|
28
|
+
to applicable law.
|
|
29
|
+
|
|
30
|
+
## Patents
|
|
31
|
+
|
|
32
|
+
The licensor grants you a license, under any patent claims the licensor can
|
|
33
|
+
license, or becomes able to license, to make, have made, use, sell, offer for
|
|
34
|
+
sale, import and have imported the software, in each case subject to the
|
|
35
|
+
limitations and conditions in this license. This license does not cover any
|
|
36
|
+
patent claims that you cause to be infringed by modifications or additions to
|
|
37
|
+
the software. If you or your company make any written claim that the software
|
|
38
|
+
infringes or contributes to infringement of any patent, your patent license for
|
|
39
|
+
the software granted under these terms ends immediately. If your company makes
|
|
40
|
+
such a claim, your patent license ends immediately for work on behalf of your
|
|
41
|
+
company.
|
|
42
|
+
|
|
43
|
+
## Notices
|
|
44
|
+
|
|
45
|
+
You must ensure that anyone who gets a copy of any part of the software from you
|
|
46
|
+
also gets a copy of these terms.
|
|
47
|
+
|
|
48
|
+
If you modify the software, you must include in any modified copies of the
|
|
49
|
+
software prominent notices stating that you have modified the software.
|
|
50
|
+
|
|
51
|
+
## No Other Rights
|
|
52
|
+
|
|
53
|
+
These terms do not imply any licenses other than those expressly granted in
|
|
54
|
+
these terms.
|
|
55
|
+
|
|
56
|
+
## Termination
|
|
57
|
+
|
|
58
|
+
If you use the software in violation of these terms, such use is not licensed,
|
|
59
|
+
and your licenses will automatically terminate. If the licensor provides you
|
|
60
|
+
with a notice of your violation, and you cease all violation of this license no
|
|
61
|
+
later than 30 days after you receive that notice, your licenses will be
|
|
62
|
+
reinstated retroactively. However, if you violate these terms after such
|
|
63
|
+
reinstatement, any additional violation of these terms will cause your licenses
|
|
64
|
+
to terminate automatically and permanently.
|
|
65
|
+
|
|
66
|
+
## No Liability
|
|
67
|
+
|
|
68
|
+
*As far as the law allows, the software comes as is, without any warranty or
|
|
69
|
+
condition, and the licensor will not be liable to you for any damages arising
|
|
70
|
+
out of these terms or the use or nature of the software, under any kind of
|
|
71
|
+
legal claim.*
|
|
72
|
+
|
|
73
|
+
## Definitions
|
|
74
|
+
|
|
75
|
+
The **licensor** is the entity offering these terms, and the **software** is the
|
|
76
|
+
software the licensor makes available under these terms, including any portion
|
|
77
|
+
of it.
|
|
78
|
+
|
|
79
|
+
**you** refers to the individual or entity agreeing to these terms.
|
|
80
|
+
|
|
81
|
+
**your company** is any legal entity, sole proprietorship, or other kind of
|
|
82
|
+
organization that you work for, plus all organizations that have control over,
|
|
83
|
+
are under the control of, or are under common control with that
|
|
84
|
+
organization. **control** means ownership of substantially all the assets of an
|
|
85
|
+
entity, or the power to direct its management and policies by vote, contract, or
|
|
86
|
+
otherwise. Control can be direct or indirect.
|
|
87
|
+
|
|
88
|
+
**your licenses** are all the licenses granted to you for the software under
|
|
89
|
+
these terms.
|
|
90
|
+
|
|
91
|
+
**use** means anything you do with the software requiring one of your licenses.
|
|
92
|
+
|
|
93
|
+
**trademark** means trademarks, service marks, and similar rights.
|
package/README.md
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# AFS JSON Example
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<picture>
|
|
5
|
+
<source srcset="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/logo-dark.svg" media="(prefers-color-scheme: dark)">
|
|
6
|
+
<source srcset="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/logo.svg" media="(prefers-color-scheme: light)">
|
|
7
|
+
<img src="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/logo.svg" alt="AIGNE Logo" width="400" />
|
|
8
|
+
</picture>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
This example demonstrates how to create a chatbot that can interact with JSON and YAML files as a virtual file system using the [AIGNE Framework](https://github.com/AIGNE-io/aigne-framework) and [AIGNE CLI](https://github.com/AIGNE-io/aigne-framework/blob/main/packages/cli/README.md). The example utilizes the `AFSJSON` module to provide JSON/YAML file access to AI agents through the **AIGNE File System (AFS)** interface.
|
|
12
|
+
|
|
13
|
+
**AIGNE File System (AFS)** is a virtual file system abstraction that provides AI agents with unified access to various storage backends. For comprehensive documentation, see [AFS Documentation](../../afs/README.md).
|
|
14
|
+
|
|
15
|
+
**Note:** The AFSJSON module supports both JSON and YAML formats. File format is automatically detected based on the file extension (.json, .yaml, .yml).
|
|
16
|
+
|
|
17
|
+
## What You'll See
|
|
18
|
+
|
|
19
|
+
**User asks:** "What's the email of the second user?"
|
|
20
|
+
|
|
21
|
+
**Behind the scenes:**
|
|
22
|
+
1. LLM calls `afs_list` → lists JSON structure as directories/files
|
|
23
|
+
2. Sees `/users` directory with `/users/0`, `/users/1`, `/users/2` subdirectories
|
|
24
|
+
3. LLM calls `afs_read("/users/1/email")` → reads the email property
|
|
25
|
+
4. LLM presents: "The email is alice@example.com"
|
|
26
|
+
|
|
27
|
+
**The power:** AI agents can navigate JSON structures as if they were directories, making complex data queries simple and intuitive!
|
|
28
|
+
|
|
29
|
+
## Prerequisites
|
|
30
|
+
|
|
31
|
+
* [Node.js](https://nodejs.org) (>=20.0) and npm installed on your machine
|
|
32
|
+
* A JSON or YAML file to explore
|
|
33
|
+
* An [OpenAI API key](https://platform.openai.com/api-keys) for interacting with OpenAI's services
|
|
34
|
+
* Optional dependencies (if running the example from source code):
|
|
35
|
+
* [Pnpm](https://pnpm.io) for package management
|
|
36
|
+
* [Bun](https://bun.sh) for running unit tests & examples
|
|
37
|
+
|
|
38
|
+
## Quick Start (No Installation Required)
|
|
39
|
+
|
|
40
|
+
### Run the Example
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export OPENAI_API_KEY=YOUR_OPENAI_API_KEY
|
|
44
|
+
|
|
45
|
+
# Mount a JSON file (read-write by default)
|
|
46
|
+
npx -y @aigne/example-afs-json --path ./config.json --interactive
|
|
47
|
+
|
|
48
|
+
# Mount a YAML file
|
|
49
|
+
npx -y @aigne/example-afs-json --path ./config.yaml --interactive
|
|
50
|
+
|
|
51
|
+
# Ask a specific question
|
|
52
|
+
npx -y @aigne/example-afs-json --path ./data.json --input "What users are in the JSON file?"
|
|
53
|
+
|
|
54
|
+
# YAML file example
|
|
55
|
+
npx -y @aigne/example-afs-json --path ./settings.yml --input "What's the database host?"
|
|
56
|
+
|
|
57
|
+
# Read-only mode (works with both JSON and YAML)
|
|
58
|
+
npx -y @aigne/example-afs-json --path ./config.json --access-mode readonly --interactive
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## See It In Action
|
|
62
|
+
|
|
63
|
+
Here's what happens when you ask about JSON data:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
Given JSON file (users.json):
|
|
67
|
+
{
|
|
68
|
+
"users": [
|
|
69
|
+
{ "name": "Bob", "email": "bob@example.com", "age": 30 },
|
|
70
|
+
{ "name": "Alice", "email": "alice@example.com", "age": 25 },
|
|
71
|
+
{ "name": "Charlie", "email": "charlie@example.com", "age": 35 }
|
|
72
|
+
],
|
|
73
|
+
"config": {
|
|
74
|
+
"appName": "MyApp",
|
|
75
|
+
"version": "1.0.0"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
👤 You: "What's the email of the second user?"
|
|
80
|
+
|
|
81
|
+
🤖 Agent thinks: Let me explore the JSON structure...
|
|
82
|
+
→ Calls: afs_list("/")
|
|
83
|
+
|
|
84
|
+
📁 Found structure:
|
|
85
|
+
• /users (directory - array)
|
|
86
|
+
• /config (directory - object)
|
|
87
|
+
|
|
88
|
+
🤖 Agent thinks: Users is an array, let me check its contents...
|
|
89
|
+
→ Calls: afs_list("/users")
|
|
90
|
+
|
|
91
|
+
📄 Found items:
|
|
92
|
+
• /users/0 (first user)
|
|
93
|
+
• /users/1 (second user)
|
|
94
|
+
• /users/2 (third user)
|
|
95
|
+
|
|
96
|
+
🤖 Agent thinks: Let me read the email of the second user...
|
|
97
|
+
→ Calls: afs_read("/users/1/email")
|
|
98
|
+
|
|
99
|
+
🤖 AI: "The email of the second user is alice@example.com"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Key insight:** JSON structures become navigable file systems - arrays are directories with numeric indices, objects are directories with property names!
|
|
103
|
+
|
|
104
|
+
### Connect to an AI Model
|
|
105
|
+
|
|
106
|
+
As an example, running `npx -y @aigne/example-afs-json --input "What's in this JSON?"` requires an AI model. If this is your first run, you need to connect one.
|
|
107
|
+
|
|
108
|
+
- Connect via the official AIGNE Hub
|
|
109
|
+
- Connect via a self-hosted AIGNE Hub
|
|
110
|
+
- Connect via a third-party model provider (OpenAI, DeepSeek, etc.)
|
|
111
|
+
|
|
112
|
+
For detailed setup instructions, see [.env.local.example](./.env.local.example).
|
|
113
|
+
|
|
114
|
+
### Debugging
|
|
115
|
+
|
|
116
|
+
The `aigne observe` command starts a local web server to monitor and analyze agent execution data. It provides a user-friendly interface to inspect traces, view detailed call information, and understand your agent's behavior during runtime.
|
|
117
|
+
|
|
118
|
+
## Installation
|
|
119
|
+
|
|
120
|
+
### Clone the Repository
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
git clone https://github.com/AIGNE-io/aigne-framework
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Install Dependencies
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
cd aigne-framework/examples/afs-json
|
|
130
|
+
|
|
131
|
+
pnpm install
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Run the Example
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Run with a JSON file
|
|
138
|
+
pnpm start --path ./data.json
|
|
139
|
+
|
|
140
|
+
# Run in interactive chat mode
|
|
141
|
+
pnpm start --path ./config.json --interactive
|
|
142
|
+
|
|
143
|
+
# Read-only mode (no modifications allowed)
|
|
144
|
+
pnpm start --path ./config.json --access-mode readonly --interactive
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Command Line Options
|
|
148
|
+
|
|
149
|
+
| Option | Description | Default | Example |
|
|
150
|
+
|--------|-------------|---------|---------|
|
|
151
|
+
| `--path` | Path to the JSON or YAML file | Required | `--path ./data.json` or `--path ./config.yaml` |
|
|
152
|
+
| `--access-mode` | Access mode: `readonly` or `readwrite` | `readwrite` | `--access-mode readonly` |
|
|
153
|
+
| `--interactive` | Run in interactive chat mode | `false` | `--interactive` |
|
|
154
|
+
| `--input` | Single question to ask | - | `--input "What's in this file?"` |
|
|
155
|
+
|
|
156
|
+
**Supported file formats:**
|
|
157
|
+
- `.json` - JSON files
|
|
158
|
+
- `.yaml` - YAML files
|
|
159
|
+
- `.yml` - YAML files
|
|
160
|
+
|
|
161
|
+
File format is automatically detected from the extension.
|
|
162
|
+
|
|
163
|
+
## How It Works: 3 Simple Steps
|
|
164
|
+
|
|
165
|
+
### 1. Create AFSJSON Module
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { AFSJSON } from "@aigne/afs-json";
|
|
169
|
+
|
|
170
|
+
// Works with JSON files
|
|
171
|
+
const afsJson = new AFSJSON({
|
|
172
|
+
jsonPath: './data.json',
|
|
173
|
+
name: 'data', // optional: module name
|
|
174
|
+
accessMode: 'readwrite' // or 'readonly'
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Also works with YAML files
|
|
178
|
+
const afsYaml = new AFSJSON({
|
|
179
|
+
jsonPath: './config.yaml', // or './config.yml'
|
|
180
|
+
name: 'config',
|
|
181
|
+
accessMode: 'readwrite'
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 2. Mount It as an AFS Module
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { AFS } from "@aigne/afs";
|
|
189
|
+
import { AFSHistory } from "@aigne/afs-history";
|
|
190
|
+
|
|
191
|
+
const afs = new AFS()
|
|
192
|
+
.mount(new AFSHistory({ storage: { url: ":memory:" } }))
|
|
193
|
+
.mount(afsJson); // Mounted at /modules/data
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### 3. Create an AI Agent
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { AIAgent } from "@aigne/core";
|
|
200
|
+
|
|
201
|
+
const agent = AIAgent.from({
|
|
202
|
+
instructions: "Help users query and modify JSON data.",
|
|
203
|
+
inputKey: "message",
|
|
204
|
+
afs, // Agent gets: afs_list, afs_read, afs_write, afs_search
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**That's it!** The agent can now navigate JSON structures like a file system.
|
|
209
|
+
|
|
210
|
+
### What the Agent Can Do
|
|
211
|
+
|
|
212
|
+
**Read Operations:**
|
|
213
|
+
- **`afs_list`** - List JSON structure (objects/arrays as directories)
|
|
214
|
+
- **`afs_read`** - Read property values or nested structures
|
|
215
|
+
- **`afs_search`** - Search for values in the JSON
|
|
216
|
+
|
|
217
|
+
**Write Operations (readwrite mode):**
|
|
218
|
+
- **`afs_write`** - Update or create properties
|
|
219
|
+
- **`afs_delete`** - Delete properties or array elements
|
|
220
|
+
- **`afs_rename`** - Rename properties
|
|
221
|
+
|
|
222
|
+
All write operations automatically save to the file in its original format (JSON or YAML)!
|
|
223
|
+
|
|
224
|
+
## Path Structure
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
// Given this JSON:
|
|
228
|
+
{
|
|
229
|
+
"users": [
|
|
230
|
+
{ "name": "Bob", "email": "bob@example.com" },
|
|
231
|
+
{ "name": "Alice", "email": "alice@example.com" }
|
|
232
|
+
],
|
|
233
|
+
"config": {
|
|
234
|
+
"theme": "dark",
|
|
235
|
+
"lang": "en"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Mapped to AFS paths:
|
|
240
|
+
/ # Root
|
|
241
|
+
├── users/ # Array (directory)
|
|
242
|
+
│ ├── 0/ # First user (directory)
|
|
243
|
+
│ │ ├── name # File: "Bob"
|
|
244
|
+
│ │ └── email # File: "bob@example.com"
|
|
245
|
+
│ └── 1/ # Second user (directory)
|
|
246
|
+
│ ├── name # File: "Alice"
|
|
247
|
+
│ └── email # File: "alice@example.com"
|
|
248
|
+
└── config/ # Object (directory)
|
|
249
|
+
├── theme # File: "dark"
|
|
250
|
+
└── lang # File: "en"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Try These Examples
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Query user data (JSON)
|
|
257
|
+
npx -y @aigne/example-afs-json --path ./users.json --input "How many users are there?"
|
|
258
|
+
|
|
259
|
+
# Query YAML configuration
|
|
260
|
+
npx -y @aigne/example-afs-json --path ./config.yaml --input "What's the database host?"
|
|
261
|
+
|
|
262
|
+
# Read specific values
|
|
263
|
+
npx -y @aigne/example-afs-json --path ./config.json --input "What's the app version?"
|
|
264
|
+
|
|
265
|
+
# Search for values in YAML
|
|
266
|
+
npx -y @aigne/example-afs-json --path ./settings.yml --input "Find all email addresses"
|
|
267
|
+
|
|
268
|
+
# Update values (readwrite mode)
|
|
269
|
+
npx -y @aigne/example-afs-json --path ./config.json --input "Update the theme to light"
|
|
270
|
+
|
|
271
|
+
# Update YAML file
|
|
272
|
+
npx -y @aigne/example-afs-json --path ./config.yaml --input "Change the database port to 3306"
|
|
273
|
+
|
|
274
|
+
# Interactive mode - ask follow-up questions
|
|
275
|
+
npx -y @aigne/example-afs-json --path ./data.json --interactive
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**In chat mode, try:**
|
|
279
|
+
- "What properties are in the root?"
|
|
280
|
+
- "Show me all users"
|
|
281
|
+
- "What's the email of the first user?"
|
|
282
|
+
- "List all configuration settings"
|
|
283
|
+
- "Update the version to 2.0.0"
|
|
284
|
+
- "Add a new user named David"
|
|
285
|
+
|
|
286
|
+
## Use Cases
|
|
287
|
+
|
|
288
|
+
### Configuration Management
|
|
289
|
+
Let AI help manage app configurations (JSON or YAML):
|
|
290
|
+
```typescript
|
|
291
|
+
// JSON configuration
|
|
292
|
+
const afs = new AFS()
|
|
293
|
+
.mount(new AFSJSON({
|
|
294
|
+
jsonPath: './config.json',
|
|
295
|
+
accessMode: 'readwrite'
|
|
296
|
+
}));
|
|
297
|
+
|
|
298
|
+
// YAML configuration (common in Kubernetes, Docker Compose)
|
|
299
|
+
const afs = new AFS()
|
|
300
|
+
.mount(new AFSJSON({
|
|
301
|
+
jsonPath: './config.yaml',
|
|
302
|
+
accessMode: 'readwrite'
|
|
303
|
+
}));
|
|
304
|
+
// Ask: "Update the database port to 5432"
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Data Analysis
|
|
308
|
+
Query complex JSON data structures:
|
|
309
|
+
```typescript
|
|
310
|
+
const afs = new AFS()
|
|
311
|
+
.mount(new AFSJSON({
|
|
312
|
+
jsonPath: './analytics.json',
|
|
313
|
+
accessMode: 'readonly'
|
|
314
|
+
}));
|
|
315
|
+
// Ask: "What's the total revenue for last month?"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### API Response Exploration
|
|
319
|
+
Navigate large API responses:
|
|
320
|
+
```typescript
|
|
321
|
+
const afs = new AFS()
|
|
322
|
+
.mount(new AFSJSON({
|
|
323
|
+
jsonPath: './api-response.json',
|
|
324
|
+
accessMode: 'readonly'
|
|
325
|
+
}));
|
|
326
|
+
// Ask: "Find all error messages in the response"
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Settings Editor
|
|
330
|
+
Interactive settings modification:
|
|
331
|
+
```typescript
|
|
332
|
+
const afs = new AFS()
|
|
333
|
+
.mount(new AFSJSON({
|
|
334
|
+
jsonPath: './user-settings.json',
|
|
335
|
+
accessMode: 'readwrite'
|
|
336
|
+
}));
|
|
337
|
+
// Ask: "Enable dark mode and set font size to 14"
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Multi-File Access
|
|
341
|
+
Mount multiple JSON and YAML files:
|
|
342
|
+
```typescript
|
|
343
|
+
const afs = new AFS()
|
|
344
|
+
.mount("/users", new AFSJSON({ jsonPath: './users.json' }))
|
|
345
|
+
.mount("/config", new AFSJSON({ jsonPath: './config.yaml' }))
|
|
346
|
+
.mount("/data", new AFSJSON({ jsonPath: './data.json' }))
|
|
347
|
+
.mount("/k8s", new AFSJSON({ jsonPath: './deployment.yml' }));
|
|
348
|
+
// Agent can query across all files regardless of format
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## How JSON Maps to Paths
|
|
352
|
+
|
|
353
|
+
### Objects as Directories
|
|
354
|
+
```json
|
|
355
|
+
{ "name": "Bob", "age": 30 }
|
|
356
|
+
```
|
|
357
|
+
→ `/name` (file), `/age` (file)
|
|
358
|
+
|
|
359
|
+
### Arrays as Directories
|
|
360
|
+
```json
|
|
361
|
+
["apple", "banana", "orange"]
|
|
362
|
+
```
|
|
363
|
+
→ `/0` (file: "apple"), `/1` (file: "banana"), `/2` (file: "orange")
|
|
364
|
+
|
|
365
|
+
### Nested Structures
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"user": {
|
|
369
|
+
"profile": {
|
|
370
|
+
"name": "Bob"
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
→ `/user/profile/name` (file: "Bob")
|
|
376
|
+
|
|
377
|
+
### Arrays of Objects
|
|
378
|
+
```json
|
|
379
|
+
{
|
|
380
|
+
"users": [
|
|
381
|
+
{ "name": "Bob", "email": "bob@example.com" },
|
|
382
|
+
{ "name": "Alice", "email": "alice@example.com" }
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
→ `/users/0/name` (file: "Bob")
|
|
387
|
+
→ `/users/0/email` (file: "bob@example.com")
|
|
388
|
+
→ `/users/1/name` (file: "Alice")
|
|
389
|
+
→ `/users/1/email` (file: "alice@example.com")
|
|
390
|
+
|
|
391
|
+
## Advanced Features
|
|
392
|
+
|
|
393
|
+
### Read-Only Mode
|
|
394
|
+
Prevent accidental modifications:
|
|
395
|
+
```typescript
|
|
396
|
+
const afsJson = new AFSJSON({
|
|
397
|
+
jsonPath: './config.json',
|
|
398
|
+
accessMode: 'readonly' // No write/delete operations allowed
|
|
399
|
+
});
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Auto-Save on Write
|
|
403
|
+
Changes are automatically saved to the JSON file:
|
|
404
|
+
```typescript
|
|
405
|
+
// When agent calls afs_write, the JSON file is updated immediately
|
|
406
|
+
await afs.write('/config/theme', { content: 'dark' });
|
|
407
|
+
// config.json is now updated with theme: "dark"
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Array Operations
|
|
411
|
+
AI can intelligently modify arrays:
|
|
412
|
+
```typescript
|
|
413
|
+
// Add new array element
|
|
414
|
+
// Ask: "Add a new user named David with email david@example.com"
|
|
415
|
+
|
|
416
|
+
// Delete array element (indices shift automatically)
|
|
417
|
+
// Ask: "Remove the second user"
|
|
418
|
+
|
|
419
|
+
// Update array element
|
|
420
|
+
// Ask: "Update the first user's email to newemail@example.com"
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Related Examples
|
|
424
|
+
|
|
425
|
+
- [AFS LocalFS Example](../afs-local-fs/README.md) - Local file system access
|
|
426
|
+
- [AFS Git Example](../afs-git/README.md) - Git repository access
|
|
427
|
+
- [AFS Memory Example](../afs-memory/README.md) - Conversational memory with user profiles
|
|
428
|
+
- [AFS MCP Server Example](../afs-mcp-server/README.md) - Integration with MCP servers
|
|
429
|
+
|
|
430
|
+
## Related Packages
|
|
431
|
+
|
|
432
|
+
- [@aigne/afs](../../afs/README.md) - AFS core package
|
|
433
|
+
- [@aigne/afs-json](../../afs/json/README.md) - AFSJSON module documentation
|
|
434
|
+
|
|
435
|
+
## TypeScript Support
|
|
436
|
+
|
|
437
|
+
This package includes full TypeScript type definitions.
|
|
438
|
+
|
|
439
|
+
## License
|
|
440
|
+
|
|
441
|
+
[MIT](../../LICENSE.md)
|
package/index.test.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { runExampleTest } from "@aigne/test-utils/run-example-test.js";
|
|
3
|
+
|
|
4
|
+
test(
|
|
5
|
+
"should successfully run the chatbot",
|
|
6
|
+
async () => {
|
|
7
|
+
const { status } = await runExampleTest();
|
|
8
|
+
expect(status).toBe(0);
|
|
9
|
+
},
|
|
10
|
+
{ timeout: 600000 },
|
|
11
|
+
);
|
package/index.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env npx -y bun
|
|
2
|
+
|
|
3
|
+
import { AFS, type AFSAccessMode } from "@aigne/afs";
|
|
4
|
+
import { AFSHistory } from "@aigne/afs-history";
|
|
5
|
+
import { AFSJSON } from "@aigne/afs-json";
|
|
6
|
+
import { loadAIGNEWithCmdOptions, runWithAIGNE } from "@aigne/cli/utils/run-with-aigne.js";
|
|
7
|
+
import { AIAgent } from "@aigne/core";
|
|
8
|
+
import yargs from "yargs";
|
|
9
|
+
|
|
10
|
+
const argv = yargs()
|
|
11
|
+
.option("path", {
|
|
12
|
+
type: "string",
|
|
13
|
+
describe: "Path to the json/yaml file to mount",
|
|
14
|
+
default: ".",
|
|
15
|
+
})
|
|
16
|
+
.option("description", {
|
|
17
|
+
type: "string",
|
|
18
|
+
default: "Working directory mounted from local file system",
|
|
19
|
+
describe: "Description of the mounted file system",
|
|
20
|
+
})
|
|
21
|
+
.option("access-mode", {
|
|
22
|
+
type: "string",
|
|
23
|
+
choices: ["readonly", "readwrite"],
|
|
24
|
+
default: "readonly",
|
|
25
|
+
describe: "Access mode for the mounted file system",
|
|
26
|
+
})
|
|
27
|
+
.demandOption("path")
|
|
28
|
+
.strict(false)
|
|
29
|
+
.parseSync(process.argv);
|
|
30
|
+
|
|
31
|
+
const aigne = await loadAIGNEWithCmdOptions();
|
|
32
|
+
|
|
33
|
+
const afs = new AFS()
|
|
34
|
+
.mount(new AFSHistory({ storage: { url: ":memory:" } })) // In-memory history for this example
|
|
35
|
+
.mount(
|
|
36
|
+
new AFSJSON({
|
|
37
|
+
jsonPath: argv.path,
|
|
38
|
+
description: argv.description,
|
|
39
|
+
accessMode: argv.accessMode as AFSAccessMode,
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const agent = AIAgent.from({
|
|
44
|
+
instructions: `\
|
|
45
|
+
You are a friendly chatbot that can retrieve files from a virtual file system.
|
|
46
|
+
You should use the provided functions to list, search, and read files as needed to answer user questions.
|
|
47
|
+
|
|
48
|
+
<afs_modules>
|
|
49
|
+
{{ $afs.description }}
|
|
50
|
+
|
|
51
|
+
{{ $afs.modules | yaml.stringify }}
|
|
52
|
+
</afs_modules>
|
|
53
|
+
`,
|
|
54
|
+
inputKey: "message",
|
|
55
|
+
afs,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await runWithAIGNE(agent, {
|
|
59
|
+
aigne,
|
|
60
|
+
chatLoopOptions: {
|
|
61
|
+
welcome:
|
|
62
|
+
"Hello! I'm a chatbot that can help you interact with a json file mounted on AFS. Ask me anything about the file!",
|
|
63
|
+
},
|
|
64
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aigne/example-afs-git",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "A demonstration of using AIGNE Framework with AFS json module",
|
|
5
|
+
"author": "Arcblock <blocklet@arcblock.io> https://github.com/blocklet",
|
|
6
|
+
"homepage": "https://github.com/AIGNE-io/aigne-framework/tree/main/examples/afs-json",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/AIGNE-io/aigne-framework"
|
|
11
|
+
},
|
|
12
|
+
"bin": "index.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
".env.local.example",
|
|
15
|
+
"*.ts",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"yargs": "^18.0.0",
|
|
20
|
+
"@aigne/afs-history": "^1.2.0-beta.11",
|
|
21
|
+
"@aigne/afs": "^1.4.0-beta.10",
|
|
22
|
+
"@aigne/afs-json": "^1.0.0",
|
|
23
|
+
"@aigne/cli": "^1.59.0-beta.30",
|
|
24
|
+
"@aigne/core": "^1.72.0-beta.24"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/bun": "^1.2.22",
|
|
28
|
+
"@aigne/test-utils": "^0.5.69-beta.24"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"start": "bun run index.ts",
|
|
32
|
+
"lint": "tsc --noEmit",
|
|
33
|
+
"test:llm": "bun test index.test.ts"
|
|
34
|
+
}
|
|
35
|
+
}
|