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.
Files changed (87) hide show
  1. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/PKG-INFO +1 -1
  2. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/__init__.py +10 -2
  3. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/api/http.py +84 -86
  4. hindsight_api-0.1.2/hindsight_api/config.py +154 -0
  5. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/__init__.py +7 -2
  6. hindsight_api-0.1.2/hindsight_api/engine/cross_encoder.py +306 -0
  7. hindsight_api-0.1.2/hindsight_api/engine/embeddings.py +292 -0
  8. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/llm_wrapper.py +88 -139
  9. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/memory_engine.py +71 -51
  10. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/bank_utils.py +2 -2
  11. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/fact_extraction.py +1 -1
  12. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/reranking.py +6 -10
  13. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/tracer.py +1 -1
  14. hindsight_api-0.1.2/hindsight_api/main.py +201 -0
  15. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/migrations.py +7 -7
  16. hindsight_api-0.1.2/hindsight_api/server.py +43 -0
  17. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/pyproject.toml +16 -2
  18. hindsight_api-0.1.0/hindsight_api/cli.py +0 -127
  19. hindsight_api-0.1.0/hindsight_api/engine/cross_encoder.py +0 -102
  20. hindsight_api-0.1.0/hindsight_api/engine/embeddings.py +0 -118
  21. hindsight_api-0.1.0/hindsight_api/web/__init__.py +0 -12
  22. hindsight_api-0.1.0/hindsight_api/web/server.py +0 -109
  23. hindsight_api-0.1.0/test_chunks_debug.py +0 -46
  24. hindsight_api-0.1.0/test_mentioned_at.py +0 -69
  25. hindsight_api-0.1.0/tests/__init__.py +0 -1
  26. hindsight_api-0.1.0/tests/conftest.py +0 -164
  27. hindsight_api-0.1.0/tests/fixtures/README.md +0 -19
  28. hindsight_api-0.1.0/tests/fixtures/locomo_conversation_sample.json +0 -5271
  29. hindsight_api-0.1.0/tests/test_agents_api.py +0 -245
  30. hindsight_api-0.1.0/tests/test_batch_chunking.py +0 -58
  31. hindsight_api-0.1.0/tests/test_chunking.py +0 -56
  32. hindsight_api-0.1.0/tests/test_document_tracking.py +0 -131
  33. hindsight_api-0.1.0/tests/test_fact_extraction_quality.py +0 -1050
  34. hindsight_api-0.1.0/tests/test_fact_ordering.py +0 -180
  35. hindsight_api-0.1.0/tests/test_http_api_integration.py +0 -427
  36. hindsight_api-0.1.0/tests/test_link_utils.py +0 -256
  37. hindsight_api-0.1.0/tests/test_mcp_api_integration.py +0 -177
  38. hindsight_api-0.1.0/tests/test_mcp_routing.py +0 -98
  39. hindsight_api-0.1.0/tests/test_observations.py +0 -497
  40. hindsight_api-0.1.0/tests/test_query_analyzer.py +0 -285
  41. hindsight_api-0.1.0/tests/test_retain.py +0 -1597
  42. hindsight_api-0.1.0/tests/test_search_trace.py +0 -140
  43. hindsight_api-0.1.0/tests/test_temporal_ranges.py +0 -135
  44. hindsight_api-0.1.0/tests/test_think.py +0 -150
  45. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/.gitignore +0 -0
  46. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/README.md +0 -0
  47. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/README +0 -0
  48. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/env.py +0 -0
  49. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/script.py.mako +0 -0
  50. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/5a366d414dce_initial_schema.py +0 -0
  51. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py +0 -0
  52. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py +0 -0
  53. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py +0 -0
  54. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py +0 -0
  55. {hindsight_api-0.1.0 → hindsight_api-0.1.2/hindsight_api}/alembic/versions/rename_personality_to_disposition.py +0 -0
  56. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/api/__init__.py +0 -0
  57. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/api/mcp.py +0 -0
  58. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/db_utils.py +0 -0
  59. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/entity_resolver.py +0 -0
  60. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/query_analyzer.py +0 -0
  61. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/response_models.py +0 -0
  62. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/__init__.py +0 -0
  63. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/chunk_storage.py +0 -0
  64. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/deduplication.py +0 -0
  65. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/embedding_processing.py +0 -0
  66. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/embedding_utils.py +0 -0
  67. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/entity_processing.py +0 -0
  68. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/fact_storage.py +0 -0
  69. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/link_creation.py +0 -0
  70. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/link_utils.py +0 -0
  71. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/observation_regeneration.py +0 -0
  72. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/orchestrator.py +0 -0
  73. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/retain/types.py +0 -0
  74. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/__init__.py +0 -0
  75. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/fusion.py +0 -0
  76. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/observation_utils.py +0 -0
  77. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/retrieval.py +0 -0
  78. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/scoring.py +0 -0
  79. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/temporal_extraction.py +0 -0
  80. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/think_utils.py +0 -0
  81. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/trace.py +0 -0
  82. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/search/types.py +0 -0
  83. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/task_backend.py +0 -0
  84. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/engine/utils.py +0 -0
  85. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/metrics.py +0 -0
  86. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/models.py +0 -0
  87. {hindsight_api-0.1.0 → hindsight_api-0.1.2}/hindsight_api/pg0.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hindsight-api
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Temporal + Semantic + Entity Memory System for AI agents using PostgreSQL
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: alembic>=1.17.1
@@ -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, SentenceTransformersEmbeddings
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
- "SentenceTransformersEmbeddings",
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="1.0.0",
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
- Recall memory using semantic similarity and spreading activation.
860
-
861
- The type parameter is optional and must be one of:
862
- - 'world': General knowledge about people, places, events, and things that happen
863
- - 'experience': Memories about experience, conversations, actions taken, and tasks performed
864
- - 'opinion': The bank's formed beliefs, perspectives, and viewpoints
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
- Reflect and formulate an answer using bank identity, world facts, and opinions.
977
-
978
- This endpoint:
979
- 1. Retrieves experience (conversations and events)
980
- 2. Retrieves world facts relevant to the query
981
- 3. Retrieves existing opinions (bank's perspectives)
982
- 4. Uses LLM to formulate a contextual answer
983
- 5. Extracts and stores any new opinions formed
984
- 6. Returns plain text answer, the facts used, and new opinions
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
- Delete a document and all its associated memory units and links.
1394
-
1395
- This will cascade delete:
1396
- - The document itself
1397
- - All memory units extracted from this document
1398
- - All links (temporal, semantic, entity) associated with those memory units
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
- Retain memory items with automatic fact extraction.
1695
-
1696
- This is the main endpoint for storing memories. It supports both synchronous and asynchronous processing
1697
- via the async parameter.
1698
-
1699
- Features:
1700
- - Efficient batch processing
1701
- - Automatic fact extraction from natural language
1702
- - Entity recognition and linking
1703
- - Document tracking with automatic upsert (when document_id is provided on items)
1704
- - Temporal and semantic linking
1705
- - Optional asynchronous processing
1706
-
1707
- The system automatically:
1708
- 1. Extracts semantic facts from the content
1709
- 2. Generates embeddings
1710
- 3. Deduplicates similar facts
1711
- 4. Creates temporal, semantic, and entity links
1712
- 5. Tracks document metadata
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': 'batch_put',
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, SentenceTransformersEmbeddings
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
- "SentenceTransformersEmbeddings",
33
+ "LocalSTEmbeddings",
34
+ "RemoteTEIEmbeddings",
35
+ "CrossEncoderModel",
36
+ "LocalSTCrossEncoder",
37
+ "RemoteTEICrossEncoder",
33
38
  "SearchTrace",
34
39
  "SearchTracer",
35
40
  "QueryInfo",