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.
@@ -0,0 +1,5 @@
1
+ include README.md
2
+ include LICENSE
3
+ recursive-include agentfs_sdk *.py
4
+ recursive-exclude * __pycache__
5
+ recursive-exclude * *.py[co]
@@ -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()