hindsight-api 0.1.0__py3-none-any.whl → 0.1.2__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.
Files changed (32) hide show
  1. hindsight_api/__init__.py +10 -2
  2. hindsight_api/alembic/README +1 -0
  3. hindsight_api/alembic/env.py +146 -0
  4. hindsight_api/alembic/script.py.mako +28 -0
  5. hindsight_api/alembic/versions/5a366d414dce_initial_schema.py +274 -0
  6. hindsight_api/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py +70 -0
  7. hindsight_api/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py +39 -0
  8. hindsight_api/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py +48 -0
  9. hindsight_api/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py +62 -0
  10. hindsight_api/alembic/versions/rename_personality_to_disposition.py +65 -0
  11. hindsight_api/api/http.py +84 -86
  12. hindsight_api/config.py +154 -0
  13. hindsight_api/engine/__init__.py +7 -2
  14. hindsight_api/engine/cross_encoder.py +219 -15
  15. hindsight_api/engine/embeddings.py +192 -18
  16. hindsight_api/engine/llm_wrapper.py +88 -139
  17. hindsight_api/engine/memory_engine.py +71 -51
  18. hindsight_api/engine/retain/bank_utils.py +2 -2
  19. hindsight_api/engine/retain/fact_extraction.py +1 -1
  20. hindsight_api/engine/search/reranking.py +6 -10
  21. hindsight_api/engine/search/tracer.py +1 -1
  22. hindsight_api/main.py +201 -0
  23. hindsight_api/migrations.py +7 -7
  24. hindsight_api/server.py +43 -0
  25. {hindsight_api-0.1.0.dist-info → hindsight_api-0.1.2.dist-info}/METADATA +1 -1
  26. {hindsight_api-0.1.0.dist-info → hindsight_api-0.1.2.dist-info}/RECORD +28 -19
  27. hindsight_api-0.1.2.dist-info/entry_points.txt +2 -0
  28. hindsight_api/cli.py +0 -127
  29. hindsight_api/web/__init__.py +0 -12
  30. hindsight_api/web/server.py +0 -109
  31. hindsight_api-0.1.0.dist-info/entry_points.txt +0 -2
  32. {hindsight_api-0.1.0.dist-info → hindsight_api-0.1.2.dist-info}/WHEEL +0 -0
@@ -11,17 +11,20 @@ This implements a sophisticated memory architecture that combines:
11
11
  import json
12
12
  import os
13
13
  from datetime import datetime, timedelta, timezone
14
- from typing import Any, Dict, List, Optional, Tuple, Union, TypedDict
14
+ from typing import Any, Dict, List, Optional, Tuple, Union, TypedDict, TYPE_CHECKING
15
15
  import asyncpg
16
16
  import asyncio
17
- from .embeddings import Embeddings, SentenceTransformersEmbeddings
18
- from .cross_encoder import CrossEncoderModel
17
+ from .embeddings import Embeddings, create_embeddings_from_env
18
+ from .cross_encoder import CrossEncoderModel, create_cross_encoder_from_env
19
19
  import time
20
20
  import numpy as np
21
21
  import uuid
22
22
  import logging
23
23
  from pydantic import BaseModel, Field
24
24
 
25
+ if TYPE_CHECKING:
26
+ from ..config import HindsightConfig
27
+
25
28
 
26
29
  class RetainContentDict(TypedDict, total=False):
27
30
  """Type definition for content items in retain_batch_async.
@@ -99,10 +102,10 @@ class MemoryEngine:
99
102
 
100
103
  def __init__(
101
104
  self,
102
- db_url: str,
103
- memory_llm_provider: str,
104
- memory_llm_api_key: str,
105
- memory_llm_model: str,
105
+ db_url: Optional[str] = None,
106
+ memory_llm_provider: Optional[str] = None,
107
+ memory_llm_api_key: Optional[str] = None,
108
+ memory_llm_model: Optional[str] = None,
106
109
  memory_llm_base_url: Optional[str] = None,
107
110
  embeddings: Optional[Embeddings] = None,
108
111
  cross_encoder: Optional[CrossEncoderModel] = None,
@@ -115,26 +118,34 @@ class MemoryEngine:
115
118
  """
116
119
  Initialize the temporal + semantic memory system.
117
120
 
121
+ All parameters are optional and will be read from environment variables if not provided.
122
+ See hindsight_api.config for environment variable names and defaults.
123
+
118
124
  Args:
119
- db_url: PostgreSQL connection URL (postgresql://user:pass@host:port/dbname). Required.
125
+ db_url: PostgreSQL connection URL. Defaults to HINDSIGHT_API_DATABASE_URL env var or "pg0".
120
126
  Also supports pg0 URLs: "pg0" or "pg0://instance-name" or "pg0://instance-name:port"
121
- memory_llm_provider: LLM provider for memory operations: "openai", "groq", or "ollama". Required.
122
- memory_llm_api_key: API key for the LLM provider. Required.
123
- memory_llm_model: Model name to use for all memory operations (put/think/opinions). Required.
124
- memory_llm_base_url: Base URL for the LLM API. Optional. Defaults based on provider:
125
- - groq: https://api.groq.com/openai/v1
126
- - ollama: http://localhost:11434/v1
127
- embeddings: Embeddings implementation to use. If not provided, uses SentenceTransformersEmbeddings
128
- cross_encoder: Cross-encoder model for reranking. If not provided, uses default when cross-encoder reranker is selected
129
- query_analyzer: Query analyzer implementation to use. If not provided, uses TransformerQueryAnalyzer
127
+ memory_llm_provider: LLM provider. Defaults to HINDSIGHT_API_LLM_PROVIDER env var or "groq".
128
+ memory_llm_api_key: API key for the LLM provider. Defaults to HINDSIGHT_API_LLM_API_KEY env var.
129
+ memory_llm_model: Model name. Defaults to HINDSIGHT_API_LLM_MODEL env var.
130
+ memory_llm_base_url: Base URL for the LLM API. Defaults based on provider.
131
+ embeddings: Embeddings implementation. If not provided, created from env vars.
132
+ cross_encoder: Cross-encoder model. If not provided, created from env vars.
133
+ query_analyzer: Query analyzer implementation. If not provided, uses DateparserQueryAnalyzer.
130
134
  pool_min_size: Minimum number of connections in the pool (default: 5)
131
135
  pool_max_size: Maximum number of connections in the pool (default: 100)
132
- Increase for parallel think/search operations (e.g., 200-300 for 100+ parallel thinks)
133
- task_backend: Custom task backend for async task execution. If not provided, uses AsyncIOQueueBackend
136
+ task_backend: Custom task backend. If not provided, uses AsyncIOQueueBackend.
134
137
  run_migrations: Whether to run database migrations during initialize(). Default: True
135
138
  """
136
- if not db_url:
137
- raise ValueError("Database url is required")
139
+ # Load config from environment for any missing parameters
140
+ from ..config import get_config
141
+ config = get_config()
142
+
143
+ # Apply defaults from config
144
+ db_url = db_url or config.database_url
145
+ memory_llm_provider = memory_llm_provider or config.llm_provider
146
+ memory_llm_api_key = memory_llm_api_key or config.llm_api_key
147
+ memory_llm_model = memory_llm_model or config.llm_model
148
+ memory_llm_base_url = memory_llm_base_url or config.get_llm_base_url() or None
138
149
  # Track pg0 instance (if used)
139
150
  self._pg0: Optional[EmbeddedPostgres] = None
140
151
  self._pg0_instance_name: Optional[str] = None
@@ -184,11 +195,11 @@ class MemoryEngine:
184
195
  # Initialize entity resolver (will be created in initialize())
185
196
  self.entity_resolver = None
186
197
 
187
- # Initialize embeddings
198
+ # Initialize embeddings (from env vars if not provided)
188
199
  if embeddings is not None:
189
200
  self.embeddings = embeddings
190
201
  else:
191
- self.embeddings = SentenceTransformersEmbeddings("BAAI/bge-small-en-v1.5")
202
+ self.embeddings = create_embeddings_from_env()
192
203
 
193
204
  # Initialize query analyzer
194
205
  if query_analyzer is not None:
@@ -319,7 +330,7 @@ class MemoryEngine:
319
330
  await self._handle_reinforce_opinion(task_dict)
320
331
  elif task_type == 'form_opinion':
321
332
  await self._handle_form_opinion(task_dict)
322
- elif task_type == 'batch_put':
333
+ elif task_type == 'batch_retain':
323
334
  await self._handle_batch_retain(task_dict)
324
335
  elif task_type == 'regenerate_observations':
325
336
  await self._handle_regenerate_observations(task_dict)
@@ -414,32 +425,41 @@ class MemoryEngine:
414
425
  if not was_already_running:
415
426
  self._pg0 = pg0
416
427
 
417
- def load_embeddings():
418
- """Load embedding model (CPU-bound)."""
419
- self.embeddings.load()
420
-
421
- def load_cross_encoder():
422
- """Load cross-encoder model (CPU-bound)."""
423
- self._cross_encoder_reranker.cross_encoder.load()
424
-
425
- def load_query_analyzer():
426
- """Load query analyzer model (CPU-bound)."""
427
- self.query_analyzer.load()
428
-
429
- # Run pg0 and all model loads in parallel
430
- # pg0 is async (IO-bound), models are sync (CPU-bound in thread pool)
431
- # Use 3 workers to load all models concurrently
432
- with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
433
- # Start all tasks
434
- pg0_task = asyncio.create_task(start_pg0())
435
- embeddings_future = loop.run_in_executor(executor, load_embeddings)
436
- cross_encoder_future = loop.run_in_executor(executor, load_cross_encoder)
437
- query_analyzer_future = loop.run_in_executor(executor, load_query_analyzer)
438
-
439
- # Wait for all to complete
440
- await asyncio.gather(
441
- pg0_task, embeddings_future, cross_encoder_future, query_analyzer_future
442
- )
428
+ async def init_embeddings():
429
+ """Initialize embedding model."""
430
+ # For local providers, run in thread pool to avoid blocking event loop
431
+ if self.embeddings.provider_name == "local":
432
+ await loop.run_in_executor(
433
+ None,
434
+ lambda: asyncio.run(self.embeddings.initialize())
435
+ )
436
+ else:
437
+ await self.embeddings.initialize()
438
+
439
+ async def init_cross_encoder():
440
+ """Initialize cross-encoder model."""
441
+ cross_encoder = self._cross_encoder_reranker.cross_encoder
442
+ # For local providers, run in thread pool to avoid blocking event loop
443
+ if cross_encoder.provider_name == "local":
444
+ await loop.run_in_executor(
445
+ None,
446
+ lambda: asyncio.run(cross_encoder.initialize())
447
+ )
448
+ else:
449
+ await cross_encoder.initialize()
450
+
451
+ async def init_query_analyzer():
452
+ """Initialize query analyzer model."""
453
+ # Query analyzer load is sync and CPU-bound
454
+ await loop.run_in_executor(None, self.query_analyzer.load)
455
+
456
+ # Run pg0 and all model initializations in parallel
457
+ await asyncio.gather(
458
+ start_pg0(),
459
+ init_embeddings(),
460
+ init_cross_encoder(),
461
+ init_query_analyzer(),
462
+ )
443
463
 
444
464
  # Run database migrations if enabled
445
465
  if self._run_migrations:
@@ -2692,7 +2712,7 @@ Guidelines:
2692
2712
  ],
2693
2713
  scope="memory_think",
2694
2714
  temperature=0.9,
2695
- max_tokens=1000
2715
+ max_completion_tokens=1000
2696
2716
  )
2697
2717
  llm_time = time.time() - llm_start
2698
2718
 
@@ -273,7 +273,7 @@ Merged background:"""
273
273
  response_format=BackgroundMergeResponse,
274
274
  scope="bank_background",
275
275
  temperature=0.3,
276
- max_tokens=8192
276
+ max_completion_tokens=8192
277
277
  )
278
278
  logger.info(f"Successfully got structured response: background={parsed.background[:100]}")
279
279
 
@@ -291,7 +291,7 @@ Merged background:"""
291
291
  messages=messages,
292
292
  scope="bank_background",
293
293
  temperature=0.3,
294
- max_tokens=8192
294
+ max_completion_tokens=8192
295
295
  )
296
296
 
297
297
  logger.info(f"LLM response for background merge (first 500 chars): {content[:500]}")
@@ -579,7 +579,7 @@ Text:
579
579
  response_format=FactExtractionResponse,
580
580
  scope="memory_extract_facts",
581
581
  temperature=0.1,
582
- max_tokens=65000,
582
+ max_completion_tokens=65000,
583
583
  skip_validation=True, # Get raw JSON, we'll validate leniently
584
584
  )
585
585
 
@@ -10,10 +10,8 @@ class CrossEncoderReranker:
10
10
  """
11
11
  Neural reranking using a cross-encoder model.
12
12
 
13
- Uses cross-encoder/ms-marco-MiniLM-L-6-v2 by default:
14
- - Fast inference (~80ms for 100 pairs on CPU)
15
- - Small model (80MB)
16
- - Trained for passage re-ranking
13
+ Configured via environment variables (see cross_encoder.py).
14
+ Default local model is cross-encoder/ms-marco-MiniLM-L-6-v2.
17
15
  """
18
16
 
19
17
  def __init__(self, cross_encoder=None):
@@ -21,14 +19,12 @@ class CrossEncoderReranker:
21
19
  Initialize cross-encoder reranker.
22
20
 
23
21
  Args:
24
- cross_encoder: CrossEncoderReranker instance. If None, uses default
25
- SentenceTransformersCrossEncoder with ms-marco-MiniLM-L-6-v2
26
- (loaded lazily for faster startup)
22
+ cross_encoder: CrossEncoderModel instance. If None, creates one from
23
+ environment variables (defaults to local provider)
27
24
  """
28
25
  if cross_encoder is None:
29
- from hindsight_api.engine.cross_encoder import SentenceTransformersCrossEncoder
30
- # Model is loaded lazily - call ensure_loaded() during initialize()
31
- cross_encoder = SentenceTransformersCrossEncoder()
26
+ from hindsight_api.engine.cross_encoder import create_cross_encoder_from_env
27
+ cross_encoder = create_cross_encoder_from_env()
32
28
  self.cross_encoder = cross_encoder
33
29
 
34
30
  def rerank(
@@ -368,7 +368,7 @@ class SearchTracer:
368
368
 
369
369
  # Extract score components (only include non-None values)
370
370
  score_components = {}
371
- for key in ["semantic_similarity", "bm25_score", "rrf_score", "recency_normalized", "frequency_normalized"]:
371
+ for key in ["semantic_similarity", "bm25_score", "rrf_score", "recency_normalized", "frequency_normalized", "cross_encoder_score", "cross_encoder_score_normalized"]:
372
372
  if key in result and result[key] is not None:
373
373
  score_components[key] = result[key]
374
374
 
hindsight_api/main.py ADDED
@@ -0,0 +1,201 @@
1
+ """
2
+ Command-line interface for Hindsight API.
3
+
4
+ Run the server with:
5
+ hindsight-api
6
+
7
+ Stop with Ctrl+C.
8
+ """
9
+ import argparse
10
+ import asyncio
11
+ import atexit
12
+ import os
13
+ import signal
14
+ import sys
15
+ import warnings
16
+ from typing import Optional
17
+
18
+ import uvicorn
19
+
20
+ from . import MemoryEngine
21
+ from .api import create_app
22
+ from .config import get_config, HindsightConfig
23
+
24
+ # Filter deprecation warnings from third-party libraries
25
+ warnings.filterwarnings("ignore", message="websockets.legacy is deprecated")
26
+ warnings.filterwarnings("ignore", message="websockets.server.WebSocketServerProtocol is deprecated")
27
+
28
+ # Disable tokenizers parallelism to avoid warnings
29
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
30
+
31
+ # Global reference for cleanup
32
+ _memory: Optional[MemoryEngine] = None
33
+
34
+
35
+ def _cleanup():
36
+ """Synchronous cleanup function to stop resources on exit."""
37
+ global _memory
38
+ if _memory is not None and _memory._pg0 is not None:
39
+ try:
40
+ loop = asyncio.new_event_loop()
41
+ loop.run_until_complete(_memory._pg0.stop())
42
+ loop.close()
43
+ print("\npg0 stopped.")
44
+ except Exception as e:
45
+ print(f"\nError stopping pg0: {e}")
46
+
47
+
48
+ def _signal_handler(signum, frame):
49
+ """Handle SIGINT/SIGTERM to ensure cleanup."""
50
+ print(f"\nReceived signal {signum}, shutting down...")
51
+ _cleanup()
52
+ sys.exit(0)
53
+
54
+
55
+ def main():
56
+ """Main entry point for the CLI."""
57
+ global _memory
58
+
59
+ # Load configuration from environment (for CLI args defaults)
60
+ config = get_config()
61
+
62
+ parser = argparse.ArgumentParser(
63
+ prog="hindsight-api",
64
+ description="Hindsight API Server",
65
+ )
66
+
67
+ # Server options
68
+ parser.add_argument(
69
+ "--host", default=config.host,
70
+ help=f"Host to bind to (default: {config.host}, env: HINDSIGHT_API_HOST)"
71
+ )
72
+ parser.add_argument(
73
+ "--port", type=int, default=config.port,
74
+ help=f"Port to bind to (default: {config.port}, env: HINDSIGHT_API_PORT)"
75
+ )
76
+ parser.add_argument(
77
+ "--log-level", default=config.log_level,
78
+ choices=["critical", "error", "warning", "info", "debug", "trace"],
79
+ help=f"Log level (default: {config.log_level}, env: HINDSIGHT_API_LOG_LEVEL)"
80
+ )
81
+
82
+ # Development options
83
+ parser.add_argument(
84
+ "--reload", action="store_true",
85
+ help="Enable auto-reload on code changes (development only)"
86
+ )
87
+ parser.add_argument(
88
+ "--workers", type=int, default=1,
89
+ help="Number of worker processes (default: 1)"
90
+ )
91
+
92
+ # Access log options
93
+ parser.add_argument(
94
+ "--access-log", action="store_true",
95
+ help="Enable access log"
96
+ )
97
+ parser.add_argument(
98
+ "--no-access-log", dest="access_log", action="store_false",
99
+ help="Disable access log (default)"
100
+ )
101
+ parser.set_defaults(access_log=False)
102
+
103
+ # Proxy options
104
+ parser.add_argument(
105
+ "--proxy-headers", action="store_true",
106
+ help="Enable X-Forwarded-Proto, X-Forwarded-For headers"
107
+ )
108
+ parser.add_argument(
109
+ "--forwarded-allow-ips", default=None,
110
+ help="Comma separated list of IPs to trust with proxy headers"
111
+ )
112
+
113
+ # SSL options
114
+ parser.add_argument(
115
+ "--ssl-keyfile", default=None,
116
+ help="SSL key file"
117
+ )
118
+ parser.add_argument(
119
+ "--ssl-certfile", default=None,
120
+ help="SSL certificate file"
121
+ )
122
+
123
+ args = parser.parse_args()
124
+
125
+ # Configure Python logging based on log level
126
+ # Update config with CLI override if provided
127
+ if args.log_level != config.log_level:
128
+ config = HindsightConfig(
129
+ database_url=config.database_url,
130
+ llm_provider=config.llm_provider,
131
+ llm_api_key=config.llm_api_key,
132
+ llm_model=config.llm_model,
133
+ llm_base_url=config.llm_base_url,
134
+ embeddings_provider=config.embeddings_provider,
135
+ embeddings_local_model=config.embeddings_local_model,
136
+ embeddings_tei_url=config.embeddings_tei_url,
137
+ reranker_provider=config.reranker_provider,
138
+ reranker_local_model=config.reranker_local_model,
139
+ reranker_tei_url=config.reranker_tei_url,
140
+ host=args.host,
141
+ port=args.port,
142
+ log_level=args.log_level,
143
+ mcp_enabled=config.mcp_enabled,
144
+ )
145
+ config.configure_logging()
146
+
147
+ # Register cleanup handlers
148
+ atexit.register(_cleanup)
149
+ signal.signal(signal.SIGINT, _signal_handler)
150
+ signal.signal(signal.SIGTERM, _signal_handler)
151
+
152
+ # Create MemoryEngine (reads configuration from environment)
153
+ _memory = MemoryEngine()
154
+
155
+ # Create FastAPI app
156
+ app = create_app(
157
+ memory=_memory,
158
+ http_api_enabled=True,
159
+ mcp_api_enabled=config.mcp_enabled,
160
+ mcp_mount_path="/mcp",
161
+ initialize_memory=True,
162
+ )
163
+
164
+ # Prepare uvicorn config
165
+ uvicorn_config = {
166
+ "app": app,
167
+ "host": args.host,
168
+ "port": args.port,
169
+ "log_level": args.log_level,
170
+ "access_log": args.access_log,
171
+ "proxy_headers": args.proxy_headers,
172
+ "ws": "wsproto", # Use wsproto instead of websockets to avoid deprecation warnings
173
+ }
174
+
175
+ # Add optional parameters if provided
176
+ if args.reload:
177
+ uvicorn_config["reload"] = True
178
+ if args.workers > 1:
179
+ uvicorn_config["workers"] = args.workers
180
+ if args.forwarded_allow_ips:
181
+ uvicorn_config["forwarded_allow_ips"] = args.forwarded_allow_ips
182
+ if args.ssl_keyfile:
183
+ uvicorn_config["ssl_keyfile"] = args.ssl_keyfile
184
+ if args.ssl_certfile:
185
+ uvicorn_config["ssl_certfile"] = args.ssl_certfile
186
+
187
+ print(f"\nStarting Hindsight API...")
188
+ print(f" URL: http://{args.host}:{args.port}")
189
+ print(f" Database: {config.database_url}")
190
+ print(f" LLM: {config.llm_provider} / {config.llm_model}")
191
+ print(f" Embeddings: {config.embeddings_provider}")
192
+ print(f" Reranker: {config.reranker_provider}")
193
+ if config.mcp_enabled:
194
+ print(f" MCP: enabled at /mcp")
195
+ print()
196
+
197
+ uvicorn.run(**uvicorn_config)
198
+
199
+
200
+ if __name__ == "__main__":
201
+ main()
@@ -88,11 +88,11 @@ def run_migrations(database_url: str, script_location: Optional[str] = None) ->
88
88
  try:
89
89
  # Determine script location
90
90
  if script_location is None:
91
- # Default: use the alembic directory in the hindsight_api package
92
- # This file is in: hindsight-api/hindsight_api/migrations.py
93
- # Default location is: hindsight-api/alembic
94
- package_root = Path(__file__).parent.parent
95
- script_location = str(package_root / "alembic")
91
+ # Default: use the alembic directory inside the hindsight_api package
92
+ # This file is in: hindsight_api/migrations.py
93
+ # Alembic is in: hindsight_api/alembic/
94
+ package_dir = Path(__file__).parent
95
+ script_location = str(package_dir / "alembic")
96
96
 
97
97
  script_path = Path(script_location)
98
98
  if not script_path.exists():
@@ -162,8 +162,8 @@ def check_migration_status(database_url: Optional[str] = None, script_location:
162
162
 
163
163
  # Get head revision from migration scripts
164
164
  if script_location is None:
165
- package_root = Path(__file__).parent.parent
166
- script_location = str(package_root / "alembic")
165
+ package_dir = Path(__file__).parent
166
+ script_location = str(package_dir / "alembic")
167
167
 
168
168
  script_path = Path(script_location)
169
169
  if not script_path.exists():
@@ -0,0 +1,43 @@
1
+ """
2
+ FastAPI server for Hindsight API.
3
+
4
+ This module provides the ASGI app for uvicorn import string usage:
5
+ uvicorn hindsight_api.server:app
6
+
7
+ For CLI usage, use the hindsight-api command instead.
8
+ """
9
+ import os
10
+ import warnings
11
+
12
+ # Filter deprecation warnings from third-party libraries
13
+ warnings.filterwarnings("ignore", message="websockets.legacy is deprecated")
14
+ warnings.filterwarnings("ignore", message="websockets.server.WebSocketServerProtocol is deprecated")
15
+
16
+ from hindsight_api import MemoryEngine
17
+ from hindsight_api.api import create_app
18
+ from hindsight_api.config import get_config
19
+
20
+ # Disable tokenizers parallelism to avoid warnings
21
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
22
+
23
+ # Load configuration and configure logging
24
+ config = get_config()
25
+ config.configure_logging()
26
+
27
+ # Create app at module level (required for uvicorn import string)
28
+ # MemoryEngine reads configuration from environment variables automatically
29
+ _memory = MemoryEngine()
30
+
31
+ # Create unified app with both HTTP and optionally MCP
32
+ app = create_app(
33
+ memory=_memory,
34
+ http_api_enabled=True,
35
+ mcp_api_enabled=config.mcp_enabled,
36
+ mcp_mount_path="/mcp"
37
+ )
38
+
39
+
40
+ if __name__ == "__main__":
41
+ # When run directly, delegate to the CLI
42
+ from hindsight_api.main import main
43
+ main()
@@ -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
@@ -1,31 +1,42 @@
1
- hindsight_api/__init__.py,sha256=yQWYWUWEhvs1OY1coENhZV_CuOAWmN_YKZXQMIvGN94,851
2
- hindsight_api/cli.py,sha256=NPuykf35Us8J40iV4-mrGk13d1GSt2TeBl5Nd88CY0I,3274
1
+ hindsight_api/__init__.py,sha256=gPkRHnMATZqBgc7b-Mcro4f_gY9W0BlnGBE0zg1t_IY,1139
2
+ hindsight_api/config.py,sha256=V29wimS9xCOP20lXL6VUJZZKB46YbD_8TV9LHUtJKng,5186
3
+ hindsight_api/main.py,sha256=Tl_w0kM-bcB0Y37_rKv_RzGOj_ReMuio20JtSunz9aE,6079
3
4
  hindsight_api/metrics.py,sha256=j4-eeqVjjcGQxAxS_GgEaBNm10KdUxrGS_I2d1IM1hY,7255
4
- hindsight_api/migrations.py,sha256=A6D1LVuReJ7Ua10ABWyW2-neE7CtRErGWFipbVNH7mw,7382
5
+ hindsight_api/migrations.py,sha256=nSbU37ZszVZifYJTU_vEXfusTxWaUea9dRi7-Ao3-SQ,7349
5
6
  hindsight_api/models.py,sha256=ncIi8agl3PVk7ffyXlJosFym1jJZZhVmXTguZ3EnAEc,12515
6
7
  hindsight_api/pg0.py,sha256=_GuVccjE0_OthaK72_GXC3NkcI9q3MkU3i8m685mDfQ,13542
8
+ hindsight_api/server.py,sha256=C_w3_xzKRVkSsFkujhMz9S4nDlAc0eOFClGIefTCZIk,1263
9
+ hindsight_api/alembic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
10
+ hindsight_api/alembic/env.py,sha256=i0gc3GN2rWidtqRp-vdvnJTIR0zl1X4Uokqp_WnTsAo,4837
11
+ hindsight_api/alembic/script.py.mako,sha256=04kgeBtNMa4cCnG8CfQcKt6P6rnloIfj8wy0u_DBydM,704
12
+ hindsight_api/alembic/versions/5a366d414dce_initial_schema.py,sha256=qTrvBWf-48sL2kx7eNq1BoDjF_QfePGq2-wKrK__wWk,16774
13
+ hindsight_api/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py,sha256=g0edMh_4w8WDVcnB-GA1l-RdreYJkV-kJWZX9VJHYp8,2592
14
+ hindsight_api/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py,sha256=brlAuHO5ygarkfsjW-p70NiVDGfj98BjczaptGPyYNg,1159
15
+ hindsight_api/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py,sha256=pLz_s5kV3IHQ3TrpvHmtXQOkdfK4iQ07w93dEsXu3Qk,1536
16
+ hindsight_api/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py,sha256=fykAU4V4jq1wVpCBoH0TzvSFyeyxZtk-6hpaZAbrFxU,2327
17
+ hindsight_api/alembic/versions/rename_personality_to_disposition.py,sha256=xlp-Is96e3TvCwSqhPctQRqLBHcl3dvDmlzbCMZGw1A,2196
7
18
  hindsight_api/api/__init__.py,sha256=dIJqoygqYaEgm-Bd7qwZ4UTnb9UPyXtlDxZnQpvVC0o,2946
8
- hindsight_api/api/http.py,sha256=7g6ij_Kegu5fSoqDIpPYWVS1cqxpD1Uc_0moQ5bbddA,69206
19
+ hindsight_api/api/http.py,sha256=_vy70aWQ5TJlhXgIw6PbH0mrqat8_J_0rQwY73h24Pg,69863
9
20
  hindsight_api/api/mcp.py,sha256=DldtC8LQUguAbJSSHnEBS65wC-AQBjcF8rl51xUR1gQ,7808
10
- hindsight_api/engine/__init__.py,sha256=5DU5DvnJdzkrgNgKchpzkiJr-37I-kE1tegJg2LF04k,1214
11
- hindsight_api/engine/cross_encoder.py,sha256=8BBMyM5ryRuQ7W8x0jea4Y6GW3MtqtxyHGz1yyCXz2g,3175
21
+ hindsight_api/engine/__init__.py,sha256=W_y6iAHgu-HUpvdXlI6JJ0KO42wVkrWvcUSJZqTCj_M,1406
22
+ hindsight_api/engine/cross_encoder.py,sha256=D6iTTXv23R1n8O_IoAsBCsCbevZTNhnJSt4AirADksg,10789
12
23
  hindsight_api/engine/db_utils.py,sha256=p1Ne70wPP327xdPI_XjMfnagilY8sknbkhEIZuED6DU,2724
13
- hindsight_api/engine/embeddings.py,sha256=9drPQoK8LtertxsnI8GU24bPQtOJb8n3Uguhz6Nl_x0,3886
24
+ hindsight_api/engine/embeddings.py,sha256=RdK9A3lUjp1FZFArllhTgKo70Pot4ZUEJ1Pw70BpNmk,10218
14
25
  hindsight_api/engine/entity_resolver.py,sha256=w5DPCuYNsK4GF8Qe3oY7jCKcOT1WYx2h0YD1nX0QRtA,23184
15
- hindsight_api/engine/llm_wrapper.py,sha256=Pro7r-bkilfqRH3x4E_k08p41kntRoCpJQ0FyrQBzJ0,22003
16
- hindsight_api/engine/memory_engine.py,sha256=dk3NjIQo-re8Y1rrRNDwukQdAqr5Yxe-Nuaf27XeCnU,133449
26
+ hindsight_api/engine/llm_wrapper.py,sha256=v7XWms1uCj9Bev-Txy4iGhofZTQmA29aaudZCSD3UHs,18672
27
+ hindsight_api/engine/memory_engine.py,sha256=QQz-5vD_Qh_0qFtNoWcynUQesw_Hyh8TZ3qzq4tTB7g,134144
17
28
  hindsight_api/engine/query_analyzer.py,sha256=K0QCg7tsbqtwC7TR5wt3FPoP8QDuZsX9r0Zljc8nnYo,19733
18
29
  hindsight_api/engine/response_models.py,sha256=e-_vE1zAVFLpkl6SeHIYvHcQ4Z-AaOdq0jjjhh8yHk4,8683
19
30
  hindsight_api/engine/task_backend.py,sha256=ojxMC9PeHdnkWVs2ozeqycjI_1mmpkDa0_Qfej9AHrg,7287
20
31
  hindsight_api/engine/utils.py,sha256=VAjpZSbdiwhlE6cDlYfTt_-5hIJ--0xtfixETK0LPSk,6910
21
32
  hindsight_api/engine/retain/__init__.py,sha256=L_QuR1YLHsJ7OCmVFNsZe8WDjbsTTHL-wCiUXtw1aUE,1230
22
- hindsight_api/engine/retain/bank_utils.py,sha256=j5vzmNwUvtx3kCIQgzSHCvByCvpIRjLbjx74r1XGEIg,14121
33
+ hindsight_api/engine/retain/bank_utils.py,sha256=r-_411UuuQwxlIxEteA2GE_Wr9BdsNt0OVCjaJgcISU,14143
23
34
  hindsight_api/engine/retain/chunk_storage.py,sha256=rjmfnllS185tmjJGkMjWZ9q_6hJO4N6Ll9jgPx6f5xo,2081
24
35
  hindsight_api/engine/retain/deduplication.py,sha256=9YXgVI_m1Mtz5Cv46ZceCEs0GwpLqTPHrZ-vlWlXk6I,3313
25
36
  hindsight_api/engine/retain/embedding_processing.py,sha256=cHTt3rPvDCWBWVPfSeg6bwH8HoXYGmP4bvS21boNONI,1734
26
37
  hindsight_api/engine/retain/embedding_utils.py,sha256=Q24h_iw6pRAW2vDWPvauWY1o3bXLzW3eWvSxDALDiE0,1588
27
38
  hindsight_api/engine/retain/entity_processing.py,sha256=F_6yYjf7Me5khg-X57ZW4wK5BBAmzMpry-TXwVFQZ-8,2658
28
- hindsight_api/engine/retain/fact_extraction.py,sha256=ZBT--eKLcAW0a3GJ-TE7k_nzA_R4fJboEaakKx5W2iA,50807
39
+ hindsight_api/engine/retain/fact_extraction.py,sha256=dZ0FYepvndUfWTowGxM5vrrF0NV_LIIGsANA6Ze6Mf4,50818
29
40
  hindsight_api/engine/retain/fact_storage.py,sha256=rKJiWr_1lrqyB6s0mTCnTiHVZIUbCfd3zigNwISnVPI,5637
30
41
  hindsight_api/engine/retain/link_creation.py,sha256=rkYKO73dWBL8BbRBeiwNgHzwrU-sKWUjmrgLIxr3LiA,3280
31
42
  hindsight_api/engine/retain/link_utils.py,sha256=g80xUMr45na8UX505VnoZ7jSKdvyRgxDHnDoINd8GNI,28828
@@ -35,17 +46,15 @@ hindsight_api/engine/retain/types.py,sha256=JJ4t8Qtp64kTPB9CKOFDXqdos2i8GZXmJZNz
35
46
  hindsight_api/engine/search/__init__.py,sha256=7X6U10bVw0JRWxQdE5RCfVpawDlSUldi1mPoCzY0V0A,363
36
47
  hindsight_api/engine/search/fusion.py,sha256=so6LU7kWRR-VJd1Pxlu8idRJ7P2WLCoDwXUnb8jQifo,4309
37
48
  hindsight_api/engine/search/observation_utils.py,sha256=SPrDx6M0daJ_zLLkk78GlQIG3EL7DqMKSu_etKerUfU,4331
38
- hindsight_api/engine/search/reranking.py,sha256=Bk5i5kal5yy4CM8m2uSxAumLPgLeHdncBX6wk4WTmEI,3525
49
+ hindsight_api/engine/search/reranking.py,sha256=znjN78VfuT4PqprhGRPd2B9WtVMhAU5A662s0xCvU7g,3329
39
50
  hindsight_api/engine/search/retrieval.py,sha256=i6pffxsfYkTjQYS8iNMC60owMr__a8i7khkHb4LUWuI,19661
40
51
  hindsight_api/engine/search/scoring.py,sha256=feFPalpbIMndp8j2Ab0zvu7fRq3c43Wmzrjw3piQ0eM,5167
41
52
  hindsight_api/engine/search/temporal_extraction.py,sha256=5klrZdza3mkgk5A15_m_j4IIfOHMc6fUR9UJuzLa790,1812
42
53
  hindsight_api/engine/search/think_utils.py,sha256=VJJXFmBg03yO4Mg--UBMlTQW9IZOj2eyTZztjzhT8F8,11315
43
54
  hindsight_api/engine/search/trace.py,sha256=Hx-siW9yAfqZoK9LG6esbed0vQuHMNsGxSvCg4FK6-4,11042
44
- hindsight_api/engine/search/tracer.py,sha256=mcM9qZpj3YFudrBCESwc6YKNAiWIMx1lScXWn5ru-ok,15017
55
+ hindsight_api/engine/search/tracer.py,sha256=LQ78knpMxyZmPUvm3PJNN2opCyA-LpB47JZ84n0g2pw,15074
45
56
  hindsight_api/engine/search/types.py,sha256=qIeHW_gT7f291vteTZXygAM8oAaPp2dq6uEdvOyOwzs,5488
46
- hindsight_api/web/__init__.py,sha256=WABqyqiAVFJJWOhKCytkj5Vcb61eAsRib3Ek7IMX6_U,378
47
- hindsight_api/web/server.py,sha256=l-Tw8G9IRdcSay-KWiUT4VlIJBzxbe-TV0rjX0fwLMc,4464
48
- hindsight_api-0.1.0.dist-info/METADATA,sha256=7KQUZY0Kcdl83K9zVA4gPVJAMOy12IxL7sr0PjI9EKs,1466
49
- hindsight_api-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
50
- hindsight_api-0.1.0.dist-info/entry_points.txt,sha256=53Fn-VxtkqreZhOPTJB_FupH7e5GyiMY3gzEp22d8xs,57
51
- hindsight_api-0.1.0.dist-info/RECORD,,
57
+ hindsight_api-0.1.2.dist-info/METADATA,sha256=lgnN2q6oLQ8zseo3n01WgcUv3DQAgRMZJ9PzGvP94y8,1466
58
+ hindsight_api-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
59
+ hindsight_api-0.1.2.dist-info/entry_points.txt,sha256=ZDj1gJCi6Ga6VLdPgRSrRizQ4dUTreefjeG_tO1CuHk,58
60
+ hindsight_api-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ hindsight-api = hindsight_api.main:main