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/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
+ )