hindsight-api 0.0.21__py3-none-any.whl → 0.1.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.
- hindsight_api/__init__.py +10 -2
- hindsight_api/alembic/README +1 -0
- hindsight_api/alembic/env.py +146 -0
- hindsight_api/alembic/script.py.mako +28 -0
- hindsight_api/alembic/versions/5a366d414dce_initial_schema.py +274 -0
- hindsight_api/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py +70 -0
- hindsight_api/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py +39 -0
- hindsight_api/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py +48 -0
- hindsight_api/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py +62 -0
- hindsight_api/alembic/versions/rename_personality_to_disposition.py +65 -0
- hindsight_api/api/__init__.py +2 -4
- hindsight_api/api/http.py +112 -164
- hindsight_api/api/mcp.py +2 -1
- hindsight_api/config.py +154 -0
- hindsight_api/engine/__init__.py +7 -2
- hindsight_api/engine/cross_encoder.py +225 -16
- hindsight_api/engine/embeddings.py +198 -19
- hindsight_api/engine/entity_resolver.py +56 -29
- hindsight_api/engine/llm_wrapper.py +147 -106
- hindsight_api/engine/memory_engine.py +337 -192
- hindsight_api/engine/response_models.py +15 -17
- hindsight_api/engine/retain/bank_utils.py +25 -35
- hindsight_api/engine/retain/entity_processing.py +5 -5
- hindsight_api/engine/retain/fact_extraction.py +86 -24
- hindsight_api/engine/retain/fact_storage.py +1 -1
- hindsight_api/engine/retain/link_creation.py +12 -6
- hindsight_api/engine/retain/link_utils.py +50 -56
- hindsight_api/engine/retain/observation_regeneration.py +264 -0
- hindsight_api/engine/retain/orchestrator.py +31 -44
- hindsight_api/engine/retain/types.py +14 -0
- hindsight_api/engine/search/reranking.py +6 -10
- hindsight_api/engine/search/retrieval.py +2 -2
- hindsight_api/engine/search/think_utils.py +59 -30
- hindsight_api/engine/search/tracer.py +1 -1
- hindsight_api/main.py +201 -0
- hindsight_api/migrations.py +61 -39
- hindsight_api/models.py +1 -2
- hindsight_api/pg0.py +17 -36
- hindsight_api/server.py +43 -0
- {hindsight_api-0.0.21.dist-info → hindsight_api-0.1.1.dist-info}/METADATA +2 -3
- hindsight_api-0.1.1.dist-info/RECORD +60 -0
- hindsight_api-0.1.1.dist-info/entry_points.txt +2 -0
- hindsight_api/cli.py +0 -128
- hindsight_api/web/__init__.py +0 -12
- hindsight_api/web/server.py +0 -109
- hindsight_api-0.0.21.dist-info/RECORD +0 -50
- hindsight_api-0.0.21.dist-info/entry_points.txt +0 -2
- {hindsight_api-0.0.21.dist-info → hindsight_api-0.1.1.dist-info}/WHEEL +0 -0
hindsight_api/api/http.py
CHANGED
|
@@ -36,27 +36,13 @@ from pydantic import BaseModel, Field, ConfigDict
|
|
|
36
36
|
from hindsight_api import MemoryEngine
|
|
37
37
|
from hindsight_api.engine.memory_engine import Budget
|
|
38
38
|
from hindsight_api.engine.db_utils import acquire_with_retry
|
|
39
|
+
from hindsight_api.engine.response_models import VALID_RECALL_FACT_TYPES
|
|
39
40
|
from hindsight_api.metrics import get_metrics_collector, initialize_metrics, create_metrics_collector
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
logger = logging.getLogger(__name__)
|
|
43
44
|
|
|
44
45
|
|
|
45
|
-
class MetadataFilter(BaseModel):
|
|
46
|
-
"""Filter for metadata fields. Matches records where (key=value) OR (key not set) when match_unset=True."""
|
|
47
|
-
model_config = ConfigDict(json_schema_extra={
|
|
48
|
-
"example": {
|
|
49
|
-
"key": "source",
|
|
50
|
-
"value": "slack",
|
|
51
|
-
"match_unset": True
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
key: str = Field(description="Metadata key to filter on")
|
|
56
|
-
value: Optional[str] = Field(default=None, description="Value to match. If None with match_unset=True, matches any record where key is not set.")
|
|
57
|
-
match_unset: bool = Field(default=True, description="If True, also match records where this metadata key is not set")
|
|
58
|
-
|
|
59
|
-
|
|
60
46
|
class EntityIncludeOptions(BaseModel):
|
|
61
47
|
"""Options for including entity observations in recall results."""
|
|
62
48
|
max_tokens: int = Field(default=500, description="Maximum tokens for entity observations")
|
|
@@ -89,7 +75,6 @@ class RecallRequest(BaseModel):
|
|
|
89
75
|
"max_tokens": 4096,
|
|
90
76
|
"trace": True,
|
|
91
77
|
"query_timestamp": "2023-05-30T23:40:00",
|
|
92
|
-
"filters": [{"key": "source", "value": "slack", "match_unset": True}],
|
|
93
78
|
"include": {
|
|
94
79
|
"entities": {
|
|
95
80
|
"max_tokens": 500
|
|
@@ -104,7 +89,6 @@ class RecallRequest(BaseModel):
|
|
|
104
89
|
max_tokens: int = 4096
|
|
105
90
|
trace: bool = False
|
|
106
91
|
query_timestamp: Optional[str] = Field(default=None, description="ISO format date string (e.g., '2023-05-30T23:40:00')")
|
|
107
|
-
filters: Optional[List[MetadataFilter]] = Field(default=None, description="Filter by metadata. Multiple filters are ANDed together.")
|
|
108
92
|
include: IncludeOptions = Field(default_factory=IncludeOptions, description="Options for including additional data (entities are included by default)")
|
|
109
93
|
|
|
110
94
|
|
|
@@ -362,7 +346,6 @@ class ReflectRequest(BaseModel):
|
|
|
362
346
|
"query": "What do you think about artificial intelligence?",
|
|
363
347
|
"budget": "low",
|
|
364
348
|
"context": "This is for a research paper on AI ethics",
|
|
365
|
-
"filters": [{"key": "source", "value": "slack", "match_unset": True}],
|
|
366
349
|
"include": {
|
|
367
350
|
"facts": {}
|
|
368
351
|
}
|
|
@@ -372,7 +355,6 @@ class ReflectRequest(BaseModel):
|
|
|
372
355
|
query: str
|
|
373
356
|
budget: Budget = Budget.LOW
|
|
374
357
|
context: Optional[str] = None
|
|
375
|
-
filters: Optional[List[MetadataFilter]] = Field(default=None, description="Filter by metadata. Multiple filters are ANDed together.")
|
|
376
358
|
include: ReflectIncludeOptions = Field(default_factory=ReflectIncludeOptions, description="Options for including additional data (disabled by default)")
|
|
377
359
|
|
|
378
360
|
|
|
@@ -439,24 +421,18 @@ class BanksResponse(BaseModel):
|
|
|
439
421
|
|
|
440
422
|
|
|
441
423
|
class DispositionTraits(BaseModel):
|
|
442
|
-
"""Disposition traits
|
|
424
|
+
"""Disposition traits that influence how memories are formed and interpreted."""
|
|
443
425
|
model_config = ConfigDict(json_schema_extra={
|
|
444
426
|
"example": {
|
|
445
|
-
"
|
|
446
|
-
"
|
|
447
|
-
"
|
|
448
|
-
"agreeableness": 0.7,
|
|
449
|
-
"neuroticism": 0.3,
|
|
450
|
-
"bias_strength": 0.7
|
|
427
|
+
"skepticism": 3,
|
|
428
|
+
"literalism": 3,
|
|
429
|
+
"empathy": 3
|
|
451
430
|
}
|
|
452
431
|
})
|
|
453
432
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
agreeableness: float = Field(ge=0.0, le=1.0, description="Agreeableness (0-1)")
|
|
458
|
-
neuroticism: float = Field(ge=0.0, le=1.0, description="Neuroticism (0-1)")
|
|
459
|
-
bias_strength: float = Field(ge=0.0, le=1.0, description="How strongly disposition influences opinions (0-1)")
|
|
433
|
+
skepticism: int = Field(ge=1, le=5, description="How skeptical vs trusting (1=trusting, 5=skeptical)")
|
|
434
|
+
literalism: int = Field(ge=1, le=5, description="How literally to interpret information (1=flexible, 5=literal)")
|
|
435
|
+
empathy: int = Field(ge=1, le=5, description="How much to consider emotional context (1=detached, 5=empathetic)")
|
|
460
436
|
|
|
461
437
|
|
|
462
438
|
class BankProfileResponse(BaseModel):
|
|
@@ -466,12 +442,9 @@ class BankProfileResponse(BaseModel):
|
|
|
466
442
|
"bank_id": "user123",
|
|
467
443
|
"name": "Alice",
|
|
468
444
|
"disposition": {
|
|
469
|
-
"
|
|
470
|
-
"
|
|
471
|
-
"
|
|
472
|
-
"agreeableness": 0.7,
|
|
473
|
-
"neuroticism": 0.3,
|
|
474
|
-
"bias_strength": 0.7
|
|
445
|
+
"skepticism": 3,
|
|
446
|
+
"literalism": 3,
|
|
447
|
+
"empathy": 3
|
|
475
448
|
},
|
|
476
449
|
"background": "I am a software engineer with 10 years of experience in startups"
|
|
477
450
|
}
|
|
@@ -500,7 +473,7 @@ class AddBackgroundRequest(BaseModel):
|
|
|
500
473
|
content: str = Field(description="New background information to add or merge")
|
|
501
474
|
update_disposition: bool = Field(
|
|
502
475
|
default=True,
|
|
503
|
-
description="If true, infer
|
|
476
|
+
description="If true, infer disposition traits from the merged background (default: true)"
|
|
504
477
|
)
|
|
505
478
|
|
|
506
479
|
|
|
@@ -510,12 +483,9 @@ class BackgroundResponse(BaseModel):
|
|
|
510
483
|
"example": {
|
|
511
484
|
"background": "I was born in Texas. I am a software engineer with 10 years of experience.",
|
|
512
485
|
"disposition": {
|
|
513
|
-
"
|
|
514
|
-
"
|
|
515
|
-
"
|
|
516
|
-
"agreeableness": 0.8,
|
|
517
|
-
"neuroticism": 0.4,
|
|
518
|
-
"bias_strength": 0.6
|
|
486
|
+
"skepticism": 3,
|
|
487
|
+
"literalism": 3,
|
|
488
|
+
"empathy": 3
|
|
519
489
|
}
|
|
520
490
|
}
|
|
521
491
|
})
|
|
@@ -543,12 +513,9 @@ class BankListResponse(BaseModel):
|
|
|
543
513
|
"bank_id": "user123",
|
|
544
514
|
"name": "Alice",
|
|
545
515
|
"disposition": {
|
|
546
|
-
"
|
|
547
|
-
"
|
|
548
|
-
"
|
|
549
|
-
"agreeableness": 0.5,
|
|
550
|
-
"neuroticism": 0.5,
|
|
551
|
-
"bias_strength": 0.5
|
|
516
|
+
"skepticism": 3,
|
|
517
|
+
"literalism": 3,
|
|
518
|
+
"empathy": 3
|
|
552
519
|
},
|
|
553
520
|
"background": "I am a software engineer",
|
|
554
521
|
"created_at": "2024-01-15T10:30:00Z",
|
|
@@ -567,12 +534,9 @@ class CreateBankRequest(BaseModel):
|
|
|
567
534
|
"example": {
|
|
568
535
|
"name": "Alice",
|
|
569
536
|
"disposition": {
|
|
570
|
-
"
|
|
571
|
-
"
|
|
572
|
-
"
|
|
573
|
-
"agreeableness": 0.7,
|
|
574
|
-
"neuroticism": 0.3,
|
|
575
|
-
"bias_strength": 0.7
|
|
537
|
+
"skepticism": 3,
|
|
538
|
+
"literalism": 3,
|
|
539
|
+
"empathy": 3
|
|
576
540
|
},
|
|
577
541
|
"background": "I am a creative software engineer with 10 years of experience"
|
|
578
542
|
}
|
|
@@ -715,13 +679,13 @@ class DeleteResponse(BaseModel):
|
|
|
715
679
|
success: bool
|
|
716
680
|
|
|
717
681
|
|
|
718
|
-
def create_app(memory: MemoryEngine,
|
|
682
|
+
def create_app(memory: MemoryEngine, initialize_memory: bool = True) -> FastAPI:
|
|
719
683
|
"""
|
|
720
684
|
Create and configure the FastAPI application.
|
|
721
685
|
|
|
722
686
|
Args:
|
|
723
|
-
memory: MemoryEngine instance (already initialized with required parameters)
|
|
724
|
-
|
|
687
|
+
memory: MemoryEngine instance (already initialized with required parameters).
|
|
688
|
+
Migrations are controlled by the MemoryEngine's run_migrations parameter.
|
|
725
689
|
initialize_memory: Whether to initialize memory system on startup (default: True)
|
|
726
690
|
|
|
727
691
|
Returns:
|
|
@@ -752,16 +716,11 @@ def create_app(memory: MemoryEngine, run_migrations: bool = True, initialize_mem
|
|
|
752
716
|
app.state.prometheus_reader = None
|
|
753
717
|
# Metrics collector is already initialized as no-op by default
|
|
754
718
|
|
|
755
|
-
# Startup: Initialize database and memory system
|
|
719
|
+
# Startup: Initialize database and memory system (migrations run inside initialize if enabled)
|
|
756
720
|
if initialize_memory:
|
|
757
721
|
await memory.initialize()
|
|
758
722
|
logging.info("Memory system initialized")
|
|
759
723
|
|
|
760
|
-
if run_migrations:
|
|
761
|
-
from hindsight_api.migrations import run_migrations as do_migrations
|
|
762
|
-
do_migrations(memory.db_url)
|
|
763
|
-
logging.info("Database migrations applied")
|
|
764
|
-
|
|
765
724
|
|
|
766
725
|
|
|
767
726
|
yield
|
|
@@ -770,9 +729,11 @@ def create_app(memory: MemoryEngine, run_migrations: bool = True, initialize_mem
|
|
|
770
729
|
await memory.close()
|
|
771
730
|
logging.info("Memory system closed")
|
|
772
731
|
|
|
732
|
+
from hindsight_api import __version__
|
|
733
|
+
|
|
773
734
|
app = FastAPI(
|
|
774
735
|
title="Hindsight HTTP API",
|
|
775
|
-
version=
|
|
736
|
+
version=__version__,
|
|
776
737
|
description="HTTP API for Hindsight",
|
|
777
738
|
contact={
|
|
778
739
|
"name": "Memory System",
|
|
@@ -834,7 +795,8 @@ def _register_routes(app: FastAPI):
|
|
|
834
795
|
response_model=GraphDataResponse,
|
|
835
796
|
summary="Get memory graph data",
|
|
836
797
|
description="Retrieve graph data for visualization, optionally filtered by type (world/experience/opinion). Limited to 1000 most recent items.",
|
|
837
|
-
operation_id="get_graph"
|
|
798
|
+
operation_id="get_graph",
|
|
799
|
+
tags=["Memory"]
|
|
838
800
|
)
|
|
839
801
|
async def api_graph(bank_id: str,
|
|
840
802
|
type: Optional[str] = None
|
|
@@ -855,7 +817,8 @@ def _register_routes(app: FastAPI):
|
|
|
855
817
|
response_model=ListMemoryUnitsResponse,
|
|
856
818
|
summary="List memory units",
|
|
857
819
|
description="List memory units with pagination and optional full-text search. Supports filtering by type. Results are sorted by most recent first (mentioned_at DESC, then created_at DESC).",
|
|
858
|
-
operation_id="list_memories"
|
|
820
|
+
operation_id="list_memories",
|
|
821
|
+
tags=["Memory"]
|
|
859
822
|
)
|
|
860
823
|
async def api_list(bank_id: str,
|
|
861
824
|
type: Optional[str] = None,
|
|
@@ -896,34 +859,22 @@ def _register_routes(app: FastAPI):
|
|
|
896
859
|
"/v1/default/banks/{bank_id}/memories/recall",
|
|
897
860
|
response_model=RecallResponse,
|
|
898
861
|
summary="Recall memory",
|
|
899
|
-
description=""
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
Set include_entities=true to get entity observations alongside recall results.
|
|
908
|
-
""",
|
|
909
|
-
operation_id="recall_memories"
|
|
862
|
+
description="Recall memory using semantic similarity and spreading activation.\n\n"
|
|
863
|
+
"The type parameter is optional and must be one of:\n"
|
|
864
|
+
"- `world`: General knowledge about people, places, events, and things that happen\n"
|
|
865
|
+
"- `experience`: Memories about experience, conversations, actions taken, and tasks performed\n"
|
|
866
|
+
"- `opinion`: The bank's formed beliefs, perspectives, and viewpoints\n\n"
|
|
867
|
+
"Set `include_entities=true` to get entity observations alongside recall results.",
|
|
868
|
+
operation_id="recall_memories",
|
|
869
|
+
tags=["Memory"]
|
|
910
870
|
)
|
|
911
871
|
async def api_recall(bank_id: str, request: RecallRequest):
|
|
912
872
|
"""Run a recall and return results with trace."""
|
|
913
873
|
metrics = get_metrics_collector()
|
|
914
874
|
|
|
915
875
|
try:
|
|
916
|
-
# Validate types
|
|
917
|
-
valid_fact_types = ["world", "experience", "opinion"]
|
|
918
|
-
|
|
919
876
|
# Default to world, experience, opinion if not specified (exclude observation by default)
|
|
920
|
-
fact_types = request.types if request.types else
|
|
921
|
-
for ft in fact_types:
|
|
922
|
-
if ft not in valid_fact_types:
|
|
923
|
-
raise HTTPException(
|
|
924
|
-
status_code=400,
|
|
925
|
-
detail=f"Invalid type '{ft}'. Must be one of: {', '.join(valid_fact_types)}"
|
|
926
|
-
)
|
|
877
|
+
fact_types = request.types if request.types else list(VALID_RECALL_FACT_TYPES)
|
|
927
878
|
|
|
928
879
|
# Parse query_timestamp if provided
|
|
929
880
|
question_date = None
|
|
@@ -1022,18 +973,16 @@ def _register_routes(app: FastAPI):
|
|
|
1022
973
|
"/v1/default/banks/{bank_id}/reflect",
|
|
1023
974
|
response_model=ReflectResponse,
|
|
1024
975
|
summary="Reflect and generate answer",
|
|
1025
|
-
description=""
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
""",
|
|
1036
|
-
operation_id="reflect"
|
|
976
|
+
description="Reflect and formulate an answer using bank identity, world facts, and opinions.\n\n"
|
|
977
|
+
"This endpoint:\n"
|
|
978
|
+
"1. Retrieves experience (conversations and events)\n"
|
|
979
|
+
"2. Retrieves world facts relevant to the query\n"
|
|
980
|
+
"3. Retrieves existing opinions (bank's perspectives)\n"
|
|
981
|
+
"4. Uses LLM to formulate a contextual answer\n"
|
|
982
|
+
"5. Extracts and stores any new opinions formed\n"
|
|
983
|
+
"6. Returns plain text answer, the facts used, and new opinions",
|
|
984
|
+
operation_id="reflect",
|
|
985
|
+
tags=["Memory"]
|
|
1037
986
|
)
|
|
1038
987
|
async def api_reflect(bank_id: str, request: ReflectRequest):
|
|
1039
988
|
metrics = get_metrics_collector()
|
|
@@ -1079,7 +1028,8 @@ def _register_routes(app: FastAPI):
|
|
|
1079
1028
|
response_model=BankListResponse,
|
|
1080
1029
|
summary="List all memory banks",
|
|
1081
1030
|
description="Get a list of all agents with their profiles",
|
|
1082
|
-
operation_id="list_banks"
|
|
1031
|
+
operation_id="list_banks",
|
|
1032
|
+
tags=["Banks"]
|
|
1083
1033
|
)
|
|
1084
1034
|
async def api_list_banks():
|
|
1085
1035
|
"""Get list of all banks with their profiles."""
|
|
@@ -1096,7 +1046,8 @@ def _register_routes(app: FastAPI):
|
|
|
1096
1046
|
"/v1/default/banks/{bank_id}/stats",
|
|
1097
1047
|
summary="Get statistics for memory bank",
|
|
1098
1048
|
description="Get statistics about nodes and links for a specific agent",
|
|
1099
|
-
operation_id="get_agent_stats"
|
|
1049
|
+
operation_id="get_agent_stats",
|
|
1050
|
+
tags=["Banks"]
|
|
1100
1051
|
)
|
|
1101
1052
|
async def api_stats(bank_id: str):
|
|
1102
1053
|
"""Get statistics about memory nodes and links for a memory bank."""
|
|
@@ -1217,7 +1168,8 @@ def _register_routes(app: FastAPI):
|
|
|
1217
1168
|
response_model=EntityListResponse,
|
|
1218
1169
|
summary="List entities",
|
|
1219
1170
|
description="List all entities (people, organizations, etc.) known by the bank, ordered by mention count.",
|
|
1220
|
-
operation_id="list_entities"
|
|
1171
|
+
operation_id="list_entities",
|
|
1172
|
+
tags=["Entities"]
|
|
1221
1173
|
)
|
|
1222
1174
|
async def api_list_entities(bank_id: str,
|
|
1223
1175
|
limit: int = Query(default=100, description="Maximum number of entities to return")
|
|
@@ -1239,7 +1191,8 @@ def _register_routes(app: FastAPI):
|
|
|
1239
1191
|
response_model=EntityDetailResponse,
|
|
1240
1192
|
summary="Get entity details",
|
|
1241
1193
|
description="Get detailed information about an entity including observations (mental model).",
|
|
1242
|
-
operation_id="get_entity"
|
|
1194
|
+
operation_id="get_entity",
|
|
1195
|
+
tags=["Entities"]
|
|
1243
1196
|
)
|
|
1244
1197
|
async def api_get_entity(bank_id: str, entity_id: str):
|
|
1245
1198
|
"""Get entity details with observations."""
|
|
@@ -1289,7 +1242,8 @@ def _register_routes(app: FastAPI):
|
|
|
1289
1242
|
response_model=EntityDetailResponse,
|
|
1290
1243
|
summary="Regenerate entity observations",
|
|
1291
1244
|
description="Regenerate observations for an entity based on all facts mentioning it.",
|
|
1292
|
-
operation_id="regenerate_entity_observations"
|
|
1245
|
+
operation_id="regenerate_entity_observations",
|
|
1246
|
+
tags=["Entities"]
|
|
1293
1247
|
)
|
|
1294
1248
|
async def api_regenerate_entity_observations(bank_id: str, entity_id: str):
|
|
1295
1249
|
"""Regenerate observations for an entity."""
|
|
@@ -1346,7 +1300,8 @@ def _register_routes(app: FastAPI):
|
|
|
1346
1300
|
response_model=ListDocumentsResponse,
|
|
1347
1301
|
summary="List documents",
|
|
1348
1302
|
description="List documents with pagination and optional search. Documents are the source content from which memory units are extracted.",
|
|
1349
|
-
operation_id="list_documents"
|
|
1303
|
+
operation_id="list_documents",
|
|
1304
|
+
tags=["Documents"]
|
|
1350
1305
|
)
|
|
1351
1306
|
async def api_list_documents(bank_id: str,
|
|
1352
1307
|
q: Optional[str] = None,
|
|
@@ -1382,7 +1337,8 @@ def _register_routes(app: FastAPI):
|
|
|
1382
1337
|
response_model=DocumentResponse,
|
|
1383
1338
|
summary="Get document details",
|
|
1384
1339
|
description="Get a specific document including its original text",
|
|
1385
|
-
operation_id="get_document"
|
|
1340
|
+
operation_id="get_document",
|
|
1341
|
+
tags=["Documents"]
|
|
1386
1342
|
)
|
|
1387
1343
|
async def api_get_document(bank_id: str,
|
|
1388
1344
|
document_id: str
|
|
@@ -1413,7 +1369,8 @@ def _register_routes(app: FastAPI):
|
|
|
1413
1369
|
response_model=ChunkResponse,
|
|
1414
1370
|
summary="Get chunk details",
|
|
1415
1371
|
description="Get a specific chunk by its ID",
|
|
1416
|
-
operation_id="get_chunk"
|
|
1372
|
+
operation_id="get_chunk",
|
|
1373
|
+
tags=["Documents"]
|
|
1417
1374
|
)
|
|
1418
1375
|
async def api_get_chunk(chunk_id: str):
|
|
1419
1376
|
"""
|
|
@@ -1439,17 +1396,14 @@ def _register_routes(app: FastAPI):
|
|
|
1439
1396
|
@app.delete(
|
|
1440
1397
|
"/v1/default/banks/{bank_id}/documents/{document_id}",
|
|
1441
1398
|
summary="Delete a document",
|
|
1442
|
-
description=""
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
This operation cannot be undone.
|
|
1451
|
-
""",
|
|
1452
|
-
operation_id="delete_document"
|
|
1399
|
+
description="Delete a document and all its associated memory units and links.\n\n"
|
|
1400
|
+
"This will cascade delete:\n"
|
|
1401
|
+
"- The document itself\n"
|
|
1402
|
+
"- All memory units extracted from this document\n"
|
|
1403
|
+
"- All links (temporal, semantic, entity) associated with those memory units\n\n"
|
|
1404
|
+
"This operation cannot be undone.",
|
|
1405
|
+
operation_id="delete_document",
|
|
1406
|
+
tags=["Documents"]
|
|
1453
1407
|
)
|
|
1454
1408
|
async def api_delete_document(bank_id: str,
|
|
1455
1409
|
document_id: str
|
|
@@ -1486,7 +1440,8 @@ This operation cannot be undone.
|
|
|
1486
1440
|
"/v1/default/banks/{bank_id}/operations",
|
|
1487
1441
|
summary="List async operations",
|
|
1488
1442
|
description="Get a list of all async operations (pending and failed) for a specific agent, including error messages for failed operations",
|
|
1489
|
-
operation_id="list_operations"
|
|
1443
|
+
operation_id="list_operations",
|
|
1444
|
+
tags=["Operations"]
|
|
1490
1445
|
)
|
|
1491
1446
|
async def api_list_operations(bank_id: str):
|
|
1492
1447
|
"""List all async operations (pending and failed) for a memory bank."""
|
|
@@ -1530,7 +1485,8 @@ This operation cannot be undone.
|
|
|
1530
1485
|
"/v1/default/banks/{bank_id}/operations/{operation_id}",
|
|
1531
1486
|
summary="Cancel a pending async operation",
|
|
1532
1487
|
description="Cancel a pending async operation by removing it from the queue",
|
|
1533
|
-
operation_id="cancel_operation"
|
|
1488
|
+
operation_id="cancel_operation",
|
|
1489
|
+
tags=["Operations"]
|
|
1534
1490
|
)
|
|
1535
1491
|
async def api_cancel_operation(bank_id: str, operation_id: str):
|
|
1536
1492
|
"""Cancel a pending async operation."""
|
|
@@ -1580,7 +1536,8 @@ This operation cannot be undone.
|
|
|
1580
1536
|
response_model=BankProfileResponse,
|
|
1581
1537
|
summary="Get memory bank profile",
|
|
1582
1538
|
description="Get disposition traits and background for a memory bank. Auto-creates agent with defaults if not exists.",
|
|
1583
|
-
operation_id="get_bank_profile"
|
|
1539
|
+
operation_id="get_bank_profile",
|
|
1540
|
+
tags=["Banks"]
|
|
1584
1541
|
)
|
|
1585
1542
|
async def api_get_bank_profile(bank_id: str):
|
|
1586
1543
|
"""Get memory bank profile (disposition + background)."""
|
|
@@ -1605,8 +1562,9 @@ This operation cannot be undone.
|
|
|
1605
1562
|
"/v1/default/banks/{bank_id}/profile",
|
|
1606
1563
|
response_model=BankProfileResponse,
|
|
1607
1564
|
summary="Update memory bank disposition",
|
|
1608
|
-
description="Update bank's
|
|
1609
|
-
operation_id="update_bank_disposition"
|
|
1565
|
+
description="Update bank's disposition traits (skepticism, literalism, empathy)",
|
|
1566
|
+
operation_id="update_bank_disposition",
|
|
1567
|
+
tags=["Banks"]
|
|
1610
1568
|
)
|
|
1611
1569
|
async def api_update_bank_disposition(bank_id: str,
|
|
1612
1570
|
request: UpdateDispositionRequest
|
|
@@ -1640,7 +1598,8 @@ This operation cannot be undone.
|
|
|
1640
1598
|
response_model=BackgroundResponse,
|
|
1641
1599
|
summary="Add/merge memory bank background",
|
|
1642
1600
|
description="Add new background information or merge with existing. LLM intelligently resolves conflicts, normalizes to first person, and optionally infers disposition traits.",
|
|
1643
|
-
operation_id="add_bank_background"
|
|
1601
|
+
operation_id="add_bank_background",
|
|
1602
|
+
tags=["Banks"]
|
|
1644
1603
|
)
|
|
1645
1604
|
async def api_add_bank_background(bank_id: str,
|
|
1646
1605
|
request: AddBackgroundRequest
|
|
@@ -1670,7 +1629,8 @@ This operation cannot be undone.
|
|
|
1670
1629
|
response_model=BankProfileResponse,
|
|
1671
1630
|
summary="Create or update memory bank",
|
|
1672
1631
|
description="Create a new agent or update existing agent with disposition and background. Auto-fills missing fields with defaults.",
|
|
1673
|
-
operation_id="create_or_update_bank"
|
|
1632
|
+
operation_id="create_or_update_bank",
|
|
1633
|
+
tags=["Banks"]
|
|
1674
1634
|
)
|
|
1675
1635
|
async def api_create_or_update_bank(bank_id: str,
|
|
1676
1636
|
request: CreateBankRequest
|
|
@@ -1740,39 +1700,26 @@ This operation cannot be undone.
|
|
|
1740
1700
|
"/v1/default/banks/{bank_id}/memories",
|
|
1741
1701
|
response_model=RetainResponse,
|
|
1742
1702
|
summary="Retain memories",
|
|
1743
|
-
description=""
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
When async=true:
|
|
1765
|
-
- Returns immediately after queuing the task
|
|
1766
|
-
- Processing happens in the background
|
|
1767
|
-
- Use the operations endpoint to monitor progress
|
|
1768
|
-
|
|
1769
|
-
When async=false (default):
|
|
1770
|
-
- Waits for processing to complete
|
|
1771
|
-
- Returns after all memories are stored
|
|
1772
|
-
|
|
1773
|
-
Note: If a memory item has a document_id that already exists, the old document and its memory units will be deleted before creating new ones (upsert behavior). Items with the same document_id are grouped together for efficient processing.
|
|
1774
|
-
""",
|
|
1775
|
-
operation_id="retain_memories"
|
|
1703
|
+
description="Retain memory items with automatic fact extraction.\n\n"
|
|
1704
|
+
"This is the main endpoint for storing memories. It supports both synchronous and asynchronous processing via the `async` parameter.\n\n"
|
|
1705
|
+
"**Features:**\n"
|
|
1706
|
+
"- Efficient batch processing\n"
|
|
1707
|
+
"- Automatic fact extraction from natural language\n"
|
|
1708
|
+
"- Entity recognition and linking\n"
|
|
1709
|
+
"- Document tracking with automatic upsert (when document_id is provided)\n"
|
|
1710
|
+
"- Temporal and semantic linking\n"
|
|
1711
|
+
"- Optional asynchronous processing\n\n"
|
|
1712
|
+
"**The system automatically:**\n"
|
|
1713
|
+
"1. Extracts semantic facts from the content\n"
|
|
1714
|
+
"2. Generates embeddings\n"
|
|
1715
|
+
"3. Deduplicates similar facts\n"
|
|
1716
|
+
"4. Creates temporal, semantic, and entity links\n"
|
|
1717
|
+
"5. Tracks document metadata\n\n"
|
|
1718
|
+
"**When `async=true`:** Returns immediately after queuing. Use the operations endpoint to monitor progress.\n\n"
|
|
1719
|
+
"**When `async=false` (default):** Waits for processing to complete.\n\n"
|
|
1720
|
+
"**Note:** If a memory item has a `document_id` that already exists, the old document and its memory units will be deleted before creating new ones (upsert behavior).",
|
|
1721
|
+
operation_id="retain_memories",
|
|
1722
|
+
tags=["Memory"]
|
|
1776
1723
|
)
|
|
1777
1724
|
async def api_retain(bank_id: str, request: RetainRequest):
|
|
1778
1725
|
"""Retain memories with optional async processing."""
|
|
@@ -1813,7 +1760,7 @@ This operation cannot be undone.
|
|
|
1813
1760
|
|
|
1814
1761
|
# Submit task to background queue
|
|
1815
1762
|
await app.state.memory._task_backend.submit_task({
|
|
1816
|
-
'type': '
|
|
1763
|
+
'type': 'batch_retain',
|
|
1817
1764
|
'operation_id': str(operation_id),
|
|
1818
1765
|
'bank_id': bank_id,
|
|
1819
1766
|
'contents': contents
|
|
@@ -1852,8 +1799,9 @@ This operation cannot be undone.
|
|
|
1852
1799
|
"/v1/default/banks/{bank_id}/memories",
|
|
1853
1800
|
response_model=DeleteResponse,
|
|
1854
1801
|
summary="Clear memory bank memories",
|
|
1855
|
-
description="Delete memory units for a memory bank. Optionally filter by type (world, experience, opinion) to delete only specific types. This is a destructive operation that cannot be undone. The bank profile (
|
|
1856
|
-
operation_id="clear_bank_memories"
|
|
1802
|
+
description="Delete memory units for a memory bank. Optionally filter by type (world, experience, opinion) to delete only specific types. This is a destructive operation that cannot be undone. The bank profile (disposition and background) will be preserved.",
|
|
1803
|
+
operation_id="clear_bank_memories",
|
|
1804
|
+
tags=["Memory"]
|
|
1857
1805
|
)
|
|
1858
1806
|
async def api_clear_bank_memories(bank_id: str,
|
|
1859
1807
|
type: Optional[str] = Query(None, description="Optional fact type filter (world, experience, opinion)")
|
hindsight_api/api/mcp.py
CHANGED
|
@@ -8,6 +8,7 @@ from typing import Optional
|
|
|
8
8
|
|
|
9
9
|
from fastmcp import FastMCP
|
|
10
10
|
from hindsight_api import MemoryEngine
|
|
11
|
+
from hindsight_api.engine.response_models import VALID_RECALL_FACT_TYPES
|
|
11
12
|
|
|
12
13
|
# Configure logging from HINDSIGHT_API_LOG_LEVEL environment variable
|
|
13
14
|
_log_level_str = os.environ.get("HINDSIGHT_API_LOG_LEVEL", "info").lower()
|
|
@@ -90,7 +91,7 @@ def create_mcp_server(memory: MemoryEngine) -> FastMCP:
|
|
|
90
91
|
search_result = await memory.recall_async(
|
|
91
92
|
bank_id=bank_id,
|
|
92
93
|
query=query,
|
|
93
|
-
fact_type=
|
|
94
|
+
fact_type=list(VALID_RECALL_FACT_TYPES),
|
|
94
95
|
budget=Budget.LOW
|
|
95
96
|
)
|
|
96
97
|
|