hebbrix 2.0.0__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.
- hebbrix/__init__.py +69 -0
- hebbrix/chat.py +349 -0
- hebbrix/client.py +226 -0
- hebbrix/exceptions.py +48 -0
- hebbrix/resources.py +978 -0
- hebbrix-2.0.0.dist-info/METADATA +125 -0
- hebbrix-2.0.0.dist-info/RECORD +9 -0
- hebbrix-2.0.0.dist-info/WHEEL +5 -0
- hebbrix-2.0.0.dist-info/top_level.txt +1 -0
hebbrix/resources.py
ADDED
|
@@ -0,0 +1,978 @@
|
|
|
1
|
+
"""
|
|
2
|
+
API Resource classes
|
|
3
|
+
|
|
4
|
+
Each resource class wraps a specific set of API endpoints.
|
|
5
|
+
"""
|
|
6
|
+
from typing import Optional, Dict, Any, List, TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from hebbrix.client import MemoryClient
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseResource:
|
|
13
|
+
"""Base class for API resources."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, client: "MemoryClient"):
|
|
16
|
+
self.client = client
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AuthResource(BaseResource):
|
|
20
|
+
"""Authentication endpoints."""
|
|
21
|
+
|
|
22
|
+
async def register(
|
|
23
|
+
self,
|
|
24
|
+
email: str,
|
|
25
|
+
password: str,
|
|
26
|
+
full_name: str,
|
|
27
|
+
) -> Dict[str, Any]:
|
|
28
|
+
"""
|
|
29
|
+
Register a new user.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
email: User email
|
|
33
|
+
password: User password
|
|
34
|
+
full_name: User's full name
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Authentication response with access token
|
|
38
|
+
"""
|
|
39
|
+
return await self.client.post(
|
|
40
|
+
"/v1/auth/register",
|
|
41
|
+
json={
|
|
42
|
+
"email": email,
|
|
43
|
+
"password": password,
|
|
44
|
+
"full_name": full_name,
|
|
45
|
+
},
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
async def login(self, email: str, password: str) -> Dict[str, Any]:
|
|
49
|
+
"""
|
|
50
|
+
Login with email and password.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
email: User email
|
|
54
|
+
password: User password
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Authentication response with access token
|
|
58
|
+
"""
|
|
59
|
+
return await self.client.post(
|
|
60
|
+
"/v1/auth/login",
|
|
61
|
+
json={"email": email, "password": password},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
async def create_api_key(self, name: str) -> Dict[str, Any]:
|
|
65
|
+
"""
|
|
66
|
+
Create a new API key.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
name: API key name
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
API key data (key is only shown once)
|
|
73
|
+
"""
|
|
74
|
+
return await self.client.post(
|
|
75
|
+
"/v1/auth/api-keys",
|
|
76
|
+
json={"name": name},
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
async def get_me(self) -> Dict[str, Any]:
|
|
80
|
+
"""
|
|
81
|
+
Get current user information.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
User data
|
|
85
|
+
"""
|
|
86
|
+
return await self.client.get("/v1/auth/me")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class CollectionsResource(BaseResource):
|
|
90
|
+
"""Collection management endpoints."""
|
|
91
|
+
|
|
92
|
+
async def create(
|
|
93
|
+
self,
|
|
94
|
+
name: str,
|
|
95
|
+
description: Optional[str] = None,
|
|
96
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
97
|
+
) -> Dict[str, Any]:
|
|
98
|
+
"""
|
|
99
|
+
Create a new collection.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
name: Collection name
|
|
103
|
+
description: Optional description
|
|
104
|
+
metadata: Optional metadata
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Created collection
|
|
108
|
+
"""
|
|
109
|
+
return await self.client.post(
|
|
110
|
+
"/v1/collections",
|
|
111
|
+
json={
|
|
112
|
+
"name": name,
|
|
113
|
+
"description": description,
|
|
114
|
+
"metadata": metadata or {},
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
async def list(
|
|
119
|
+
self,
|
|
120
|
+
skip: int = 0,
|
|
121
|
+
limit: int = 100,
|
|
122
|
+
) -> List[Dict[str, Any]]:
|
|
123
|
+
"""
|
|
124
|
+
List all collections.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
skip: Number of items to skip
|
|
128
|
+
limit: Maximum number of items
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
List of collections
|
|
132
|
+
"""
|
|
133
|
+
return await self.client.get(
|
|
134
|
+
"/v1/collections",
|
|
135
|
+
params={"skip": skip, "limit": limit},
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
async def get(self, collection_id: str) -> Dict[str, Any]:
|
|
139
|
+
"""
|
|
140
|
+
Get a specific collection.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
collection_id: Collection ID
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Collection data
|
|
147
|
+
"""
|
|
148
|
+
return await self.client.get(f"/v1/collections/{collection_id}")
|
|
149
|
+
|
|
150
|
+
async def update(
|
|
151
|
+
self,
|
|
152
|
+
collection_id: str,
|
|
153
|
+
name: Optional[str] = None,
|
|
154
|
+
description: Optional[str] = None,
|
|
155
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
156
|
+
) -> Dict[str, Any]:
|
|
157
|
+
"""
|
|
158
|
+
Update a collection.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
collection_id: Collection ID
|
|
162
|
+
name: New name
|
|
163
|
+
description: New description
|
|
164
|
+
metadata: New metadata
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Updated collection
|
|
168
|
+
"""
|
|
169
|
+
data = {}
|
|
170
|
+
if name is not None:
|
|
171
|
+
data["name"] = name
|
|
172
|
+
if description is not None:
|
|
173
|
+
data["description"] = description
|
|
174
|
+
if metadata is not None:
|
|
175
|
+
data["metadata"] = metadata
|
|
176
|
+
|
|
177
|
+
return await self.client.patch(
|
|
178
|
+
f"/v1/collections/{collection_id}",
|
|
179
|
+
json=data,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
async def delete(self, collection_id: str) -> None:
|
|
183
|
+
"""
|
|
184
|
+
Delete a collection.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
collection_id: Collection ID
|
|
188
|
+
"""
|
|
189
|
+
await self.client.delete(f"/v1/collections/{collection_id}")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class MemoriesResource(BaseResource):
|
|
193
|
+
"""Memory management endpoints."""
|
|
194
|
+
|
|
195
|
+
async def create(
|
|
196
|
+
self,
|
|
197
|
+
collection_id: str,
|
|
198
|
+
content: str,
|
|
199
|
+
importance: float = 0.5,
|
|
200
|
+
source_type: str = "text",
|
|
201
|
+
source_reference: Optional[str] = None,
|
|
202
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
203
|
+
) -> Dict[str, Any]:
|
|
204
|
+
"""
|
|
205
|
+
Create a new memory.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
collection_id: Collection ID
|
|
209
|
+
content: Memory content
|
|
210
|
+
importance: Importance score (0-1)
|
|
211
|
+
source_type: Type of source
|
|
212
|
+
source_reference: Reference to source
|
|
213
|
+
metadata: Optional metadata
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Created memory
|
|
217
|
+
"""
|
|
218
|
+
return await self.client.post(
|
|
219
|
+
"/v1/memories",
|
|
220
|
+
json={
|
|
221
|
+
"collection_id": collection_id,
|
|
222
|
+
"content": content,
|
|
223
|
+
"importance": importance,
|
|
224
|
+
"source_type": source_type,
|
|
225
|
+
"source_reference": source_reference,
|
|
226
|
+
"metadata": metadata or {},
|
|
227
|
+
},
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
async def list(
|
|
231
|
+
self,
|
|
232
|
+
collection_id: Optional[str] = None,
|
|
233
|
+
skip: int = 0,
|
|
234
|
+
limit: int = 100,
|
|
235
|
+
) -> List[Dict[str, Any]]:
|
|
236
|
+
"""
|
|
237
|
+
List memories.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
collection_id: Optional collection filter
|
|
241
|
+
skip: Number of items to skip
|
|
242
|
+
limit: Maximum number of items
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
List of memories
|
|
246
|
+
"""
|
|
247
|
+
params = {"skip": skip, "limit": limit}
|
|
248
|
+
if collection_id:
|
|
249
|
+
params["collection_id"] = collection_id
|
|
250
|
+
|
|
251
|
+
return await self.client.get("/v1/memories", params=params)
|
|
252
|
+
|
|
253
|
+
async def get(self, memory_id: str) -> Dict[str, Any]:
|
|
254
|
+
"""
|
|
255
|
+
Get a specific memory.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
memory_id: Memory ID
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Memory data with metadata
|
|
262
|
+
"""
|
|
263
|
+
return await self.client.get(f"/v1/memories/{memory_id}")
|
|
264
|
+
|
|
265
|
+
async def update(
|
|
266
|
+
self,
|
|
267
|
+
memory_id: str,
|
|
268
|
+
content: Optional[str] = None,
|
|
269
|
+
importance: Optional[float] = None,
|
|
270
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
271
|
+
) -> Dict[str, Any]:
|
|
272
|
+
"""
|
|
273
|
+
Update a memory.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
memory_id: Memory ID
|
|
277
|
+
content: New content
|
|
278
|
+
importance: New importance
|
|
279
|
+
metadata: New metadata
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
Updated memory
|
|
283
|
+
"""
|
|
284
|
+
data = {}
|
|
285
|
+
if content is not None:
|
|
286
|
+
data["content"] = content
|
|
287
|
+
if importance is not None:
|
|
288
|
+
data["importance"] = importance
|
|
289
|
+
if metadata is not None:
|
|
290
|
+
data["metadata"] = metadata
|
|
291
|
+
|
|
292
|
+
return await self.client.patch(f"/v1/memories/{memory_id}", json=data)
|
|
293
|
+
|
|
294
|
+
async def delete(self, memory_id: str) -> None:
|
|
295
|
+
"""
|
|
296
|
+
Delete a memory.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
memory_id: Memory ID
|
|
300
|
+
"""
|
|
301
|
+
await self.client.delete(f"/v1/memories/{memory_id}")
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class SearchResource(BaseResource):
|
|
305
|
+
"""Search and reasoning endpoints."""
|
|
306
|
+
|
|
307
|
+
async def search(
|
|
308
|
+
self,
|
|
309
|
+
query: str,
|
|
310
|
+
collection_id: Optional[str] = None,
|
|
311
|
+
limit: int = 10,
|
|
312
|
+
search_type: str = "hybrid",
|
|
313
|
+
filters: Optional[Dict[str, Any]] = None,
|
|
314
|
+
) -> List[Dict[str, Any]]:
|
|
315
|
+
"""
|
|
316
|
+
Search memories.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
query: Search query
|
|
320
|
+
collection_id: Optional collection filter
|
|
321
|
+
limit: Number of results
|
|
322
|
+
search_type: Type of search (hybrid, vector, bm25, graph)
|
|
323
|
+
filters: Additional filters
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
Search results
|
|
327
|
+
"""
|
|
328
|
+
response = await self.client.post(
|
|
329
|
+
"/v1/search",
|
|
330
|
+
json={
|
|
331
|
+
"query": query,
|
|
332
|
+
"collection_id": collection_id,
|
|
333
|
+
"limit": limit,
|
|
334
|
+
"search_type": search_type,
|
|
335
|
+
"filters": filters or {},
|
|
336
|
+
},
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
return response.get("results", [])
|
|
340
|
+
|
|
341
|
+
async def similar(
|
|
342
|
+
self,
|
|
343
|
+
memory_id: str,
|
|
344
|
+
limit: int = 10,
|
|
345
|
+
) -> List[Dict[str, Any]]:
|
|
346
|
+
"""
|
|
347
|
+
Find similar memories.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
memory_id: Memory ID
|
|
351
|
+
limit: Number of results
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
Similar memories
|
|
355
|
+
"""
|
|
356
|
+
response = await self.client.get(
|
|
357
|
+
f"/v1/search/similar/{memory_id}",
|
|
358
|
+
params={"limit": limit},
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
return response.get("results", [])
|
|
362
|
+
|
|
363
|
+
async def reason(
|
|
364
|
+
self,
|
|
365
|
+
query: str,
|
|
366
|
+
collection_id: Optional[str] = None,
|
|
367
|
+
provider: Optional[str] = None,
|
|
368
|
+
include_steps: bool = False,
|
|
369
|
+
) -> Dict[str, Any]:
|
|
370
|
+
"""
|
|
371
|
+
Perform reasoning over memories.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
query: Question or query
|
|
375
|
+
collection_id: Optional collection filter
|
|
376
|
+
provider: LLM provider (gemini, openai, anthropic)
|
|
377
|
+
include_steps: Include reasoning steps
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
Reasoning result with answer and sources
|
|
381
|
+
"""
|
|
382
|
+
return await self.client.post(
|
|
383
|
+
"/v1/search/reason",
|
|
384
|
+
json={
|
|
385
|
+
"query": query,
|
|
386
|
+
"collection_id": collection_id,
|
|
387
|
+
"provider": provider,
|
|
388
|
+
"include_steps": include_steps,
|
|
389
|
+
},
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
class RLResource(BaseResource):
|
|
394
|
+
"""Reinforcement Learning training endpoints."""
|
|
395
|
+
|
|
396
|
+
async def train_memory_manager(
|
|
397
|
+
self,
|
|
398
|
+
collection_id: Optional[str] = None,
|
|
399
|
+
num_episodes: int = 100,
|
|
400
|
+
**kwargs,
|
|
401
|
+
) -> Dict[str, Any]:
|
|
402
|
+
"""
|
|
403
|
+
Train the Memory Manager agent using RL.
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
collection_id: Optional collection to train on
|
|
407
|
+
num_episodes: Number of training episodes
|
|
408
|
+
**kwargs: Additional training parameters
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Training results with metrics
|
|
412
|
+
"""
|
|
413
|
+
return await self.client.post(
|
|
414
|
+
"/rl/train/memory-manager",
|
|
415
|
+
json={
|
|
416
|
+
"collection_id": collection_id,
|
|
417
|
+
"num_episodes": num_episodes,
|
|
418
|
+
**kwargs,
|
|
419
|
+
},
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
async def train_answer_agent(
|
|
423
|
+
self,
|
|
424
|
+
collection_id: Optional[str] = None,
|
|
425
|
+
num_episodes: int = 100,
|
|
426
|
+
**kwargs,
|
|
427
|
+
) -> Dict[str, Any]:
|
|
428
|
+
"""
|
|
429
|
+
Train the Answer Agent using RL.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
collection_id: Optional collection to train on
|
|
433
|
+
num_episodes: Number of training episodes
|
|
434
|
+
**kwargs: Additional training parameters
|
|
435
|
+
|
|
436
|
+
Returns:
|
|
437
|
+
Training results with metrics
|
|
438
|
+
"""
|
|
439
|
+
return await self.client.post(
|
|
440
|
+
"/rl/train/answer-agent",
|
|
441
|
+
json={
|
|
442
|
+
"collection_id": collection_id,
|
|
443
|
+
"num_episodes": num_episodes,
|
|
444
|
+
**kwargs,
|
|
445
|
+
},
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
async def get_metrics(self) -> Dict[str, Any]:
|
|
449
|
+
"""
|
|
450
|
+
Get RL training metrics.
|
|
451
|
+
|
|
452
|
+
Returns:
|
|
453
|
+
Training metrics and statistics
|
|
454
|
+
"""
|
|
455
|
+
return await self.client.get("/rl/metrics")
|
|
456
|
+
|
|
457
|
+
async def evaluate(
|
|
458
|
+
self,
|
|
459
|
+
agent_type: str,
|
|
460
|
+
collection_id: Optional[str] = None,
|
|
461
|
+
) -> Dict[str, Any]:
|
|
462
|
+
"""
|
|
463
|
+
Evaluate a trained RL agent.
|
|
464
|
+
|
|
465
|
+
Args:
|
|
466
|
+
agent_type: Type of agent (memory_manager or answer_agent)
|
|
467
|
+
collection_id: Optional collection to evaluate on
|
|
468
|
+
|
|
469
|
+
Returns:
|
|
470
|
+
Evaluation results
|
|
471
|
+
"""
|
|
472
|
+
return await self.client.post(
|
|
473
|
+
"/rl/evaluate",
|
|
474
|
+
json={
|
|
475
|
+
"agent_type": agent_type,
|
|
476
|
+
"collection_id": collection_id,
|
|
477
|
+
},
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
class ProceduralResource(BaseResource):
|
|
482
|
+
"""Procedural memory endpoints."""
|
|
483
|
+
|
|
484
|
+
async def create(
|
|
485
|
+
self,
|
|
486
|
+
name: str,
|
|
487
|
+
description: str,
|
|
488
|
+
trigger_condition: str,
|
|
489
|
+
action_sequence: List[str],
|
|
490
|
+
collection_id: Optional[str] = None,
|
|
491
|
+
category: Optional[str] = None,
|
|
492
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
493
|
+
) -> Dict[str, Any]:
|
|
494
|
+
"""
|
|
495
|
+
Create a new procedure.
|
|
496
|
+
|
|
497
|
+
Args:
|
|
498
|
+
name: Procedure name
|
|
499
|
+
description: What the procedure does
|
|
500
|
+
trigger_condition: When to trigger (IF condition)
|
|
501
|
+
action_sequence: Steps to execute (THEN actions)
|
|
502
|
+
collection_id: Optional collection ID
|
|
503
|
+
category: Optional category
|
|
504
|
+
metadata: Optional metadata
|
|
505
|
+
|
|
506
|
+
Returns:
|
|
507
|
+
Created procedure
|
|
508
|
+
"""
|
|
509
|
+
return await self.client.post(
|
|
510
|
+
"/procedural",
|
|
511
|
+
json={
|
|
512
|
+
"name": name,
|
|
513
|
+
"description": description,
|
|
514
|
+
"trigger_condition": trigger_condition,
|
|
515
|
+
"action_sequence": action_sequence,
|
|
516
|
+
"collection_id": collection_id,
|
|
517
|
+
"category": category,
|
|
518
|
+
"metadata": metadata or {},
|
|
519
|
+
},
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
async def list(
|
|
523
|
+
self,
|
|
524
|
+
collection_id: Optional[str] = None,
|
|
525
|
+
category: Optional[str] = None,
|
|
526
|
+
skip: int = 0,
|
|
527
|
+
limit: int = 100,
|
|
528
|
+
) -> List[Dict[str, Any]]:
|
|
529
|
+
"""
|
|
530
|
+
List procedures.
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
collection_id: Optional collection filter
|
|
534
|
+
category: Optional category filter
|
|
535
|
+
skip: Number of items to skip
|
|
536
|
+
limit: Maximum number of items
|
|
537
|
+
|
|
538
|
+
Returns:
|
|
539
|
+
List of procedures
|
|
540
|
+
"""
|
|
541
|
+
params = {"skip": skip, "limit": limit}
|
|
542
|
+
if collection_id:
|
|
543
|
+
params["collection_id"] = collection_id
|
|
544
|
+
if category:
|
|
545
|
+
params["category"] = category
|
|
546
|
+
|
|
547
|
+
return await self.client.get("/procedural", params=params)
|
|
548
|
+
|
|
549
|
+
async def get(self, procedure_id: str) -> Dict[str, Any]:
|
|
550
|
+
"""
|
|
551
|
+
Get a specific procedure.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
procedure_id: Procedure ID
|
|
555
|
+
|
|
556
|
+
Returns:
|
|
557
|
+
Procedure data
|
|
558
|
+
"""
|
|
559
|
+
return await self.client.get(f"/procedural/{procedure_id}")
|
|
560
|
+
|
|
561
|
+
async def execute(
|
|
562
|
+
self,
|
|
563
|
+
procedure_id: str,
|
|
564
|
+
context: Optional[Dict[str, Any]] = None,
|
|
565
|
+
) -> Dict[str, Any]:
|
|
566
|
+
"""
|
|
567
|
+
Execute a procedure.
|
|
568
|
+
|
|
569
|
+
Args:
|
|
570
|
+
procedure_id: Procedure ID
|
|
571
|
+
context: Optional execution context
|
|
572
|
+
|
|
573
|
+
Returns:
|
|
574
|
+
Execution result
|
|
575
|
+
"""
|
|
576
|
+
return await self.client.post(
|
|
577
|
+
f"/procedural/{procedure_id}/execute",
|
|
578
|
+
json={"context": context or {}},
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
async def update(
|
|
582
|
+
self,
|
|
583
|
+
procedure_id: str,
|
|
584
|
+
name: Optional[str] = None,
|
|
585
|
+
description: Optional[str] = None,
|
|
586
|
+
trigger_condition: Optional[str] = None,
|
|
587
|
+
action_sequence: Optional[List[str]] = None,
|
|
588
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
589
|
+
) -> Dict[str, Any]:
|
|
590
|
+
"""
|
|
591
|
+
Update a procedure.
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
procedure_id: Procedure ID
|
|
595
|
+
name: New name
|
|
596
|
+
description: New description
|
|
597
|
+
trigger_condition: New trigger
|
|
598
|
+
action_sequence: New actions
|
|
599
|
+
metadata: New metadata
|
|
600
|
+
|
|
601
|
+
Returns:
|
|
602
|
+
Updated procedure
|
|
603
|
+
"""
|
|
604
|
+
data = {}
|
|
605
|
+
if name is not None:
|
|
606
|
+
data["name"] = name
|
|
607
|
+
if description is not None:
|
|
608
|
+
data["description"] = description
|
|
609
|
+
if trigger_condition is not None:
|
|
610
|
+
data["trigger_condition"] = trigger_condition
|
|
611
|
+
if action_sequence is not None:
|
|
612
|
+
data["action_sequence"] = action_sequence
|
|
613
|
+
if metadata is not None:
|
|
614
|
+
data["metadata"] = metadata
|
|
615
|
+
|
|
616
|
+
return await self.client.patch(f"/procedural/{procedure_id}", json=data)
|
|
617
|
+
|
|
618
|
+
async def delete(self, procedure_id: str) -> None:
|
|
619
|
+
"""
|
|
620
|
+
Delete a procedure.
|
|
621
|
+
|
|
622
|
+
Args:
|
|
623
|
+
procedure_id: Procedure ID
|
|
624
|
+
"""
|
|
625
|
+
await self.client.delete(f"/procedural/{procedure_id}")
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
class TemporalResource(BaseResource):
|
|
629
|
+
"""Temporal knowledge graph endpoints."""
|
|
630
|
+
|
|
631
|
+
async def add_fact(
|
|
632
|
+
self,
|
|
633
|
+
subject: str,
|
|
634
|
+
predicate: str,
|
|
635
|
+
object: str,
|
|
636
|
+
valid_from: Optional[str] = None,
|
|
637
|
+
valid_until: Optional[str] = None,
|
|
638
|
+
confidence: float = 1.0,
|
|
639
|
+
source_memory_id: Optional[str] = None,
|
|
640
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
641
|
+
) -> Dict[str, Any]:
|
|
642
|
+
"""
|
|
643
|
+
Add a temporal fact to the knowledge graph.
|
|
644
|
+
|
|
645
|
+
Args:
|
|
646
|
+
subject: Subject entity
|
|
647
|
+
predicate: Relationship type
|
|
648
|
+
object: Object entity
|
|
649
|
+
valid_from: When fact became true (ISO timestamp)
|
|
650
|
+
valid_until: When fact stopped being true (ISO timestamp)
|
|
651
|
+
confidence: Confidence score (0-1)
|
|
652
|
+
source_memory_id: Source memory that introduced this fact
|
|
653
|
+
metadata: Optional metadata
|
|
654
|
+
|
|
655
|
+
Returns:
|
|
656
|
+
Created fact
|
|
657
|
+
"""
|
|
658
|
+
return await self.client.post(
|
|
659
|
+
"/temporal/facts",
|
|
660
|
+
json={
|
|
661
|
+
"subject": subject,
|
|
662
|
+
"predicate": predicate,
|
|
663
|
+
"object": object,
|
|
664
|
+
"valid_from": valid_from,
|
|
665
|
+
"valid_until": valid_until,
|
|
666
|
+
"confidence": confidence,
|
|
667
|
+
"source_memory_id": source_memory_id,
|
|
668
|
+
"metadata": metadata or {},
|
|
669
|
+
},
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
async def query_facts(
|
|
673
|
+
self,
|
|
674
|
+
subject: Optional[str] = None,
|
|
675
|
+
predicate: Optional[str] = None,
|
|
676
|
+
object: Optional[str] = None,
|
|
677
|
+
at_time: Optional[str] = None,
|
|
678
|
+
) -> List[Dict[str, Any]]:
|
|
679
|
+
"""
|
|
680
|
+
Query temporal facts.
|
|
681
|
+
|
|
682
|
+
Args:
|
|
683
|
+
subject: Filter by subject
|
|
684
|
+
predicate: Filter by predicate
|
|
685
|
+
object: Filter by object
|
|
686
|
+
at_time: Query facts valid at specific time (ISO timestamp)
|
|
687
|
+
|
|
688
|
+
Returns:
|
|
689
|
+
List of matching facts
|
|
690
|
+
"""
|
|
691
|
+
params = {}
|
|
692
|
+
if subject:
|
|
693
|
+
params["subject"] = subject
|
|
694
|
+
if predicate:
|
|
695
|
+
params["predicate"] = predicate
|
|
696
|
+
if object:
|
|
697
|
+
params["object"] = object
|
|
698
|
+
if at_time:
|
|
699
|
+
params["at_time"] = at_time
|
|
700
|
+
|
|
701
|
+
return await self.client.get("/temporal/facts", params=params)
|
|
702
|
+
|
|
703
|
+
async def point_in_time(
|
|
704
|
+
self,
|
|
705
|
+
timestamp: str,
|
|
706
|
+
entity: Optional[str] = None,
|
|
707
|
+
) -> Dict[str, Any]:
|
|
708
|
+
"""
|
|
709
|
+
Query knowledge state at a specific point in time.
|
|
710
|
+
|
|
711
|
+
Args:
|
|
712
|
+
timestamp: ISO timestamp
|
|
713
|
+
entity: Optional entity filter
|
|
714
|
+
|
|
715
|
+
Returns:
|
|
716
|
+
Knowledge state at that time
|
|
717
|
+
"""
|
|
718
|
+
return await self.client.post(
|
|
719
|
+
"/temporal/point-in-time",
|
|
720
|
+
json={
|
|
721
|
+
"timestamp": timestamp,
|
|
722
|
+
"entity": entity,
|
|
723
|
+
},
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
class WorkingMemoryResource(BaseResource):
|
|
728
|
+
"""Working memory buffer endpoints."""
|
|
729
|
+
|
|
730
|
+
async def add(
|
|
731
|
+
self,
|
|
732
|
+
role: str,
|
|
733
|
+
content: str,
|
|
734
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
735
|
+
) -> Dict[str, Any]:
|
|
736
|
+
"""
|
|
737
|
+
Add item to working memory buffer.
|
|
738
|
+
|
|
739
|
+
Args:
|
|
740
|
+
role: Role (user, assistant, system)
|
|
741
|
+
content: Content
|
|
742
|
+
metadata: Optional metadata
|
|
743
|
+
|
|
744
|
+
Returns:
|
|
745
|
+
Added item
|
|
746
|
+
"""
|
|
747
|
+
return await self.client.post(
|
|
748
|
+
"/working-memory",
|
|
749
|
+
json={
|
|
750
|
+
"role": role,
|
|
751
|
+
"content": content,
|
|
752
|
+
"metadata": metadata or {},
|
|
753
|
+
},
|
|
754
|
+
)
|
|
755
|
+
|
|
756
|
+
async def get_context(self) -> Dict[str, Any]:
|
|
757
|
+
"""
|
|
758
|
+
Get current working memory context.
|
|
759
|
+
|
|
760
|
+
Returns:
|
|
761
|
+
Current context with buffer items
|
|
762
|
+
"""
|
|
763
|
+
return await self.client.get("/working-memory/context")
|
|
764
|
+
|
|
765
|
+
async def compress(self) -> Dict[str, Any]:
|
|
766
|
+
"""
|
|
767
|
+
Compress working memory buffer.
|
|
768
|
+
|
|
769
|
+
Returns:
|
|
770
|
+
Compression result
|
|
771
|
+
"""
|
|
772
|
+
return await self.client.post("/working-memory/compress")
|
|
773
|
+
|
|
774
|
+
async def clear(self) -> Dict[str, Any]:
|
|
775
|
+
"""
|
|
776
|
+
Clear working memory buffer.
|
|
777
|
+
|
|
778
|
+
Returns:
|
|
779
|
+
Clear result
|
|
780
|
+
"""
|
|
781
|
+
return await self.client.delete("/working-memory")
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
class ConsolidationResource(BaseResource):
|
|
785
|
+
"""Memory consolidation endpoints."""
|
|
786
|
+
|
|
787
|
+
async def consolidate(
|
|
788
|
+
self,
|
|
789
|
+
collection_id: str,
|
|
790
|
+
threshold: int = 100,
|
|
791
|
+
) -> Dict[str, Any]:
|
|
792
|
+
"""
|
|
793
|
+
Trigger memory consolidation.
|
|
794
|
+
|
|
795
|
+
Args:
|
|
796
|
+
collection_id: Collection to consolidate
|
|
797
|
+
threshold: Minimum number of memories to consolidate
|
|
798
|
+
|
|
799
|
+
Returns:
|
|
800
|
+
Consolidation results
|
|
801
|
+
"""
|
|
802
|
+
return await self.client.post(
|
|
803
|
+
"/consolidation/consolidate",
|
|
804
|
+
json={
|
|
805
|
+
"collection_id": collection_id,
|
|
806
|
+
"threshold": threshold,
|
|
807
|
+
},
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
async def get_stats(self, collection_id: str) -> Dict[str, Any]:
|
|
811
|
+
"""
|
|
812
|
+
Get consolidation statistics.
|
|
813
|
+
|
|
814
|
+
Args:
|
|
815
|
+
collection_id: Collection ID
|
|
816
|
+
|
|
817
|
+
Returns:
|
|
818
|
+
Consolidation stats
|
|
819
|
+
"""
|
|
820
|
+
return await self.client.get(
|
|
821
|
+
"/consolidation/stats",
|
|
822
|
+
params={"collection_id": collection_id},
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
async def archive(
|
|
826
|
+
self,
|
|
827
|
+
collection_id: str,
|
|
828
|
+
before_date: Optional[str] = None,
|
|
829
|
+
) -> Dict[str, Any]:
|
|
830
|
+
"""
|
|
831
|
+
Archive old memories.
|
|
832
|
+
|
|
833
|
+
Args:
|
|
834
|
+
collection_id: Collection ID
|
|
835
|
+
before_date: Archive memories before this date (ISO timestamp)
|
|
836
|
+
|
|
837
|
+
Returns:
|
|
838
|
+
Archive result
|
|
839
|
+
"""
|
|
840
|
+
return await self.client.post(
|
|
841
|
+
"/consolidation/archive",
|
|
842
|
+
json={
|
|
843
|
+
"collection_id": collection_id,
|
|
844
|
+
"before_date": before_date,
|
|
845
|
+
},
|
|
846
|
+
)
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
class MemoryToolsResource(BaseResource):
|
|
850
|
+
"""Self-editing memory tools endpoints."""
|
|
851
|
+
|
|
852
|
+
async def replace(
|
|
853
|
+
self,
|
|
854
|
+
memory_id: str,
|
|
855
|
+
new_content: str,
|
|
856
|
+
reason: Optional[str] = None,
|
|
857
|
+
) -> Dict[str, Any]:
|
|
858
|
+
"""
|
|
859
|
+
Replace memory content.
|
|
860
|
+
|
|
861
|
+
Args:
|
|
862
|
+
memory_id: Memory to replace
|
|
863
|
+
new_content: New content
|
|
864
|
+
reason: Optional reason for replacement
|
|
865
|
+
|
|
866
|
+
Returns:
|
|
867
|
+
Updated memory
|
|
868
|
+
"""
|
|
869
|
+
return await self.client.post(
|
|
870
|
+
"/memory-tools/replace",
|
|
871
|
+
json={
|
|
872
|
+
"memory_id": memory_id,
|
|
873
|
+
"new_content": new_content,
|
|
874
|
+
"reason": reason,
|
|
875
|
+
},
|
|
876
|
+
)
|
|
877
|
+
|
|
878
|
+
async def insert(
|
|
879
|
+
self,
|
|
880
|
+
collection_id: str,
|
|
881
|
+
content: str,
|
|
882
|
+
position: int,
|
|
883
|
+
reason: Optional[str] = None,
|
|
884
|
+
) -> Dict[str, Any]:
|
|
885
|
+
"""
|
|
886
|
+
Insert new memory at position.
|
|
887
|
+
|
|
888
|
+
Args:
|
|
889
|
+
collection_id: Collection ID
|
|
890
|
+
content: Memory content
|
|
891
|
+
position: Position to insert
|
|
892
|
+
reason: Optional reason
|
|
893
|
+
|
|
894
|
+
Returns:
|
|
895
|
+
Inserted memory
|
|
896
|
+
"""
|
|
897
|
+
return await self.client.post(
|
|
898
|
+
"/memory-tools/insert",
|
|
899
|
+
json={
|
|
900
|
+
"collection_id": collection_id,
|
|
901
|
+
"content": content,
|
|
902
|
+
"position": position,
|
|
903
|
+
"reason": reason,
|
|
904
|
+
},
|
|
905
|
+
)
|
|
906
|
+
|
|
907
|
+
async def rethink(
|
|
908
|
+
self,
|
|
909
|
+
memory_id: str,
|
|
910
|
+
query: str,
|
|
911
|
+
) -> Dict[str, Any]:
|
|
912
|
+
"""
|
|
913
|
+
Re-evaluate memory in light of new information.
|
|
914
|
+
|
|
915
|
+
Args:
|
|
916
|
+
memory_id: Memory to re-evaluate
|
|
917
|
+
query: New context or question
|
|
918
|
+
|
|
919
|
+
Returns:
|
|
920
|
+
Re-evaluation result
|
|
921
|
+
"""
|
|
922
|
+
return await self.client.post(
|
|
923
|
+
"/memory-tools/rethink",
|
|
924
|
+
json={
|
|
925
|
+
"memory_id": memory_id,
|
|
926
|
+
"query": query,
|
|
927
|
+
},
|
|
928
|
+
)
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
class WorldModelResource(BaseResource):
|
|
932
|
+
"""World model and planning endpoints."""
|
|
933
|
+
|
|
934
|
+
async def imagine_retrieval(
|
|
935
|
+
self,
|
|
936
|
+
query: str,
|
|
937
|
+
collection_id: Optional[str] = None,
|
|
938
|
+
) -> Dict[str, Any]:
|
|
939
|
+
"""
|
|
940
|
+
Simulate retrieval without actually retrieving.
|
|
941
|
+
|
|
942
|
+
Args:
|
|
943
|
+
query: Query to simulate
|
|
944
|
+
collection_id: Optional collection
|
|
945
|
+
|
|
946
|
+
Returns:
|
|
947
|
+
Simulated retrieval result
|
|
948
|
+
"""
|
|
949
|
+
return await self.client.post(
|
|
950
|
+
"/world-model/imagine-retrieval",
|
|
951
|
+
json={
|
|
952
|
+
"query": query,
|
|
953
|
+
"collection_id": collection_id,
|
|
954
|
+
},
|
|
955
|
+
)
|
|
956
|
+
|
|
957
|
+
async def plan(
|
|
958
|
+
self,
|
|
959
|
+
goal: str,
|
|
960
|
+
collection_id: Optional[str] = None,
|
|
961
|
+
) -> Dict[str, Any]:
|
|
962
|
+
"""
|
|
963
|
+
Plan memory operations to achieve goal.
|
|
964
|
+
|
|
965
|
+
Args:
|
|
966
|
+
goal: Goal to achieve
|
|
967
|
+
collection_id: Optional collection
|
|
968
|
+
|
|
969
|
+
Returns:
|
|
970
|
+
Planned operations
|
|
971
|
+
"""
|
|
972
|
+
return await self.client.post(
|
|
973
|
+
"/world-model/plan",
|
|
974
|
+
json={
|
|
975
|
+
"goal": goal,
|
|
976
|
+
"collection_id": collection_id,
|
|
977
|
+
},
|
|
978
|
+
)
|