chuk-artifacts 0.3__py3-none-any.whl → 0.4.1__py3-none-any.whl
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.
- chuk_artifacts/__init__.py +5 -1
- chuk_artifacts/core.py +75 -58
- chuk_artifacts/grid.py +140 -7
- chuk_artifacts/metadata.py +1 -0
- chuk_artifacts/models.py +3 -3
- chuk_artifacts/providers/filesystem.py +23 -3
- chuk_artifacts/providers/ibm_cos.py +61 -59
- chuk_artifacts/providers/ibm_cos_iam.py +51 -7
- chuk_artifacts/providers/memory.py +32 -4
- chuk_artifacts/store.py +53 -4
- chuk_artifacts-0.4.1.dist-info/METADATA +730 -0
- chuk_artifacts-0.4.1.dist-info/RECORD +23 -0
- chuk_artifacts-0.3.dist-info/METADATA +0 -719
- chuk_artifacts-0.3.dist-info/RECORD +0 -23
- {chuk_artifacts-0.3.dist-info → chuk_artifacts-0.4.1.dist-info}/WHEEL +0 -0
- {chuk_artifacts-0.3.dist-info → chuk_artifacts-0.4.1.dist-info}/top_level.txt +0 -0
@@ -1,719 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: chuk-artifacts
|
3
|
-
Version: 0.3
|
4
|
-
Summary: Chuk Artifacts provides a production-ready, modular artifact storage system that works seamlessly across multiple storage backends (memory, filesystem, AWS S3, IBM Cloud Object Storage) with Redis or memory-based metadata caching and strict session-based security.
|
5
|
-
Requires-Python: >=3.11
|
6
|
-
Description-Content-Type: text/markdown
|
7
|
-
Requires-Dist: chuk-tool-processor>=0.4
|
8
|
-
Requires-Dist: pydantic>=2.10.6
|
9
|
-
Requires-Dist: pyyaml>=6.0.2
|
10
|
-
Requires-Dist: aioboto3>=14.3.0
|
11
|
-
Requires-Dist: redis>=6.2.0
|
12
|
-
Requires-Dist: ibm-cos-sdk>=2.13.5
|
13
|
-
Requires-Dist: chuk-sessions>=0.2
|
14
|
-
Provides-Extra: websocket
|
15
|
-
Requires-Dist: websockets>=10.0; extra == "websocket"
|
16
|
-
Provides-Extra: dev
|
17
|
-
Requires-Dist: pytest>=8.3.5; extra == "dev"
|
18
|
-
Requires-Dist: pytest-asyncio>=0.26.0; extra == "dev"
|
19
|
-
Requires-Dist: ruff>=0.4.6; extra == "dev"
|
20
|
-
|
21
|
-
# Chuk Artifacts
|
22
|
-
|
23
|
-
[](https://github.com/your-org/chuk-artifacts)
|
24
|
-
[](https://python.org)
|
25
|
-
[](LICENSE)
|
26
|
-
|
27
|
-
**Asynchronous, multi-backend artifact storage with mandatory session-based security and grid architecture**
|
28
|
-
|
29
|
-
Chuk Artifacts provides a production-ready, modular artifact storage system that works seamlessly across multiple storage backends (memory, filesystem, AWS S3, IBM Cloud Object Storage) with Redis or memory-based metadata caching and **strict session-based security**.
|
30
|
-
|
31
|
-
## ✨ Key Features
|
32
|
-
|
33
|
-
- 🏗️ **Modular Architecture**: 5 specialized operation modules for clean separation of concerns
|
34
|
-
- 🔒 **Mandatory Session Security**: Strict isolation with no anonymous artifacts or cross-session operations
|
35
|
-
- 🌐 **Grid Architecture**: `grid/{sandbox_id}/{session_id}/{artifact_id}` paths for federation-ready organization
|
36
|
-
- 🔄 **Multi-Backend Support**: Memory, filesystem, S3, IBM COS with seamless switching
|
37
|
-
- ⚡ **High Performance**: Built with async/await for high throughput (3,000+ ops/sec)
|
38
|
-
- 🔗 **Presigned URLs**: Secure, time-limited access without credential exposure
|
39
|
-
- 📊 **Batch Operations**: Efficient multi-file uploads and processing
|
40
|
-
- 🗃️ **Metadata Caching**: Fast lookups with Redis or memory-based sessions
|
41
|
-
- 📁 **Directory-Like Operations**: Organize files with path-based prefixes
|
42
|
-
- 🔧 **Zero Configuration**: Works out of the box with sensible defaults
|
43
|
-
- 🌍 **Production Ready**: Battle-tested with comprehensive error handling
|
44
|
-
|
45
|
-
## 🚀 Quick Start
|
46
|
-
|
47
|
-
### Installation
|
48
|
-
|
49
|
-
```bash
|
50
|
-
pip install chuk-artifacts
|
51
|
-
# or with uv
|
52
|
-
uv add chuk-artifacts
|
53
|
-
```
|
54
|
-
|
55
|
-
### Basic Usage
|
56
|
-
|
57
|
-
```python
|
58
|
-
from chuk_artifacts import ArtifactStore
|
59
|
-
|
60
|
-
# Zero-config setup (uses memory provider)
|
61
|
-
async with ArtifactStore() as store:
|
62
|
-
# Store an artifact (session auto-allocated)
|
63
|
-
artifact_id = await store.store(
|
64
|
-
data=b"Hello, world!",
|
65
|
-
mime="text/plain",
|
66
|
-
summary="A simple greeting",
|
67
|
-
filename="hello.txt"
|
68
|
-
# session_id auto-allocated if not provided
|
69
|
-
)
|
70
|
-
|
71
|
-
# Retrieve it
|
72
|
-
data = await store.retrieve(artifact_id)
|
73
|
-
print(data.decode()) # "Hello, world!"
|
74
|
-
|
75
|
-
# Generate a presigned URL
|
76
|
-
download_url = await store.presign_medium(artifact_id) # 1 hour
|
77
|
-
```
|
78
|
-
|
79
|
-
### Session-Based File Management
|
80
|
-
|
81
|
-
```python
|
82
|
-
async with ArtifactStore() as store:
|
83
|
-
# Create files in user sessions
|
84
|
-
doc_id = await store.write_file(
|
85
|
-
content="# User's Document\n\nPrivate content here.",
|
86
|
-
filename="docs/private.md",
|
87
|
-
mime="text/markdown",
|
88
|
-
session_id="user_alice"
|
89
|
-
)
|
90
|
-
|
91
|
-
# List files in a session
|
92
|
-
files = await store.list_by_session("user_alice")
|
93
|
-
print(f"Alice has {len(files)} files")
|
94
|
-
|
95
|
-
# List directory-like contents
|
96
|
-
docs = await store.get_directory_contents("user_alice", "docs/")
|
97
|
-
print(f"Alice's docs: {len(docs)} files")
|
98
|
-
|
99
|
-
# Copy within same session (allowed)
|
100
|
-
backup_id = await store.copy_file(
|
101
|
-
doc_id,
|
102
|
-
new_filename="docs/private_backup.md"
|
103
|
-
)
|
104
|
-
|
105
|
-
# Cross-session operations are BLOCKED for security
|
106
|
-
try:
|
107
|
-
await store.copy_file(
|
108
|
-
doc_id,
|
109
|
-
target_session_id="user_bob" # This will fail
|
110
|
-
)
|
111
|
-
except ArtifactStoreError:
|
112
|
-
print("✅ Cross-session operations blocked!")
|
113
|
-
```
|
114
|
-
|
115
|
-
### Configuration
|
116
|
-
|
117
|
-
```python
|
118
|
-
# Production setup with S3 and Redis
|
119
|
-
store = ArtifactStore(
|
120
|
-
storage_provider="s3",
|
121
|
-
session_provider="redis",
|
122
|
-
bucket="my-artifacts"
|
123
|
-
)
|
124
|
-
|
125
|
-
# Or use environment variables
|
126
|
-
# ARTIFACT_PROVIDER=s3
|
127
|
-
# SESSION_PROVIDER=redis
|
128
|
-
# AWS_ACCESS_KEY_ID=your_key
|
129
|
-
# AWS_SECRET_ACCESS_KEY=your_secret
|
130
|
-
# ARTIFACT_BUCKET=my-artifacts
|
131
|
-
|
132
|
-
store = ArtifactStore() # Auto-loads configuration
|
133
|
-
```
|
134
|
-
|
135
|
-
## 🏗️ Modular Architecture
|
136
|
-
|
137
|
-
Chuk Artifacts uses a clean modular architecture with specialized operation modules:
|
138
|
-
|
139
|
-
```
|
140
|
-
ArtifactStore (Main Coordinator)
|
141
|
-
├── CoreStorageOperations # store() and retrieve()
|
142
|
-
├── MetadataOperations # metadata, exists, delete, update, list operations
|
143
|
-
├── PresignedURLOperations # URL generation and upload workflows
|
144
|
-
├── BatchOperations # store_batch() for multiple files
|
145
|
-
└── AdminOperations # validate_configuration, get_stats
|
146
|
-
```
|
147
|
-
|
148
|
-
### Grid Architecture
|
149
|
-
|
150
|
-
All artifacts are organized using a consistent grid structure:
|
151
|
-
|
152
|
-
```
|
153
|
-
grid/{sandbox_id}/{session_id}/{artifact_id}
|
154
|
-
```
|
155
|
-
|
156
|
-
**Benefits:**
|
157
|
-
- **Federation Ready**: Cross-sandbox discovery and routing
|
158
|
-
- **Session Isolation**: Clear boundaries for security
|
159
|
-
- **Predictable Paths**: Easy to understand and manage
|
160
|
-
- **Scalable**: Handles multi-tenant applications
|
161
|
-
|
162
|
-
This design provides:
|
163
|
-
- **Better testability**: Each module can be tested independently
|
164
|
-
- **Enhanced maintainability**: Clear separation of concerns
|
165
|
-
- **Easy extensibility**: Add new operation types without touching core
|
166
|
-
- **Improved debugging**: Isolated functionality for easier troubleshooting
|
167
|
-
|
168
|
-
## 🔒 Session-Based Security
|
169
|
-
|
170
|
-
### Mandatory Sessions
|
171
|
-
```python
|
172
|
-
# Every artifact belongs to a session - no anonymous artifacts
|
173
|
-
artifact_id = await store.store(
|
174
|
-
data=b"content",
|
175
|
-
mime="text/plain",
|
176
|
-
summary="description"
|
177
|
-
# session_id auto-allocated if not provided
|
178
|
-
)
|
179
|
-
|
180
|
-
# Get the session it was allocated to
|
181
|
-
metadata = await store.metadata(artifact_id)
|
182
|
-
session_id = metadata["session_id"]
|
183
|
-
```
|
184
|
-
|
185
|
-
### Strict Session Isolation
|
186
|
-
```python
|
187
|
-
# Users can only access their own files
|
188
|
-
alice_files = await store.list_by_session("user_alice")
|
189
|
-
bob_files = await store.list_by_session("user_bob")
|
190
|
-
|
191
|
-
# Cross-session operations are blocked
|
192
|
-
await store.copy_file(alice_file_id, target_session_id="user_bob") # ❌ Blocked
|
193
|
-
await store.move_file(alice_file_id, new_session_id="user_bob") # ❌ Blocked
|
194
|
-
```
|
195
|
-
|
196
|
-
### Multi-Tenant Safe
|
197
|
-
```python
|
198
|
-
# Perfect for SaaS applications
|
199
|
-
company_a_files = await store.list_by_session("company_a")
|
200
|
-
company_b_files = await store.list_by_session("company_b")
|
201
|
-
|
202
|
-
# Companies cannot access each other's data
|
203
|
-
# Compliance-ready: GDPR, SOX, HIPAA
|
204
|
-
```
|
205
|
-
|
206
|
-
## 📦 Storage Providers
|
207
|
-
|
208
|
-
### Memory Provider
|
209
|
-
```python
|
210
|
-
store = ArtifactStore(storage_provider="memory")
|
211
|
-
```
|
212
|
-
- Perfect for development and testing
|
213
|
-
- Zero configuration required
|
214
|
-
- Non-persistent (data lost on restart)
|
215
|
-
- **Note**: Provider isolation limitations for testing
|
216
|
-
|
217
|
-
### Filesystem Provider
|
218
|
-
```python
|
219
|
-
store = ArtifactStore(storage_provider="filesystem")
|
220
|
-
# Set root directory
|
221
|
-
os.environ["ARTIFACT_FS_ROOT"] = "./my-artifacts"
|
222
|
-
```
|
223
|
-
- Local disk storage
|
224
|
-
- Persistent across restarts
|
225
|
-
- `file://` URLs for local access
|
226
|
-
- **Full session listing support**
|
227
|
-
- Great for development and staging
|
228
|
-
|
229
|
-
### AWS S3 Provider
|
230
|
-
```python
|
231
|
-
store = ArtifactStore(storage_provider="s3")
|
232
|
-
# Configure via environment
|
233
|
-
os.environ.update({
|
234
|
-
"AWS_ACCESS_KEY_ID": "your_key",
|
235
|
-
"AWS_SECRET_ACCESS_KEY": "your_secret",
|
236
|
-
"AWS_REGION": "us-east-1",
|
237
|
-
"ARTIFACT_BUCKET": "my-bucket"
|
238
|
-
})
|
239
|
-
```
|
240
|
-
- Industry-standard cloud storage
|
241
|
-
- Native presigned URL support
|
242
|
-
- Highly scalable and durable
|
243
|
-
- **Full session listing support**
|
244
|
-
- Perfect for production workloads
|
245
|
-
|
246
|
-
### IBM Cloud Object Storage
|
247
|
-
```python
|
248
|
-
# HMAC authentication
|
249
|
-
store = ArtifactStore(storage_provider="ibm_cos")
|
250
|
-
os.environ.update({
|
251
|
-
"AWS_ACCESS_KEY_ID": "your_hmac_key",
|
252
|
-
"AWS_SECRET_ACCESS_KEY": "your_hmac_secret",
|
253
|
-
"IBM_COS_ENDPOINT": "https://s3.us-south.cloud-object-storage.appdomain.cloud"
|
254
|
-
})
|
255
|
-
|
256
|
-
# IAM authentication
|
257
|
-
store = ArtifactStore(storage_provider="ibm_cos_iam")
|
258
|
-
os.environ.update({
|
259
|
-
"IBM_COS_APIKEY": "your_api_key",
|
260
|
-
"IBM_COS_INSTANCE_CRN": "crn:v1:bluemix:public:cloud-object-storage:..."
|
261
|
-
})
|
262
|
-
```
|
263
|
-
|
264
|
-
## 🗃️ Session Providers
|
265
|
-
|
266
|
-
### Memory Sessions
|
267
|
-
```python
|
268
|
-
store = ArtifactStore(session_provider="memory")
|
269
|
-
```
|
270
|
-
- In-memory metadata storage
|
271
|
-
- Fast but non-persistent
|
272
|
-
- Perfect for testing
|
273
|
-
|
274
|
-
### Redis Sessions
|
275
|
-
```python
|
276
|
-
store = ArtifactStore(session_provider="redis")
|
277
|
-
os.environ["SESSION_REDIS_URL"] = "redis://localhost:6379/0"
|
278
|
-
```
|
279
|
-
- Persistent metadata storage
|
280
|
-
- Shared across multiple instances
|
281
|
-
- Production-ready caching
|
282
|
-
|
283
|
-
## 🎯 Common Use Cases
|
284
|
-
|
285
|
-
### MCP Server Integration
|
286
|
-
|
287
|
-
```python
|
288
|
-
from chuk_artifacts import ArtifactStore
|
289
|
-
|
290
|
-
# Initialize for MCP server
|
291
|
-
store = ArtifactStore(
|
292
|
-
storage_provider="filesystem", # or "s3" for production
|
293
|
-
session_provider="redis"
|
294
|
-
)
|
295
|
-
|
296
|
-
# MCP tool: Upload file
|
297
|
-
async def upload_file(data_base64: str, filename: str, mime: str, session_id: str):
|
298
|
-
data = base64.b64decode(data_base64)
|
299
|
-
artifact_id = await store.store(
|
300
|
-
data=data,
|
301
|
-
mime=mime,
|
302
|
-
summary=f"Uploaded: {filename}",
|
303
|
-
filename=filename,
|
304
|
-
session_id=session_id # Session isolation
|
305
|
-
)
|
306
|
-
return {"artifact_id": artifact_id}
|
307
|
-
|
308
|
-
# MCP tool: List session files
|
309
|
-
async def list_session_files(session_id: str, prefix: str = ""):
|
310
|
-
files = await store.get_directory_contents(session_id, prefix)
|
311
|
-
return {"files": files}
|
312
|
-
|
313
|
-
# MCP tool: Copy file (within session only)
|
314
|
-
async def copy_file(artifact_id: str, new_filename: str):
|
315
|
-
new_id = await store.copy_file(artifact_id, new_filename=new_filename)
|
316
|
-
return {"new_artifact_id": new_id}
|
317
|
-
```
|
318
|
-
|
319
|
-
### Web Framework Integration
|
320
|
-
|
321
|
-
```python
|
322
|
-
from chuk_artifacts import ArtifactStore
|
323
|
-
|
324
|
-
# Initialize once at startup
|
325
|
-
store = ArtifactStore(
|
326
|
-
storage_provider="s3",
|
327
|
-
session_provider="redis"
|
328
|
-
)
|
329
|
-
|
330
|
-
async def upload_file(file_content: bytes, filename: str, content_type: str, user_id: str):
|
331
|
-
"""Handle file upload in FastAPI/Flask with user isolation"""
|
332
|
-
artifact_id = await store.store(
|
333
|
-
data=file_content,
|
334
|
-
mime=content_type,
|
335
|
-
summary=f"Uploaded: {filename}",
|
336
|
-
filename=filename,
|
337
|
-
session_id=f"user_{user_id}" # User-specific session
|
338
|
-
)
|
339
|
-
|
340
|
-
# Return download URL
|
341
|
-
download_url = await store.presign_medium(artifact_id)
|
342
|
-
return {
|
343
|
-
"artifact_id": artifact_id,
|
344
|
-
"download_url": download_url
|
345
|
-
}
|
346
|
-
|
347
|
-
async def list_user_files(user_id: str, directory: str = ""):
|
348
|
-
"""List files for a specific user"""
|
349
|
-
return await store.get_directory_contents(f"user_{user_id}", directory)
|
350
|
-
```
|
351
|
-
|
352
|
-
### Advanced File Operations
|
353
|
-
|
354
|
-
```python
|
355
|
-
# Read file content directly
|
356
|
-
content = await store.read_file(artifact_id, as_text=True)
|
357
|
-
print(f"File content: {content}")
|
358
|
-
|
359
|
-
# Write file with content
|
360
|
-
new_id = await store.write_file(
|
361
|
-
content="# New Document\n\nThis is a new file.",
|
362
|
-
filename="documents/new_doc.md",
|
363
|
-
mime="text/markdown",
|
364
|
-
session_id="user_123"
|
365
|
-
)
|
366
|
-
|
367
|
-
# Move/rename file within session
|
368
|
-
await store.move_file(
|
369
|
-
artifact_id,
|
370
|
-
new_filename="documents/renamed_doc.md"
|
371
|
-
)
|
372
|
-
|
373
|
-
# Update metadata
|
374
|
-
await store.update_metadata(
|
375
|
-
artifact_id,
|
376
|
-
summary="Updated summary",
|
377
|
-
meta={"version": 2, "updated_by": "user_123"}
|
378
|
-
)
|
379
|
-
|
380
|
-
# Extend TTL
|
381
|
-
await store.extend_ttl(artifact_id, additional_seconds=3600)
|
382
|
-
```
|
383
|
-
|
384
|
-
### Batch Processing
|
385
|
-
|
386
|
-
```python
|
387
|
-
# Prepare multiple files
|
388
|
-
items = [
|
389
|
-
{
|
390
|
-
"data": file1_content,
|
391
|
-
"mime": "image/png",
|
392
|
-
"summary": "Product image 1",
|
393
|
-
"filename": "images/product1.png"
|
394
|
-
},
|
395
|
-
{
|
396
|
-
"data": file2_content,
|
397
|
-
"mime": "image/png",
|
398
|
-
"summary": "Product image 2",
|
399
|
-
"filename": "images/product2.png"
|
400
|
-
}
|
401
|
-
]
|
402
|
-
|
403
|
-
# Store all at once with session isolation
|
404
|
-
artifact_ids = await store.store_batch(items, session_id="product-catalog")
|
405
|
-
```
|
406
|
-
|
407
|
-
## 🧪 Testing
|
408
|
-
|
409
|
-
### Run All Tests
|
410
|
-
```bash
|
411
|
-
# MCP server scenarios (recommended)
|
412
|
-
uv run examples/mcp_test_demo.py
|
413
|
-
|
414
|
-
# Session security testing
|
415
|
-
uv run examples/session_operations_demo.py
|
416
|
-
|
417
|
-
# Grid architecture demo
|
418
|
-
uv run examples/grid_demo.py
|
419
|
-
|
420
|
-
# Complete verification
|
421
|
-
uv run examples/complete_verification.py
|
422
|
-
```
|
423
|
-
|
424
|
-
### Test Results
|
425
|
-
Recent test results show excellent performance:
|
426
|
-
```
|
427
|
-
📤 Test 1: Rapid file creation...
|
428
|
-
✅ Created 20 files in 0.006s (3,083 files/sec)
|
429
|
-
|
430
|
-
📋 Test 2: Session listing performance...
|
431
|
-
✅ Listed 20 files in 0.002s
|
432
|
-
|
433
|
-
📁 Test 3: Directory operations...
|
434
|
-
✅ Listed uploads/ directory (20 files) in 0.002s
|
435
|
-
|
436
|
-
📖 Test 4: Batch read operations...
|
437
|
-
✅ Read 10 files in 0.002s (4,693 reads/sec)
|
438
|
-
|
439
|
-
📋 Test 5: Copy operations...
|
440
|
-
✅ Copied 5 files in 0.003s (1,811 copies/sec)
|
441
|
-
```
|
442
|
-
|
443
|
-
### Development Setup
|
444
|
-
```python
|
445
|
-
from chuk_artifacts.config import development_setup
|
446
|
-
|
447
|
-
store = development_setup() # Uses memory providers
|
448
|
-
```
|
449
|
-
|
450
|
-
### Testing Setup
|
451
|
-
```python
|
452
|
-
from chuk_artifacts.config import testing_setup
|
453
|
-
|
454
|
-
store = testing_setup("./test-artifacts") # Uses filesystem
|
455
|
-
```
|
456
|
-
|
457
|
-
## 🔧 Configuration
|
458
|
-
|
459
|
-
### Environment Variables
|
460
|
-
|
461
|
-
```bash
|
462
|
-
# Storage configuration
|
463
|
-
ARTIFACT_PROVIDER=s3 # memory, filesystem, s3, ibm_cos, ibm_cos_iam
|
464
|
-
ARTIFACT_BUCKET=my-artifacts # Bucket/container name
|
465
|
-
ARTIFACT_FS_ROOT=./artifacts # Filesystem root (filesystem provider)
|
466
|
-
ARTIFACT_SANDBOX_ID=my-app # Sandbox identifier for multi-tenancy
|
467
|
-
|
468
|
-
# Session configuration
|
469
|
-
SESSION_PROVIDER=redis # memory, redis
|
470
|
-
SESSION_REDIS_URL=redis://localhost:6379/0
|
471
|
-
|
472
|
-
# AWS/S3 configuration
|
473
|
-
AWS_ACCESS_KEY_ID=your_key
|
474
|
-
AWS_SECRET_ACCESS_KEY=your_secret
|
475
|
-
AWS_REGION=us-east-1
|
476
|
-
S3_ENDPOINT_URL=https://custom-s3.com # Optional: custom S3 endpoint
|
477
|
-
|
478
|
-
# IBM COS configuration
|
479
|
-
IBM_COS_ENDPOINT=https://s3.us-south.cloud-object-storage.appdomain.cloud
|
480
|
-
IBM_COS_APIKEY=your_api_key # For IAM auth
|
481
|
-
IBM_COS_INSTANCE_CRN=crn:v1:... # For IAM auth
|
482
|
-
```
|
483
|
-
|
484
|
-
### Programmatic Configuration
|
485
|
-
|
486
|
-
```python
|
487
|
-
from chuk_artifacts.config import configure_s3, configure_redis_session
|
488
|
-
|
489
|
-
# Configure S3 storage
|
490
|
-
configure_s3(
|
491
|
-
access_key="AKIA...",
|
492
|
-
secret_key="...",
|
493
|
-
bucket="prod-artifacts",
|
494
|
-
region="us-west-2"
|
495
|
-
)
|
496
|
-
|
497
|
-
# Configure Redis sessions
|
498
|
-
configure_redis_session("redis://prod-redis:6379/1")
|
499
|
-
|
500
|
-
# Create store with this configuration
|
501
|
-
store = ArtifactStore()
|
502
|
-
```
|
503
|
-
|
504
|
-
## 🚀 Performance
|
505
|
-
|
506
|
-
- **High Throughput**: 3,000+ file operations per second
|
507
|
-
- **Async/Await**: Non-blocking I/O for high concurrency
|
508
|
-
- **Connection Pooling**: Efficient resource usage with aioboto3
|
509
|
-
- **Metadata Caching**: Sub-millisecond lookups with Redis
|
510
|
-
- **Batch Operations**: Reduced overhead for multiple files
|
511
|
-
- **Grid Architecture**: Optimized session-based queries
|
512
|
-
|
513
|
-
### Performance Benchmarks
|
514
|
-
```
|
515
|
-
✅ File Creation: 3,083 files/sec
|
516
|
-
✅ File Reading: 4,693 reads/sec
|
517
|
-
✅ File Copying: 1,811 copies/sec
|
518
|
-
✅ Session Listing: ~0.002s for 20+ files
|
519
|
-
✅ Directory Listing: ~0.002s for filtered results
|
520
|
-
```
|
521
|
-
|
522
|
-
## 🔒 Security
|
523
|
-
|
524
|
-
- **Mandatory Sessions**: No anonymous artifacts allowed
|
525
|
-
- **Session Isolation**: Strict boundaries prevent cross-session access
|
526
|
-
- **No Cross-Session Operations**: Copy, move, overwrite blocked across sessions
|
527
|
-
- **Grid Architecture**: Clear audit trail in paths
|
528
|
-
- **Presigned URLs**: Time-limited access without credential sharing
|
529
|
-
- **Secure Defaults**: Conservative TTL and expiration settings
|
530
|
-
- **Credential Isolation**: Environment-based configuration
|
531
|
-
- **Error Handling**: No sensitive data in logs or exceptions
|
532
|
-
|
533
|
-
### Security Validation
|
534
|
-
```python
|
535
|
-
# All these operations are blocked for security
|
536
|
-
await store.copy_file(user_a_file, target_session_id="user_b") # ❌ Blocked
|
537
|
-
await store.move_file(user_a_file, new_session_id="user_b") # ❌ Blocked
|
538
|
-
|
539
|
-
# Security test results:
|
540
|
-
# ✅ Cross-session copy correctly blocked
|
541
|
-
# ✅ Cross-session move correctly blocked
|
542
|
-
# ✅ Cross-session overwrite correctly blocked
|
543
|
-
# 🛡️ ALL SECURITY TESTS PASSED!
|
544
|
-
```
|
545
|
-
|
546
|
-
## 📝 API Reference
|
547
|
-
|
548
|
-
### Core Methods
|
549
|
-
|
550
|
-
#### `store(data, *, mime, summary, meta=None, filename=None, session_id=None, user_id=None, ttl=900)`
|
551
|
-
Store artifact data with metadata. Session auto-allocated if not provided.
|
552
|
-
|
553
|
-
#### `retrieve(artifact_id)`
|
554
|
-
Retrieve artifact data by ID.
|
555
|
-
|
556
|
-
#### `metadata(artifact_id)`
|
557
|
-
Get artifact metadata.
|
558
|
-
|
559
|
-
#### `exists(artifact_id)` / `delete(artifact_id)`
|
560
|
-
Check existence or delete artifacts.
|
561
|
-
|
562
|
-
### Session Operations
|
563
|
-
|
564
|
-
#### `create_session(user_id=None, ttl_hours=None)`
|
565
|
-
Create a new session explicitly.
|
566
|
-
|
567
|
-
#### `validate_session(session_id)` / `get_session_info(session_id)`
|
568
|
-
Session validation and information retrieval.
|
569
|
-
|
570
|
-
#### `list_by_session(session_id, limit=100)`
|
571
|
-
List all artifacts in a session.
|
572
|
-
|
573
|
-
#### `get_directory_contents(session_id, directory_prefix="", limit=100)`
|
574
|
-
Get files in a directory-like structure.
|
575
|
-
|
576
|
-
### File Operations
|
577
|
-
|
578
|
-
#### `write_file(content, *, filename, mime="text/plain", session_id=None, ...)`
|
579
|
-
Write content to new file.
|
580
|
-
|
581
|
-
#### `read_file(artifact_id, *, encoding="utf-8", as_text=True)`
|
582
|
-
Read file content directly as text or binary.
|
583
|
-
|
584
|
-
#### `copy_file(artifact_id, *, new_filename=None, new_meta=None, summary=None)`
|
585
|
-
Copy file within same session only (cross-session blocked).
|
586
|
-
|
587
|
-
#### `move_file(artifact_id, *, new_filename=None, new_meta=None)`
|
588
|
-
Move/rename file within same session only (cross-session blocked).
|
589
|
-
|
590
|
-
#### `list_files(session_id, prefix="", limit=100)`
|
591
|
-
List files with optional prefix filtering.
|
592
|
-
|
593
|
-
#### `update_file(artifact_id, *, data=None, meta=None, filename=None, summary=None, mime=None)`
|
594
|
-
Update artifact content, metadata, filename, summary, or MIME type. At least one field must be specified for update.
|
595
|
-
|
596
|
-
### Metadata Operations
|
597
|
-
|
598
|
-
#### `update_metadata(artifact_id, *, summary=None, meta=None, merge=True, **kwargs)`
|
599
|
-
Update artifact metadata.
|
600
|
-
|
601
|
-
#### `extend_ttl(artifact_id, additional_seconds)`
|
602
|
-
Extend artifact TTL.
|
603
|
-
|
604
|
-
### Presigned URLs
|
605
|
-
|
606
|
-
#### `presign(artifact_id, expires=3600)`
|
607
|
-
Generate presigned URL for download.
|
608
|
-
|
609
|
-
#### `presign_short(artifact_id)` / `presign_medium(artifact_id)` / `presign_long(artifact_id)`
|
610
|
-
Generate URLs with predefined durations (15min/1hr/24hr).
|
611
|
-
|
612
|
-
#### `presign_upload(session_id=None, filename=None, mime_type="application/octet-stream", expires=3600)`
|
613
|
-
Generate presigned URL for upload.
|
614
|
-
|
615
|
-
#### `register_uploaded_artifact(artifact_id, *, mime, summary, ...)`
|
616
|
-
Register metadata for presigned uploads.
|
617
|
-
|
618
|
-
### Batch Operations
|
619
|
-
|
620
|
-
#### `store_batch(items, session_id=None, ttl=900)`
|
621
|
-
Store multiple artifacts efficiently.
|
622
|
-
|
623
|
-
### Admin Operations
|
624
|
-
|
625
|
-
#### `validate_configuration()`
|
626
|
-
Validate storage and session provider connectivity.
|
627
|
-
|
628
|
-
#### `get_stats()`
|
629
|
-
Get storage statistics and configuration info.
|
630
|
-
|
631
|
-
### Grid Operations
|
632
|
-
|
633
|
-
#### `get_canonical_prefix(session_id)`
|
634
|
-
Get grid path prefix for session.
|
635
|
-
|
636
|
-
#### `generate_artifact_key(session_id, artifact_id)`
|
637
|
-
Generate grid artifact key.
|
638
|
-
|
639
|
-
## 🛠️ Advanced Features
|
640
|
-
|
641
|
-
### Error Handling
|
642
|
-
```python
|
643
|
-
from chuk_artifacts import (
|
644
|
-
ArtifactNotFoundError,
|
645
|
-
ArtifactExpiredError,
|
646
|
-
ProviderError,
|
647
|
-
SessionError,
|
648
|
-
ArtifactStoreError # For session security violations
|
649
|
-
)
|
650
|
-
|
651
|
-
try:
|
652
|
-
await store.copy_file(artifact_id, target_session_id="other_session")
|
653
|
-
except ArtifactStoreError as e:
|
654
|
-
print(f"Security violation: {e}")
|
655
|
-
except ArtifactNotFoundError:
|
656
|
-
print("Artifact not found or expired")
|
657
|
-
except ProviderError as e:
|
658
|
-
print(f"Storage provider error: {e}")
|
659
|
-
```
|
660
|
-
|
661
|
-
### Validation and Monitoring
|
662
|
-
```python
|
663
|
-
# Validate configuration
|
664
|
-
config_status = await store.validate_configuration()
|
665
|
-
print(f"Storage: {config_status['storage']['status']}")
|
666
|
-
print(f"Session: {config_status['session']['status']}")
|
667
|
-
|
668
|
-
# Get statistics
|
669
|
-
stats = await store.get_stats()
|
670
|
-
print(f"Provider: {stats['storage_provider']}")
|
671
|
-
print(f"Bucket: {stats['bucket']}")
|
672
|
-
print(f"Sandbox: {stats['sandbox_id']}")
|
673
|
-
```
|
674
|
-
|
675
|
-
### Context Manager Usage
|
676
|
-
```python
|
677
|
-
async with ArtifactStore() as store:
|
678
|
-
artifact_id = await store.store(
|
679
|
-
data=b"Temporary data",
|
680
|
-
mime="text/plain",
|
681
|
-
summary="Auto-cleanup example"
|
682
|
-
)
|
683
|
-
# Store automatically closed on exit
|
684
|
-
```
|
685
|
-
|
686
|
-
## 🤝 Contributing
|
687
|
-
|
688
|
-
1. Fork the repository
|
689
|
-
2. Create a feature branch: `git checkout -b feature-name`
|
690
|
-
3. Make your changes
|
691
|
-
4. Run tests: `uv run examples/mcp_test_demo.py`
|
692
|
-
5. Test session operations: `uv run examples/session_operations_demo.py`
|
693
|
-
6. Submit a pull request
|
694
|
-
|
695
|
-
## 📄 License
|
696
|
-
|
697
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
698
|
-
|
699
|
-
## 🎯 Roadmap
|
700
|
-
|
701
|
-
- [x] **Session-based security** with strict isolation
|
702
|
-
- [x] **Grid architecture** with federation-ready paths
|
703
|
-
- [x] **Modular design** with specialized operation modules
|
704
|
-
- [x] **High-performance operations** (3,000+ ops/sec)
|
705
|
-
- [x] **Directory-like operations** with prefix filtering
|
706
|
-
- [x] **Comprehensive testing** with real-world scenarios
|
707
|
-
- [ ] Azure Blob Storage provider
|
708
|
-
- [ ] Google Cloud Storage provider
|
709
|
-
- [ ] Encryption at rest
|
710
|
-
- [ ] Artifact versioning
|
711
|
-
- [ ] Webhook notifications
|
712
|
-
- [ ] Prometheus metrics export
|
713
|
-
- [ ] Federation implementation
|
714
|
-
|
715
|
-
---
|
716
|
-
|
717
|
-
**Made with ❤️ for secure, scalable artifact storage**
|
718
|
-
|
719
|
-
*Production-ready artifact storage with mandatory session security and grid architecture*
|