hindsight-api 0.1.0__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/PKG-INFO +1 -1
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/__init__.py +10 -2
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/api/http.py +84 -86
- hindsight_api-0.1.2/hindsight_api/config.py +154 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/__init__.py +7 -2
- hindsight_api-0.1.2/hindsight_api/engine/cross_encoder.py +306 -0
- hindsight_api-0.1.2/hindsight_api/engine/embeddings.py +292 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/llm_wrapper.py +88 -139
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/memory_engine.py +71 -51
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/bank_utils.py +2 -2
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/fact_extraction.py +1 -1
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/reranking.py +6 -10
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/tracer.py +1 -1
- hindsight_api-0.1.2/hindsight_api/main.py +201 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/migrations.py +7 -7
- hindsight_api-0.1.2/hindsight_api/server.py +43 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/pyproject.toml +16 -2
- hindsight_api-0.1.0/hindsight_api/cli.py +0 -127
- hindsight_api-0.1.0/hindsight_api/engine/cross_encoder.py +0 -102
- hindsight_api-0.1.0/hindsight_api/engine/embeddings.py +0 -118
- hindsight_api-0.1.0/hindsight_api/web/__init__.py +0 -12
- hindsight_api-0.1.0/hindsight_api/web/server.py +0 -109
- hindsight_api-0.1.0/test_chunks_debug.py +0 -46
- hindsight_api-0.1.0/test_mentioned_at.py +0 -69
- hindsight_api-0.1.0/tests/__init__.py +0 -1
- hindsight_api-0.1.0/tests/conftest.py +0 -164
- hindsight_api-0.1.0/tests/fixtures/README.md +0 -19
- hindsight_api-0.1.0/tests/fixtures/locomo_conversation_sample.json +0 -5271
- hindsight_api-0.1.0/tests/test_agents_api.py +0 -245
- hindsight_api-0.1.0/tests/test_batch_chunking.py +0 -58
- hindsight_api-0.1.0/tests/test_chunking.py +0 -56
- hindsight_api-0.1.0/tests/test_document_tracking.py +0 -131
- hindsight_api-0.1.0/tests/test_fact_extraction_quality.py +0 -1050
- hindsight_api-0.1.0/tests/test_fact_ordering.py +0 -180
- hindsight_api-0.1.0/tests/test_http_api_integration.py +0 -427
- hindsight_api-0.1.0/tests/test_link_utils.py +0 -256
- hindsight_api-0.1.0/tests/test_mcp_api_integration.py +0 -177
- hindsight_api-0.1.0/tests/test_mcp_routing.py +0 -98
- hindsight_api-0.1.0/tests/test_observations.py +0 -497
- hindsight_api-0.1.0/tests/test_query_analyzer.py +0 -285
- hindsight_api-0.1.0/tests/test_retain.py +0 -1597
- hindsight_api-0.1.0/tests/test_search_trace.py +0 -140
- hindsight_api-0.1.0/tests/test_temporal_ranges.py +0 -135
- hindsight_api-0.1.0/tests/test_think.py +0 -150
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/.gitignore +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/README.md +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/README +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/env.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/script.py.mako +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/5a366d414dce_initial_schema.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/rename_personality_to_disposition.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/api/__init__.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/api/mcp.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/db_utils.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/entity_resolver.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/query_analyzer.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/response_models.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/__init__.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/chunk_storage.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/deduplication.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/embedding_processing.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/embedding_utils.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/entity_processing.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/fact_storage.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/link_creation.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/link_utils.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/observation_regeneration.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/orchestrator.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/types.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/__init__.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/fusion.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/observation_utils.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/retrieval.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/scoring.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/temporal_extraction.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/think_utils.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/trace.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/types.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/task_backend.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/utils.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/metrics.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/models.py +0 -0
- {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/pg0.py +0 -0
|
@@ -16,11 +16,15 @@ from .engine.search.trace import (
|
|
|
16
16
|
SearchPhaseMetrics,
|
|
17
17
|
)
|
|
18
18
|
from .engine.search.tracer import SearchTracer
|
|
19
|
-
from .engine.embeddings import Embeddings,
|
|
19
|
+
from .engine.embeddings import Embeddings, LocalSTEmbeddings, RemoteTEIEmbeddings
|
|
20
|
+
from .engine.cross_encoder import CrossEncoderModel, LocalSTCrossEncoder, RemoteTEICrossEncoder
|
|
20
21
|
from .engine.llm_wrapper import LLMConfig
|
|
22
|
+
from .config import HindsightConfig, get_config
|
|
21
23
|
|
|
22
24
|
__all__ = [
|
|
23
25
|
"MemoryEngine",
|
|
26
|
+
"HindsightConfig",
|
|
27
|
+
"get_config",
|
|
24
28
|
"SearchTrace",
|
|
25
29
|
"SearchTracer",
|
|
26
30
|
"QueryInfo",
|
|
@@ -32,7 +36,11 @@ __all__ = [
|
|
|
32
36
|
"SearchSummary",
|
|
33
37
|
"SearchPhaseMetrics",
|
|
34
38
|
"Embeddings",
|
|
35
|
-
"
|
|
39
|
+
"LocalSTEmbeddings",
|
|
40
|
+
"RemoteTEIEmbeddings",
|
|
41
|
+
"CrossEncoderModel",
|
|
42
|
+
"LocalSTCrossEncoder",
|
|
43
|
+
"RemoteTEICrossEncoder",
|
|
36
44
|
"LLMConfig",
|
|
37
45
|
]
|
|
38
46
|
__version__ = "0.1.0"
|
|
@@ -729,9 +729,11 @@ def create_app(memory: MemoryEngine, initialize_memory: bool = True) -> FastAPI:
|
|
|
729
729
|
await memory.close()
|
|
730
730
|
logging.info("Memory system closed")
|
|
731
731
|
|
|
732
|
+
from hindsight_api import __version__
|
|
733
|
+
|
|
732
734
|
app = FastAPI(
|
|
733
735
|
title="Hindsight HTTP API",
|
|
734
|
-
version=
|
|
736
|
+
version=__version__,
|
|
735
737
|
description="HTTP API for Hindsight",
|
|
736
738
|
contact={
|
|
737
739
|
"name": "Memory System",
|
|
@@ -793,7 +795,8 @@ def _register_routes(app: FastAPI):
|
|
|
793
795
|
response_model=GraphDataResponse,
|
|
794
796
|
summary="Get memory graph data",
|
|
795
797
|
description="Retrieve graph data for visualization, optionally filtered by type (world/experience/opinion). Limited to 1000 most recent items.",
|
|
796
|
-
operation_id="get_graph"
|
|
798
|
+
operation_id="get_graph",
|
|
799
|
+
tags=["Memory"]
|
|
797
800
|
)
|
|
798
801
|
async def api_graph(bank_id: str,
|
|
799
802
|
type: Optional[str] = None
|
|
@@ -814,7 +817,8 @@ def _register_routes(app: FastAPI):
|
|
|
814
817
|
response_model=ListMemoryUnitsResponse,
|
|
815
818
|
summary="List memory units",
|
|
816
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).",
|
|
817
|
-
operation_id="list_memories"
|
|
820
|
+
operation_id="list_memories",
|
|
821
|
+
tags=["Memory"]
|
|
818
822
|
)
|
|
819
823
|
async def api_list(bank_id: str,
|
|
820
824
|
type: Optional[str] = None,
|
|
@@ -855,17 +859,14 @@ def _register_routes(app: FastAPI):
|
|
|
855
859
|
"/v1/default/banks/{bank_id}/memories/recall",
|
|
856
860
|
response_model=RecallResponse,
|
|
857
861
|
summary="Recall memory",
|
|
858
|
-
description=""
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
Set include_entities=true to get entity observations alongside recall results.
|
|
867
|
-
""",
|
|
868
|
-
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"]
|
|
869
870
|
)
|
|
870
871
|
async def api_recall(bank_id: str, request: RecallRequest):
|
|
871
872
|
"""Run a recall and return results with trace."""
|
|
@@ -972,18 +973,16 @@ def _register_routes(app: FastAPI):
|
|
|
972
973
|
"/v1/default/banks/{bank_id}/reflect",
|
|
973
974
|
response_model=ReflectResponse,
|
|
974
975
|
summary="Reflect and generate answer",
|
|
975
|
-
description=""
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
""",
|
|
986
|
-
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"]
|
|
987
986
|
)
|
|
988
987
|
async def api_reflect(bank_id: str, request: ReflectRequest):
|
|
989
988
|
metrics = get_metrics_collector()
|
|
@@ -1029,7 +1028,8 @@ def _register_routes(app: FastAPI):
|
|
|
1029
1028
|
response_model=BankListResponse,
|
|
1030
1029
|
summary="List all memory banks",
|
|
1031
1030
|
description="Get a list of all agents with their profiles",
|
|
1032
|
-
operation_id="list_banks"
|
|
1031
|
+
operation_id="list_banks",
|
|
1032
|
+
tags=["Banks"]
|
|
1033
1033
|
)
|
|
1034
1034
|
async def api_list_banks():
|
|
1035
1035
|
"""Get list of all banks with their profiles."""
|
|
@@ -1046,7 +1046,8 @@ def _register_routes(app: FastAPI):
|
|
|
1046
1046
|
"/v1/default/banks/{bank_id}/stats",
|
|
1047
1047
|
summary="Get statistics for memory bank",
|
|
1048
1048
|
description="Get statistics about nodes and links for a specific agent",
|
|
1049
|
-
operation_id="get_agent_stats"
|
|
1049
|
+
operation_id="get_agent_stats",
|
|
1050
|
+
tags=["Banks"]
|
|
1050
1051
|
)
|
|
1051
1052
|
async def api_stats(bank_id: str):
|
|
1052
1053
|
"""Get statistics about memory nodes and links for a memory bank."""
|
|
@@ -1167,7 +1168,8 @@ def _register_routes(app: FastAPI):
|
|
|
1167
1168
|
response_model=EntityListResponse,
|
|
1168
1169
|
summary="List entities",
|
|
1169
1170
|
description="List all entities (people, organizations, etc.) known by the bank, ordered by mention count.",
|
|
1170
|
-
operation_id="list_entities"
|
|
1171
|
+
operation_id="list_entities",
|
|
1172
|
+
tags=["Entities"]
|
|
1171
1173
|
)
|
|
1172
1174
|
async def api_list_entities(bank_id: str,
|
|
1173
1175
|
limit: int = Query(default=100, description="Maximum number of entities to return")
|
|
@@ -1189,7 +1191,8 @@ def _register_routes(app: FastAPI):
|
|
|
1189
1191
|
response_model=EntityDetailResponse,
|
|
1190
1192
|
summary="Get entity details",
|
|
1191
1193
|
description="Get detailed information about an entity including observations (mental model).",
|
|
1192
|
-
operation_id="get_entity"
|
|
1194
|
+
operation_id="get_entity",
|
|
1195
|
+
tags=["Entities"]
|
|
1193
1196
|
)
|
|
1194
1197
|
async def api_get_entity(bank_id: str, entity_id: str):
|
|
1195
1198
|
"""Get entity details with observations."""
|
|
@@ -1239,7 +1242,8 @@ def _register_routes(app: FastAPI):
|
|
|
1239
1242
|
response_model=EntityDetailResponse,
|
|
1240
1243
|
summary="Regenerate entity observations",
|
|
1241
1244
|
description="Regenerate observations for an entity based on all facts mentioning it.",
|
|
1242
|
-
operation_id="regenerate_entity_observations"
|
|
1245
|
+
operation_id="regenerate_entity_observations",
|
|
1246
|
+
tags=["Entities"]
|
|
1243
1247
|
)
|
|
1244
1248
|
async def api_regenerate_entity_observations(bank_id: str, entity_id: str):
|
|
1245
1249
|
"""Regenerate observations for an entity."""
|
|
@@ -1296,7 +1300,8 @@ def _register_routes(app: FastAPI):
|
|
|
1296
1300
|
response_model=ListDocumentsResponse,
|
|
1297
1301
|
summary="List documents",
|
|
1298
1302
|
description="List documents with pagination and optional search. Documents are the source content from which memory units are extracted.",
|
|
1299
|
-
operation_id="list_documents"
|
|
1303
|
+
operation_id="list_documents",
|
|
1304
|
+
tags=["Documents"]
|
|
1300
1305
|
)
|
|
1301
1306
|
async def api_list_documents(bank_id: str,
|
|
1302
1307
|
q: Optional[str] = None,
|
|
@@ -1332,7 +1337,8 @@ def _register_routes(app: FastAPI):
|
|
|
1332
1337
|
response_model=DocumentResponse,
|
|
1333
1338
|
summary="Get document details",
|
|
1334
1339
|
description="Get a specific document including its original text",
|
|
1335
|
-
operation_id="get_document"
|
|
1340
|
+
operation_id="get_document",
|
|
1341
|
+
tags=["Documents"]
|
|
1336
1342
|
)
|
|
1337
1343
|
async def api_get_document(bank_id: str,
|
|
1338
1344
|
document_id: str
|
|
@@ -1363,7 +1369,8 @@ def _register_routes(app: FastAPI):
|
|
|
1363
1369
|
response_model=ChunkResponse,
|
|
1364
1370
|
summary="Get chunk details",
|
|
1365
1371
|
description="Get a specific chunk by its ID",
|
|
1366
|
-
operation_id="get_chunk"
|
|
1372
|
+
operation_id="get_chunk",
|
|
1373
|
+
tags=["Documents"]
|
|
1367
1374
|
)
|
|
1368
1375
|
async def api_get_chunk(chunk_id: str):
|
|
1369
1376
|
"""
|
|
@@ -1389,17 +1396,14 @@ def _register_routes(app: FastAPI):
|
|
|
1389
1396
|
@app.delete(
|
|
1390
1397
|
"/v1/default/banks/{bank_id}/documents/{document_id}",
|
|
1391
1398
|
summary="Delete a document",
|
|
1392
|
-
description=""
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
This operation cannot be undone.
|
|
1401
|
-
""",
|
|
1402
|
-
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"]
|
|
1403
1407
|
)
|
|
1404
1408
|
async def api_delete_document(bank_id: str,
|
|
1405
1409
|
document_id: str
|
|
@@ -1436,7 +1440,8 @@ This operation cannot be undone.
|
|
|
1436
1440
|
"/v1/default/banks/{bank_id}/operations",
|
|
1437
1441
|
summary="List async operations",
|
|
1438
1442
|
description="Get a list of all async operations (pending and failed) for a specific agent, including error messages for failed operations",
|
|
1439
|
-
operation_id="list_operations"
|
|
1443
|
+
operation_id="list_operations",
|
|
1444
|
+
tags=["Operations"]
|
|
1440
1445
|
)
|
|
1441
1446
|
async def api_list_operations(bank_id: str):
|
|
1442
1447
|
"""List all async operations (pending and failed) for a memory bank."""
|
|
@@ -1480,7 +1485,8 @@ This operation cannot be undone.
|
|
|
1480
1485
|
"/v1/default/banks/{bank_id}/operations/{operation_id}",
|
|
1481
1486
|
summary="Cancel a pending async operation",
|
|
1482
1487
|
description="Cancel a pending async operation by removing it from the queue",
|
|
1483
|
-
operation_id="cancel_operation"
|
|
1488
|
+
operation_id="cancel_operation",
|
|
1489
|
+
tags=["Operations"]
|
|
1484
1490
|
)
|
|
1485
1491
|
async def api_cancel_operation(bank_id: str, operation_id: str):
|
|
1486
1492
|
"""Cancel a pending async operation."""
|
|
@@ -1530,7 +1536,8 @@ This operation cannot be undone.
|
|
|
1530
1536
|
response_model=BankProfileResponse,
|
|
1531
1537
|
summary="Get memory bank profile",
|
|
1532
1538
|
description="Get disposition traits and background for a memory bank. Auto-creates agent with defaults if not exists.",
|
|
1533
|
-
operation_id="get_bank_profile"
|
|
1539
|
+
operation_id="get_bank_profile",
|
|
1540
|
+
tags=["Banks"]
|
|
1534
1541
|
)
|
|
1535
1542
|
async def api_get_bank_profile(bank_id: str):
|
|
1536
1543
|
"""Get memory bank profile (disposition + background)."""
|
|
@@ -1556,7 +1563,8 @@ This operation cannot be undone.
|
|
|
1556
1563
|
response_model=BankProfileResponse,
|
|
1557
1564
|
summary="Update memory bank disposition",
|
|
1558
1565
|
description="Update bank's disposition traits (skepticism, literalism, empathy)",
|
|
1559
|
-
operation_id="update_bank_disposition"
|
|
1566
|
+
operation_id="update_bank_disposition",
|
|
1567
|
+
tags=["Banks"]
|
|
1560
1568
|
)
|
|
1561
1569
|
async def api_update_bank_disposition(bank_id: str,
|
|
1562
1570
|
request: UpdateDispositionRequest
|
|
@@ -1590,7 +1598,8 @@ This operation cannot be undone.
|
|
|
1590
1598
|
response_model=BackgroundResponse,
|
|
1591
1599
|
summary="Add/merge memory bank background",
|
|
1592
1600
|
description="Add new background information or merge with existing. LLM intelligently resolves conflicts, normalizes to first person, and optionally infers disposition traits.",
|
|
1593
|
-
operation_id="add_bank_background"
|
|
1601
|
+
operation_id="add_bank_background",
|
|
1602
|
+
tags=["Banks"]
|
|
1594
1603
|
)
|
|
1595
1604
|
async def api_add_bank_background(bank_id: str,
|
|
1596
1605
|
request: AddBackgroundRequest
|
|
@@ -1620,7 +1629,8 @@ This operation cannot be undone.
|
|
|
1620
1629
|
response_model=BankProfileResponse,
|
|
1621
1630
|
summary="Create or update memory bank",
|
|
1622
1631
|
description="Create a new agent or update existing agent with disposition and background. Auto-fills missing fields with defaults.",
|
|
1623
|
-
operation_id="create_or_update_bank"
|
|
1632
|
+
operation_id="create_or_update_bank",
|
|
1633
|
+
tags=["Banks"]
|
|
1624
1634
|
)
|
|
1625
1635
|
async def api_create_or_update_bank(bank_id: str,
|
|
1626
1636
|
request: CreateBankRequest
|
|
@@ -1690,39 +1700,26 @@ This operation cannot be undone.
|
|
|
1690
1700
|
"/v1/default/banks/{bank_id}/memories",
|
|
1691
1701
|
response_model=RetainResponse,
|
|
1692
1702
|
summary="Retain memories",
|
|
1693
|
-
description=""
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
When async=true:
|
|
1715
|
-
- Returns immediately after queuing the task
|
|
1716
|
-
- Processing happens in the background
|
|
1717
|
-
- Use the operations endpoint to monitor progress
|
|
1718
|
-
|
|
1719
|
-
When async=false (default):
|
|
1720
|
-
- Waits for processing to complete
|
|
1721
|
-
- Returns after all memories are stored
|
|
1722
|
-
|
|
1723
|
-
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.
|
|
1724
|
-
""",
|
|
1725
|
-
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"]
|
|
1726
1723
|
)
|
|
1727
1724
|
async def api_retain(bank_id: str, request: RetainRequest):
|
|
1728
1725
|
"""Retain memories with optional async processing."""
|
|
@@ -1763,7 +1760,7 @@ This operation cannot be undone.
|
|
|
1763
1760
|
|
|
1764
1761
|
# Submit task to background queue
|
|
1765
1762
|
await app.state.memory._task_backend.submit_task({
|
|
1766
|
-
'type': '
|
|
1763
|
+
'type': 'batch_retain',
|
|
1767
1764
|
'operation_id': str(operation_id),
|
|
1768
1765
|
'bank_id': bank_id,
|
|
1769
1766
|
'contents': contents
|
|
@@ -1803,7 +1800,8 @@ This operation cannot be undone.
|
|
|
1803
1800
|
response_model=DeleteResponse,
|
|
1804
1801
|
summary="Clear memory bank memories",
|
|
1805
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.",
|
|
1806
|
-
operation_id="clear_bank_memories"
|
|
1803
|
+
operation_id="clear_bank_memories",
|
|
1804
|
+
tags=["Memory"]
|
|
1807
1805
|
)
|
|
1808
1806
|
async def api_clear_bank_memories(bank_id: str,
|
|
1809
1807
|
type: Optional[str] = Query(None, description="Optional fact type filter (world, experience, opinion)")
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Centralized configuration for Hindsight API.
|
|
3
|
+
|
|
4
|
+
All environment variables and their defaults are defined here.
|
|
5
|
+
"""
|
|
6
|
+
import os
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Optional
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
# Environment variable names
|
|
14
|
+
ENV_DATABASE_URL = "HINDSIGHT_API_DATABASE_URL"
|
|
15
|
+
ENV_LLM_PROVIDER = "HINDSIGHT_API_LLM_PROVIDER"
|
|
16
|
+
ENV_LLM_API_KEY = "HINDSIGHT_API_LLM_API_KEY"
|
|
17
|
+
ENV_LLM_MODEL = "HINDSIGHT_API_LLM_MODEL"
|
|
18
|
+
ENV_LLM_BASE_URL = "HINDSIGHT_API_LLM_BASE_URL"
|
|
19
|
+
|
|
20
|
+
ENV_EMBEDDINGS_PROVIDER = "HINDSIGHT_API_EMBEDDINGS_PROVIDER"
|
|
21
|
+
ENV_EMBEDDINGS_LOCAL_MODEL = "HINDSIGHT_API_EMBEDDINGS_LOCAL_MODEL"
|
|
22
|
+
ENV_EMBEDDINGS_TEI_URL = "HINDSIGHT_API_EMBEDDINGS_TEI_URL"
|
|
23
|
+
|
|
24
|
+
ENV_RERANKER_PROVIDER = "HINDSIGHT_API_RERANKER_PROVIDER"
|
|
25
|
+
ENV_RERANKER_LOCAL_MODEL = "HINDSIGHT_API_RERANKER_LOCAL_MODEL"
|
|
26
|
+
ENV_RERANKER_TEI_URL = "HINDSIGHT_API_RERANKER_TEI_URL"
|
|
27
|
+
|
|
28
|
+
ENV_HOST = "HINDSIGHT_API_HOST"
|
|
29
|
+
ENV_PORT = "HINDSIGHT_API_PORT"
|
|
30
|
+
ENV_LOG_LEVEL = "HINDSIGHT_API_LOG_LEVEL"
|
|
31
|
+
ENV_MCP_ENABLED = "HINDSIGHT_API_MCP_ENABLED"
|
|
32
|
+
|
|
33
|
+
# Default values
|
|
34
|
+
DEFAULT_DATABASE_URL = "pg0"
|
|
35
|
+
DEFAULT_LLM_PROVIDER = "groq"
|
|
36
|
+
DEFAULT_LLM_MODEL = "openai/gpt-oss-20b"
|
|
37
|
+
|
|
38
|
+
DEFAULT_EMBEDDINGS_PROVIDER = "local"
|
|
39
|
+
DEFAULT_EMBEDDINGS_LOCAL_MODEL = "BAAI/bge-small-en-v1.5"
|
|
40
|
+
|
|
41
|
+
DEFAULT_RERANKER_PROVIDER = "local"
|
|
42
|
+
DEFAULT_RERANKER_LOCAL_MODEL = "cross-encoder/ms-marco-MiniLM-L-6-v2"
|
|
43
|
+
|
|
44
|
+
DEFAULT_HOST = "0.0.0.0"
|
|
45
|
+
DEFAULT_PORT = 8888
|
|
46
|
+
DEFAULT_LOG_LEVEL = "info"
|
|
47
|
+
DEFAULT_MCP_ENABLED = True
|
|
48
|
+
|
|
49
|
+
# Required embedding dimension for database schema
|
|
50
|
+
EMBEDDING_DIMENSION = 384
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class HindsightConfig:
|
|
55
|
+
"""Configuration container for Hindsight API."""
|
|
56
|
+
|
|
57
|
+
# Database
|
|
58
|
+
database_url: str
|
|
59
|
+
|
|
60
|
+
# LLM
|
|
61
|
+
llm_provider: str
|
|
62
|
+
llm_api_key: Optional[str]
|
|
63
|
+
llm_model: str
|
|
64
|
+
llm_base_url: Optional[str]
|
|
65
|
+
|
|
66
|
+
# Embeddings
|
|
67
|
+
embeddings_provider: str
|
|
68
|
+
embeddings_local_model: str
|
|
69
|
+
embeddings_tei_url: Optional[str]
|
|
70
|
+
|
|
71
|
+
# Reranker
|
|
72
|
+
reranker_provider: str
|
|
73
|
+
reranker_local_model: str
|
|
74
|
+
reranker_tei_url: Optional[str]
|
|
75
|
+
|
|
76
|
+
# Server
|
|
77
|
+
host: str
|
|
78
|
+
port: int
|
|
79
|
+
log_level: str
|
|
80
|
+
mcp_enabled: bool
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def from_env(cls) -> "HindsightConfig":
|
|
84
|
+
"""Create configuration from environment variables."""
|
|
85
|
+
return cls(
|
|
86
|
+
# Database
|
|
87
|
+
database_url=os.getenv(ENV_DATABASE_URL, DEFAULT_DATABASE_URL),
|
|
88
|
+
|
|
89
|
+
# LLM
|
|
90
|
+
llm_provider=os.getenv(ENV_LLM_PROVIDER, DEFAULT_LLM_PROVIDER),
|
|
91
|
+
llm_api_key=os.getenv(ENV_LLM_API_KEY),
|
|
92
|
+
llm_model=os.getenv(ENV_LLM_MODEL, DEFAULT_LLM_MODEL),
|
|
93
|
+
llm_base_url=os.getenv(ENV_LLM_BASE_URL) or None,
|
|
94
|
+
|
|
95
|
+
# Embeddings
|
|
96
|
+
embeddings_provider=os.getenv(ENV_EMBEDDINGS_PROVIDER, DEFAULT_EMBEDDINGS_PROVIDER),
|
|
97
|
+
embeddings_local_model=os.getenv(ENV_EMBEDDINGS_LOCAL_MODEL, DEFAULT_EMBEDDINGS_LOCAL_MODEL),
|
|
98
|
+
embeddings_tei_url=os.getenv(ENV_EMBEDDINGS_TEI_URL),
|
|
99
|
+
|
|
100
|
+
# Reranker
|
|
101
|
+
reranker_provider=os.getenv(ENV_RERANKER_PROVIDER, DEFAULT_RERANKER_PROVIDER),
|
|
102
|
+
reranker_local_model=os.getenv(ENV_RERANKER_LOCAL_MODEL, DEFAULT_RERANKER_LOCAL_MODEL),
|
|
103
|
+
reranker_tei_url=os.getenv(ENV_RERANKER_TEI_URL),
|
|
104
|
+
|
|
105
|
+
# Server
|
|
106
|
+
host=os.getenv(ENV_HOST, DEFAULT_HOST),
|
|
107
|
+
port=int(os.getenv(ENV_PORT, DEFAULT_PORT)),
|
|
108
|
+
log_level=os.getenv(ENV_LOG_LEVEL, DEFAULT_LOG_LEVEL),
|
|
109
|
+
mcp_enabled=os.getenv(ENV_MCP_ENABLED, str(DEFAULT_MCP_ENABLED)).lower() == "true",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def get_llm_base_url(self) -> str:
|
|
113
|
+
"""Get the LLM base URL, with provider-specific defaults."""
|
|
114
|
+
if self.llm_base_url:
|
|
115
|
+
return self.llm_base_url
|
|
116
|
+
|
|
117
|
+
provider = self.llm_provider.lower()
|
|
118
|
+
if provider == "groq":
|
|
119
|
+
return "https://api.groq.com/openai/v1"
|
|
120
|
+
elif provider == "ollama":
|
|
121
|
+
return "http://localhost:11434/v1"
|
|
122
|
+
else:
|
|
123
|
+
return ""
|
|
124
|
+
|
|
125
|
+
def get_python_log_level(self) -> int:
|
|
126
|
+
"""Get the Python logging level from the configured log level string."""
|
|
127
|
+
log_level_map = {
|
|
128
|
+
"critical": logging.CRITICAL,
|
|
129
|
+
"error": logging.ERROR,
|
|
130
|
+
"warning": logging.WARNING,
|
|
131
|
+
"info": logging.INFO,
|
|
132
|
+
"debug": logging.DEBUG,
|
|
133
|
+
"trace": logging.DEBUG, # Python doesn't have TRACE, use DEBUG
|
|
134
|
+
}
|
|
135
|
+
return log_level_map.get(self.log_level.lower(), logging.INFO)
|
|
136
|
+
|
|
137
|
+
def configure_logging(self) -> None:
|
|
138
|
+
"""Configure Python logging based on the log level."""
|
|
139
|
+
logging.basicConfig(
|
|
140
|
+
level=self.get_python_log_level(),
|
|
141
|
+
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def log_config(self) -> None:
|
|
145
|
+
"""Log the current configuration (without sensitive values)."""
|
|
146
|
+
logger.info(f"Database: {self.database_url}")
|
|
147
|
+
logger.info(f"LLM: provider={self.llm_provider}, model={self.llm_model}")
|
|
148
|
+
logger.info(f"Embeddings: provider={self.embeddings_provider}")
|
|
149
|
+
logger.info(f"Reranker: provider={self.reranker_provider}")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_config() -> HindsightConfig:
|
|
153
|
+
"""Get the current configuration from environment variables."""
|
|
154
|
+
return HindsightConfig.from_env()
|
|
@@ -9,7 +9,8 @@ This package contains all the implementation details of the memory engine:
|
|
|
9
9
|
|
|
10
10
|
from .memory_engine import MemoryEngine
|
|
11
11
|
from .db_utils import acquire_with_retry
|
|
12
|
-
from .embeddings import Embeddings,
|
|
12
|
+
from .embeddings import Embeddings, LocalSTEmbeddings, RemoteTEIEmbeddings
|
|
13
|
+
from .cross_encoder import CrossEncoderModel, LocalSTCrossEncoder, RemoteTEICrossEncoder
|
|
13
14
|
from .search.trace import (
|
|
14
15
|
SearchTrace,
|
|
15
16
|
QueryInfo,
|
|
@@ -29,7 +30,11 @@ __all__ = [
|
|
|
29
30
|
"MemoryEngine",
|
|
30
31
|
"acquire_with_retry",
|
|
31
32
|
"Embeddings",
|
|
32
|
-
"
|
|
33
|
+
"LocalSTEmbeddings",
|
|
34
|
+
"RemoteTEIEmbeddings",
|
|
35
|
+
"CrossEncoderModel",
|
|
36
|
+
"LocalSTCrossEncoder",
|
|
37
|
+
"RemoteTEICrossEncoder",
|
|
33
38
|
"SearchTrace",
|
|
34
39
|
"SearchTracer",
|
|
35
40
|
"QueryInfo",
|