agentfs-sdk 0.4.0rc5__tar.gz
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.
- agentfs_sdk-0.4.0rc5/MANIFEST.in +5 -0
- agentfs_sdk-0.4.0rc5/PKG-INFO +216 -0
- agentfs_sdk-0.4.0rc5/README.md +190 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk/__init__.py +22 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk/agentfs.py +126 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk/filesystem.py +544 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk/kvstore.py +136 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk/toolcalls.py +413 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk.egg-info/PKG-INFO +216 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk.egg-info/SOURCES.txt +18 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk.egg-info/dependency_links.txt +1 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk.egg-info/requires.txt +1 -0
- agentfs_sdk-0.4.0rc5/agentfs_sdk.egg-info/top_level.txt +1 -0
- agentfs_sdk-0.4.0rc5/pyproject.toml +65 -0
- agentfs_sdk-0.4.0rc5/setup.cfg +4 -0
- agentfs_sdk-0.4.0rc5/tests/test_agentfs.py +138 -0
- agentfs_sdk-0.4.0rc5/tests/test_basic.py +148 -0
- agentfs_sdk-0.4.0rc5/tests/test_filesystem.py +726 -0
- agentfs_sdk-0.4.0rc5/tests/test_kvstore.py +314 -0
- agentfs_sdk-0.4.0rc5/tests/test_toolcalls.py +474 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentfs-sdk
|
|
3
|
+
Version: 0.4.0rc5
|
|
4
|
+
Summary: AgentFS Python SDK - A filesystem and key-value store for AI agents
|
|
5
|
+
Author: Turso
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/tursodatabase/agentfs
|
|
8
|
+
Project-URL: Source, https://github.com/tursodatabase/agentfs
|
|
9
|
+
Project-URL: Repository, https://github.com/tursodatabase/agentfs
|
|
10
|
+
Project-URL: Issues, https://github.com/tursodatabase/agentfs/issues
|
|
11
|
+
Keywords: ai,agent,turso,sqlite,key-value,filesystem
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: MacOS
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Requires-Dist: pyturso==0.4.0rc17
|
|
26
|
+
|
|
27
|
+
# AgentFS Python SDK
|
|
28
|
+
|
|
29
|
+
A filesystem and key-value store for AI agents, powered by SQLite and [pyturso](https://pypi.org/project/pyturso/).
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install agentfs-sdk
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import asyncio
|
|
41
|
+
from agentfs_sdk import AgentFS, AgentFSOptions
|
|
42
|
+
|
|
43
|
+
async def main():
|
|
44
|
+
# Open an agent filesystem
|
|
45
|
+
agent = await AgentFS.open(AgentFSOptions(id='my-agent'))
|
|
46
|
+
|
|
47
|
+
# Use key-value store
|
|
48
|
+
await agent.kv.set('config', {'debug': True, 'version': '1.0'})
|
|
49
|
+
config = await agent.kv.get('config')
|
|
50
|
+
print(f"Config: {config}")
|
|
51
|
+
|
|
52
|
+
# Use filesystem
|
|
53
|
+
await agent.fs.write_file('/data/notes.txt', 'Hello, AgentFS!')
|
|
54
|
+
content = await agent.fs.read_file('/data/notes.txt')
|
|
55
|
+
print(f"Content: {content}")
|
|
56
|
+
|
|
57
|
+
# Track tool calls
|
|
58
|
+
call_id = await agent.tools.start('search', {'query': 'Python'})
|
|
59
|
+
await agent.tools.success(call_id, {'results': ['result1', 'result2']})
|
|
60
|
+
|
|
61
|
+
# Get statistics
|
|
62
|
+
stats = await agent.tools.get_stats()
|
|
63
|
+
for stat in stats:
|
|
64
|
+
print(f"{stat.name}: {stat.total_calls} calls, {stat.avg_duration_ms:.2f}ms avg")
|
|
65
|
+
|
|
66
|
+
# Close the database
|
|
67
|
+
await agent.close()
|
|
68
|
+
|
|
69
|
+
if __name__ == '__main__':
|
|
70
|
+
asyncio.run(main())
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Features
|
|
74
|
+
|
|
75
|
+
### Key-Value Store
|
|
76
|
+
|
|
77
|
+
Simple key-value storage with JSON serialization:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# Set a value
|
|
81
|
+
await agent.kv.set('user:123', {'name': 'Alice', 'age': 30})
|
|
82
|
+
|
|
83
|
+
# Get a value
|
|
84
|
+
user = await agent.kv.get('user:123')
|
|
85
|
+
|
|
86
|
+
# List by prefix
|
|
87
|
+
users = await agent.kv.list('user:')
|
|
88
|
+
|
|
89
|
+
# Delete a value
|
|
90
|
+
await agent.kv.delete('user:123')
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Filesystem
|
|
94
|
+
|
|
95
|
+
POSIX-like filesystem operations:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
# Write a file (creates parent directories automatically)
|
|
99
|
+
await agent.fs.write_file('/data/config.json', '{"key": "value"}')
|
|
100
|
+
|
|
101
|
+
# Read a file
|
|
102
|
+
content = await agent.fs.read_file('/data/config.json')
|
|
103
|
+
|
|
104
|
+
# Read as bytes
|
|
105
|
+
data = await agent.fs.read_file('/data/image.png', encoding=None)
|
|
106
|
+
|
|
107
|
+
# List directory
|
|
108
|
+
entries = await agent.fs.readdir('/data')
|
|
109
|
+
|
|
110
|
+
# Get file stats
|
|
111
|
+
stats = await agent.fs.stat('/data/config.json')
|
|
112
|
+
print(f"Size: {stats.size} bytes")
|
|
113
|
+
print(f"Modified: {stats.mtime}")
|
|
114
|
+
print(f"Is file: {stats.is_file()}")
|
|
115
|
+
|
|
116
|
+
# Delete a file
|
|
117
|
+
await agent.fs.delete_file('/data/config.json')
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Tool Calls Tracking
|
|
121
|
+
|
|
122
|
+
Track and analyze tool/function calls:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
# Start a tool call
|
|
126
|
+
call_id = await agent.tools.start('search', {'query': 'Python'})
|
|
127
|
+
|
|
128
|
+
# Mark as successful
|
|
129
|
+
await agent.tools.success(call_id, {'results': [...]})
|
|
130
|
+
|
|
131
|
+
# Or mark as failed
|
|
132
|
+
await agent.tools.error(call_id, 'Connection timeout')
|
|
133
|
+
|
|
134
|
+
# Record a completed call
|
|
135
|
+
await agent.tools.record(
|
|
136
|
+
'search',
|
|
137
|
+
started_at=1234567890,
|
|
138
|
+
completed_at=1234567892,
|
|
139
|
+
parameters={'query': 'Python'},
|
|
140
|
+
result={'results': [...]}
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Query tool calls
|
|
144
|
+
calls = await agent.tools.get_by_name('search', limit=10)
|
|
145
|
+
recent = await agent.tools.get_recent(since=1234567890)
|
|
146
|
+
|
|
147
|
+
# Get statistics
|
|
148
|
+
stats = await agent.tools.get_stats()
|
|
149
|
+
for stat in stats:
|
|
150
|
+
print(f"{stat.name}: {stat.successful}/{stat.total_calls} successful")
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Configuration
|
|
154
|
+
|
|
155
|
+
### Using Agent ID
|
|
156
|
+
|
|
157
|
+
Creates a database at `.agentfs/{id}.db`:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
agent = await AgentFS.open(AgentFSOptions(id='my-agent'))
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Using Custom Path
|
|
164
|
+
|
|
165
|
+
Specify a custom database path:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
agent = await AgentFS.open(AgentFSOptions(path='./data/mydb.db'))
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Using Both
|
|
172
|
+
|
|
173
|
+
You can specify both for clarity:
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
agent = await AgentFS.open(AgentFSOptions(id='my-agent', path='./data/mydb.db'))
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Context Manager Support
|
|
180
|
+
|
|
181
|
+
Use AgentFS with async context managers:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
async with await AgentFS.open(AgentFSOptions(id='my-agent')) as agent:
|
|
185
|
+
await agent.kv.set('key', 'value')
|
|
186
|
+
# Database is automatically closed when exiting the context
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
### Setup
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Install dependencies
|
|
195
|
+
uv sync --group dev
|
|
196
|
+
|
|
197
|
+
# Run tests
|
|
198
|
+
uv run pytest
|
|
199
|
+
|
|
200
|
+
# Format code
|
|
201
|
+
uv run ruff format agentfs_sdk tests
|
|
202
|
+
|
|
203
|
+
# Check code
|
|
204
|
+
uv run ruff check agentfs_sdk tests
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT License - see LICENSE file for details.
|
|
210
|
+
|
|
211
|
+
## Links
|
|
212
|
+
|
|
213
|
+
- [GitHub Repository](https://github.com/tursodatabase/agentfs)
|
|
214
|
+
- [TypeScript SDK](https://github.com/tursodatabase/agentfs/tree/main/sdk/typescript)
|
|
215
|
+
- [tursodb](https://github.com/tursodatabase/turso)
|
|
216
|
+
- [pyturso](https://pypi.org/project/pyturso/)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# AgentFS Python SDK
|
|
2
|
+
|
|
3
|
+
A filesystem and key-value store for AI agents, powered by SQLite and [pyturso](https://pypi.org/project/pyturso/).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install agentfs-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import asyncio
|
|
15
|
+
from agentfs_sdk import AgentFS, AgentFSOptions
|
|
16
|
+
|
|
17
|
+
async def main():
|
|
18
|
+
# Open an agent filesystem
|
|
19
|
+
agent = await AgentFS.open(AgentFSOptions(id='my-agent'))
|
|
20
|
+
|
|
21
|
+
# Use key-value store
|
|
22
|
+
await agent.kv.set('config', {'debug': True, 'version': '1.0'})
|
|
23
|
+
config = await agent.kv.get('config')
|
|
24
|
+
print(f"Config: {config}")
|
|
25
|
+
|
|
26
|
+
# Use filesystem
|
|
27
|
+
await agent.fs.write_file('/data/notes.txt', 'Hello, AgentFS!')
|
|
28
|
+
content = await agent.fs.read_file('/data/notes.txt')
|
|
29
|
+
print(f"Content: {content}")
|
|
30
|
+
|
|
31
|
+
# Track tool calls
|
|
32
|
+
call_id = await agent.tools.start('search', {'query': 'Python'})
|
|
33
|
+
await agent.tools.success(call_id, {'results': ['result1', 'result2']})
|
|
34
|
+
|
|
35
|
+
# Get statistics
|
|
36
|
+
stats = await agent.tools.get_stats()
|
|
37
|
+
for stat in stats:
|
|
38
|
+
print(f"{stat.name}: {stat.total_calls} calls, {stat.avg_duration_ms:.2f}ms avg")
|
|
39
|
+
|
|
40
|
+
# Close the database
|
|
41
|
+
await agent.close()
|
|
42
|
+
|
|
43
|
+
if __name__ == '__main__':
|
|
44
|
+
asyncio.run(main())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
### Key-Value Store
|
|
50
|
+
|
|
51
|
+
Simple key-value storage with JSON serialization:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
# Set a value
|
|
55
|
+
await agent.kv.set('user:123', {'name': 'Alice', 'age': 30})
|
|
56
|
+
|
|
57
|
+
# Get a value
|
|
58
|
+
user = await agent.kv.get('user:123')
|
|
59
|
+
|
|
60
|
+
# List by prefix
|
|
61
|
+
users = await agent.kv.list('user:')
|
|
62
|
+
|
|
63
|
+
# Delete a value
|
|
64
|
+
await agent.kv.delete('user:123')
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Filesystem
|
|
68
|
+
|
|
69
|
+
POSIX-like filesystem operations:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
# Write a file (creates parent directories automatically)
|
|
73
|
+
await agent.fs.write_file('/data/config.json', '{"key": "value"}')
|
|
74
|
+
|
|
75
|
+
# Read a file
|
|
76
|
+
content = await agent.fs.read_file('/data/config.json')
|
|
77
|
+
|
|
78
|
+
# Read as bytes
|
|
79
|
+
data = await agent.fs.read_file('/data/image.png', encoding=None)
|
|
80
|
+
|
|
81
|
+
# List directory
|
|
82
|
+
entries = await agent.fs.readdir('/data')
|
|
83
|
+
|
|
84
|
+
# Get file stats
|
|
85
|
+
stats = await agent.fs.stat('/data/config.json')
|
|
86
|
+
print(f"Size: {stats.size} bytes")
|
|
87
|
+
print(f"Modified: {stats.mtime}")
|
|
88
|
+
print(f"Is file: {stats.is_file()}")
|
|
89
|
+
|
|
90
|
+
# Delete a file
|
|
91
|
+
await agent.fs.delete_file('/data/config.json')
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Tool Calls Tracking
|
|
95
|
+
|
|
96
|
+
Track and analyze tool/function calls:
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
# Start a tool call
|
|
100
|
+
call_id = await agent.tools.start('search', {'query': 'Python'})
|
|
101
|
+
|
|
102
|
+
# Mark as successful
|
|
103
|
+
await agent.tools.success(call_id, {'results': [...]})
|
|
104
|
+
|
|
105
|
+
# Or mark as failed
|
|
106
|
+
await agent.tools.error(call_id, 'Connection timeout')
|
|
107
|
+
|
|
108
|
+
# Record a completed call
|
|
109
|
+
await agent.tools.record(
|
|
110
|
+
'search',
|
|
111
|
+
started_at=1234567890,
|
|
112
|
+
completed_at=1234567892,
|
|
113
|
+
parameters={'query': 'Python'},
|
|
114
|
+
result={'results': [...]}
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Query tool calls
|
|
118
|
+
calls = await agent.tools.get_by_name('search', limit=10)
|
|
119
|
+
recent = await agent.tools.get_recent(since=1234567890)
|
|
120
|
+
|
|
121
|
+
# Get statistics
|
|
122
|
+
stats = await agent.tools.get_stats()
|
|
123
|
+
for stat in stats:
|
|
124
|
+
print(f"{stat.name}: {stat.successful}/{stat.total_calls} successful")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Configuration
|
|
128
|
+
|
|
129
|
+
### Using Agent ID
|
|
130
|
+
|
|
131
|
+
Creates a database at `.agentfs/{id}.db`:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
agent = await AgentFS.open(AgentFSOptions(id='my-agent'))
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Using Custom Path
|
|
138
|
+
|
|
139
|
+
Specify a custom database path:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
agent = await AgentFS.open(AgentFSOptions(path='./data/mydb.db'))
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Using Both
|
|
146
|
+
|
|
147
|
+
You can specify both for clarity:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
agent = await AgentFS.open(AgentFSOptions(id='my-agent', path='./data/mydb.db'))
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Context Manager Support
|
|
154
|
+
|
|
155
|
+
Use AgentFS with async context managers:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
async with await AgentFS.open(AgentFSOptions(id='my-agent')) as agent:
|
|
159
|
+
await agent.kv.set('key', 'value')
|
|
160
|
+
# Database is automatically closed when exiting the context
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Development
|
|
164
|
+
|
|
165
|
+
### Setup
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Install dependencies
|
|
169
|
+
uv sync --group dev
|
|
170
|
+
|
|
171
|
+
# Run tests
|
|
172
|
+
uv run pytest
|
|
173
|
+
|
|
174
|
+
# Format code
|
|
175
|
+
uv run ruff format agentfs_sdk tests
|
|
176
|
+
|
|
177
|
+
# Check code
|
|
178
|
+
uv run ruff check agentfs_sdk tests
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT License - see LICENSE file for details.
|
|
184
|
+
|
|
185
|
+
## Links
|
|
186
|
+
|
|
187
|
+
- [GitHub Repository](https://github.com/tursodatabase/agentfs)
|
|
188
|
+
- [TypeScript SDK](https://github.com/tursodatabase/agentfs/tree/main/sdk/typescript)
|
|
189
|
+
- [tursodb](https://github.com/tursodatabase/turso)
|
|
190
|
+
- [pyturso](https://pypi.org/project/pyturso/)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""AgentFS Python SDK
|
|
2
|
+
|
|
3
|
+
A filesystem and key-value store for AI agents, powered by SQLite.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .agentfs import AgentFS, AgentFSOptions
|
|
7
|
+
from .filesystem import Filesystem, Stats
|
|
8
|
+
from .kvstore import KvStore
|
|
9
|
+
from .toolcalls import ToolCall, ToolCalls, ToolCallStats
|
|
10
|
+
|
|
11
|
+
__version__ = "0.4.0-pre.5"
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"AgentFS",
|
|
15
|
+
"AgentFSOptions",
|
|
16
|
+
"KvStore",
|
|
17
|
+
"Filesystem",
|
|
18
|
+
"Stats",
|
|
19
|
+
"ToolCalls",
|
|
20
|
+
"ToolCall",
|
|
21
|
+
"ToolCallStats",
|
|
22
|
+
]
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Main AgentFS class"""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from turso.aio import Connection, connect
|
|
9
|
+
|
|
10
|
+
from .filesystem import Filesystem
|
|
11
|
+
from .kvstore import KvStore
|
|
12
|
+
from .toolcalls import ToolCalls
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class AgentFSOptions:
|
|
17
|
+
"""Configuration options for opening an AgentFS instance
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
id: Unique identifier for the agent.
|
|
21
|
+
- If provided without `path`: Creates storage at `.agentfs/{id}.db`
|
|
22
|
+
- If provided with `path`: Uses the specified path
|
|
23
|
+
path: Explicit path to the database file.
|
|
24
|
+
- If provided: Uses the specified path directly
|
|
25
|
+
- Can be combined with `id`
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
id: Optional[str] = None
|
|
29
|
+
path: Optional[str] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AgentFS:
|
|
33
|
+
"""AgentFS - A filesystem and key-value store for AI agents
|
|
34
|
+
|
|
35
|
+
Provides a unified interface for persistent storage using SQLite,
|
|
36
|
+
with support for key-value storage, filesystem operations, and
|
|
37
|
+
tool call tracking.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, db: Connection, kv: KvStore, fs: Filesystem, tools: ToolCalls):
|
|
41
|
+
"""Private constructor - use AgentFS.open() instead"""
|
|
42
|
+
self._db = db
|
|
43
|
+
self.kv = kv
|
|
44
|
+
self.fs = fs
|
|
45
|
+
self.tools = tools
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
async def open(options: AgentFSOptions) -> "AgentFS":
|
|
49
|
+
"""Open an agent filesystem
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
options: Configuration options (id and/or path required)
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Fully initialized AgentFS instance
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
ValueError: If neither id nor path is provided, or if id contains invalid characters
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
>>> # Using id (creates .agentfs/my-agent.db)
|
|
62
|
+
>>> agent = await AgentFS.open(AgentFSOptions(id='my-agent'))
|
|
63
|
+
>>>
|
|
64
|
+
>>> # Using id with custom path
|
|
65
|
+
>>> agent = await AgentFS.open(AgentFSOptions(id='my-agent', path='./data/mydb.db'))
|
|
66
|
+
>>>
|
|
67
|
+
>>> # Using path only
|
|
68
|
+
>>> agent = await AgentFS.open(AgentFSOptions(path='./data/mydb.db'))
|
|
69
|
+
"""
|
|
70
|
+
# Require at least id or path
|
|
71
|
+
if not options.id and not options.path:
|
|
72
|
+
raise ValueError("AgentFS.open() requires at least 'id' or 'path'.")
|
|
73
|
+
|
|
74
|
+
# Validate agent ID if provided
|
|
75
|
+
if options.id and not re.match(r"^[a-zA-Z0-9_-]+$", options.id):
|
|
76
|
+
raise ValueError(
|
|
77
|
+
"Agent ID must contain only alphanumeric characters, hyphens, and underscores"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Determine database path: explicit path takes precedence, otherwise use id-based path
|
|
81
|
+
if options.path:
|
|
82
|
+
db_path = options.path
|
|
83
|
+
else:
|
|
84
|
+
# id is guaranteed to be defined here (we checked not id and not path above)
|
|
85
|
+
directory = ".agentfs"
|
|
86
|
+
if not os.path.exists(directory):
|
|
87
|
+
os.makedirs(directory, exist_ok=True)
|
|
88
|
+
db_path = f"{directory}/{options.id}.db"
|
|
89
|
+
|
|
90
|
+
# Connect to the database to ensure it's created
|
|
91
|
+
db = await connect(db_path)
|
|
92
|
+
|
|
93
|
+
return await AgentFS.open_with(db)
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
async def open_with(db: Connection) -> "AgentFS":
|
|
97
|
+
"""Open an AgentFS instance with an existing database connection
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
db: An existing pyturso.aio Connection
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Fully initialized AgentFS instance
|
|
104
|
+
"""
|
|
105
|
+
# Initialize all components in parallel
|
|
106
|
+
kv = await KvStore.from_database(db)
|
|
107
|
+
fs = await Filesystem.from_database(db)
|
|
108
|
+
tools = await ToolCalls.from_database(db)
|
|
109
|
+
|
|
110
|
+
return AgentFS(db, kv, fs, tools)
|
|
111
|
+
|
|
112
|
+
def get_database(self) -> Connection:
|
|
113
|
+
"""Get the underlying Database connection"""
|
|
114
|
+
return self._db
|
|
115
|
+
|
|
116
|
+
async def close(self) -> None:
|
|
117
|
+
"""Close the database connection"""
|
|
118
|
+
await self._db.close()
|
|
119
|
+
|
|
120
|
+
async def __aenter__(self) -> "AgentFS":
|
|
121
|
+
"""Context manager entry"""
|
|
122
|
+
return self
|
|
123
|
+
|
|
124
|
+
async def __aexit__(self, exc_type, exc, tb) -> None:
|
|
125
|
+
"""Context manager exit"""
|
|
126
|
+
await self.close()
|