hindsight-api 0.4.7__py3-none-any.whl → 0.4.8__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.
@@ -27,6 +27,7 @@ from hindsight_api.extensions.operation_validator import (
27
27
  # Mental Model operations
28
28
  MentalModelGetContext,
29
29
  MentalModelGetResult,
30
+ MentalModelRefreshContext,
30
31
  MentalModelRefreshResult,
31
32
  # Core operations
32
33
  OperationValidationError,
@@ -72,6 +73,7 @@ __all__ = [
72
73
  # Operation Validator - Mental Model
73
74
  "MentalModelGetContext",
74
75
  "MentalModelGetResult",
76
+ "MentalModelRefreshContext",
75
77
  "MentalModelRefreshResult",
76
78
  # Tenant/Auth
77
79
  "ApiKeyTenantExtension",
@@ -5,6 +5,42 @@ from hindsight_api.extensions.tenant import AuthenticationError, Tenant, TenantC
5
5
  from hindsight_api.models import RequestContext
6
6
 
7
7
 
8
+ class DefaultTenantExtension(TenantExtension):
9
+ """
10
+ Default single-tenant extension with no authentication.
11
+
12
+ This is the default extension used when no tenant extension is configured.
13
+ It provides single-tenant behavior using the configured schema from
14
+ HINDSIGHT_API_DATABASE_SCHEMA (defaults to 'public').
15
+
16
+ Features:
17
+ - No authentication required (passes all requests)
18
+ - Uses configured schema from environment
19
+ - Perfect for single-tenant deployments without auth
20
+
21
+ Configuration:
22
+ HINDSIGHT_API_DATABASE_SCHEMA=your-schema (optional, defaults to 'public')
23
+
24
+ This is automatically enabled by default. To use custom authentication,
25
+ configure a different tenant extension:
26
+ HINDSIGHT_API_TENANT_EXTENSION=hindsight_api.extensions.builtin.tenant:ApiKeyTenantExtension
27
+ """
28
+
29
+ def __init__(self, config: dict[str, str]):
30
+ super().__init__(config)
31
+ # Cache the schema at initialization for consistency
32
+ # Support explicit schema override via config, otherwise use environment
33
+ self._schema = config.get("schema", get_config().database_schema)
34
+
35
+ async def authenticate(self, context: RequestContext) -> TenantContext:
36
+ """Return configured schema without any authentication."""
37
+ return TenantContext(schema_name=self._schema)
38
+
39
+ async def list_tenants(self) -> list[Tenant]:
40
+ """Return configured schema for single-tenant setup."""
41
+ return [Tenant(schema=self._schema)]
42
+
43
+
8
44
  class ApiKeyTenantExtension(TenantExtension):
9
45
  """
10
46
  Built-in tenant extension that validates API key against an environment variable.
@@ -210,6 +210,15 @@ class MentalModelGetContext:
210
210
  request_context: "RequestContext"
211
211
 
212
212
 
213
+ @dataclass
214
+ class MentalModelRefreshContext:
215
+ """Context for a mental model refresh/create operation validation (pre-operation)."""
216
+
217
+ bank_id: str
218
+ mental_model_id: str | None # None for create (not yet assigned)
219
+ request_context: "RequestContext"
220
+
221
+
213
222
  @dataclass
214
223
  class MentalModelGetResult:
215
224
  """Result context for post-mental-model-GET hook."""
@@ -466,6 +475,23 @@ class OperationValidatorExtension(Extension, ABC):
466
475
  """
467
476
  return ValidationResult.accept()
468
477
 
478
+ async def validate_mental_model_refresh(self, ctx: MentalModelRefreshContext) -> ValidationResult:
479
+ """
480
+ Validate a mental model refresh/create operation before execution.
481
+
482
+ Override to implement custom validation logic for mental model refresh.
483
+
484
+ Args:
485
+ ctx: Context containing:
486
+ - bank_id: Bank identifier
487
+ - mental_model_id: Mental model identifier (None for create)
488
+ - request_context: Request context with auth info
489
+
490
+ Returns:
491
+ ValidationResult indicating whether the operation is allowed.
492
+ """
493
+ return ValidationResult.accept()
494
+
469
495
  # =========================================================================
470
496
  # Mental Model - Post-operation hooks (optional - override to implement)
471
497
  # =========================================================================
hindsight_api/main.py CHANGED
@@ -20,14 +20,13 @@ import warnings
20
20
 
21
21
  import uvicorn
22
22
 
23
- from . import MemoryEngine
23
+ from . import MemoryEngine, __version__
24
24
  from .api import create_app
25
25
  from .banner import print_banner
26
26
  from .config import DEFAULT_WORKERS, ENV_WORKERS, HindsightConfig, get_config
27
27
  from .daemon import (
28
28
  DEFAULT_DAEMON_PORT,
29
29
  DEFAULT_IDLE_TIMEOUT,
30
- DaemonLock,
31
30
  IdleTimeoutMiddleware,
32
31
  daemonize,
33
32
  )
@@ -136,30 +135,15 @@ def main():
136
135
 
137
136
  # Daemon mode handling
138
137
  if args.daemon:
139
- # Use fixed daemon port
140
- args.port = DEFAULT_DAEMON_PORT
138
+ # Use port from args (may be custom for profiles)
139
+ if args.port == config.port: # No custom port specified
140
+ args.port = DEFAULT_DAEMON_PORT
141
141
  args.host = "127.0.0.1" # Only bind to localhost for security
142
142
 
143
- # Check if another daemon is already running
144
- daemon_lock = DaemonLock()
145
- if not daemon_lock.acquire():
146
- print(f"Daemon already running (PID: {daemon_lock.get_pid()})", file=sys.stderr)
147
- sys.exit(1)
148
-
149
143
  # Fork into background
144
+ # No lockfile needed - port binding prevents duplicate daemons
150
145
  daemonize()
151
146
 
152
- # Re-acquire lock in child process
153
- daemon_lock = DaemonLock()
154
- if not daemon_lock.acquire():
155
- sys.exit(1)
156
-
157
- # Register cleanup to release lock
158
- def release_lock():
159
- daemon_lock.release()
160
-
161
- atexit.register(release_lock)
162
-
163
147
  # Print banner (not in daemon mode)
164
148
  if not args.daemon:
165
149
  print()
@@ -362,6 +346,7 @@ def main():
362
346
  embeddings_provider=config.embeddings_provider,
363
347
  reranker_provider=config.reranker_provider,
364
348
  mcp_enabled=config.mcp_enabled,
349
+ version=__version__,
365
350
  )
366
351
 
367
352
  # Start idle checker in daemon mode
@@ -165,6 +165,81 @@ def run_migrations(
165
165
  logger.debug("Migration advisory lock acquired")
166
166
 
167
167
  try:
168
+ # Ensure pgvector extension is installed globally BEFORE schema migrations
169
+ # This is critical: the extension must exist database-wide before any schema
170
+ # migrations run, otherwise custom schemas won't have access to vector types
171
+ logger.debug("Checking pgvector extension availability...")
172
+
173
+ # First, check if extension already exists
174
+ ext_check = conn.execute(
175
+ text(
176
+ "SELECT extname, nspname FROM pg_extension e "
177
+ "JOIN pg_namespace n ON e.extnamespace = n.oid "
178
+ "WHERE extname = 'vector'"
179
+ )
180
+ ).fetchone()
181
+
182
+ if ext_check:
183
+ # Extension exists - check if in correct schema
184
+ ext_schema = ext_check[1]
185
+ if ext_schema == "public":
186
+ logger.info("pgvector extension found in public schema - ready to use")
187
+ else:
188
+ # Extension in wrong schema - try to fix if we have permissions
189
+ logger.warning(
190
+ f"pgvector extension found in schema '{ext_schema}' instead of 'public'. "
191
+ f"Attempting to relocate..."
192
+ )
193
+ try:
194
+ conn.execute(text("DROP EXTENSION vector CASCADE"))
195
+ conn.execute(text("SET search_path TO public"))
196
+ conn.execute(text("CREATE EXTENSION vector"))
197
+ conn.commit()
198
+ logger.info("pgvector extension relocated to public schema")
199
+ except Exception as e:
200
+ # Failed to relocate - log but don't fail if extension exists somewhere
201
+ logger.warning(
202
+ f"Could not relocate pgvector extension to public schema: {e}. "
203
+ f"Continuing with extension in '{ext_schema}' schema."
204
+ )
205
+ conn.rollback()
206
+ else:
207
+ # Extension doesn't exist - try to install
208
+ logger.info("pgvector extension not found, attempting to install...")
209
+ try:
210
+ conn.execute(text("SET search_path TO public"))
211
+ conn.execute(text("CREATE EXTENSION vector"))
212
+ conn.commit()
213
+ logger.info("pgvector extension installed in public schema")
214
+ except Exception as e:
215
+ # Installation failed - this is only fatal if extension truly doesn't exist
216
+ # Check one more time in case another process installed it
217
+ conn.rollback()
218
+ ext_recheck = conn.execute(
219
+ text(
220
+ "SELECT nspname FROM pg_extension e "
221
+ "JOIN pg_namespace n ON e.extnamespace = n.oid "
222
+ "WHERE extname = 'vector'"
223
+ )
224
+ ).fetchone()
225
+
226
+ if ext_recheck:
227
+ logger.warning(
228
+ f"Could not install pgvector extension (permission denied?), "
229
+ f"but extension exists in '{ext_recheck[0]}' schema. Continuing..."
230
+ )
231
+ else:
232
+ # Extension truly doesn't exist and we can't install it
233
+ logger.error(
234
+ f"pgvector extension is not installed and cannot be installed: {e}. "
235
+ f"Please ensure pgvector is installed by a database administrator. "
236
+ f"See: https://github.com/pgvector/pgvector#installation"
237
+ )
238
+ raise RuntimeError(
239
+ "pgvector extension is required but not installed. "
240
+ "Please install it with: CREATE EXTENSION vector;"
241
+ ) from e
242
+
168
243
  # Run migrations while holding the lock
169
244
  _run_migrations_internal(database_url, script_location, schema=schema)
170
245
  finally:
@@ -176,7 +176,7 @@ def main():
176
176
  nonlocal memory, poller
177
177
  import uvicorn
178
178
 
179
- from ..extensions import TenantExtension, load_extension
179
+ from ..extensions import OperationValidatorExtension, TenantExtension, load_extension
180
180
 
181
181
  # Load tenant extension BEFORE creating MemoryEngine so it can
182
182
  # set correct schema context during task execution. Without this,
@@ -184,6 +184,12 @@ def main():
184
184
  # causing worker writes to land in the wrong schema.
185
185
  tenant_extension = load_extension("TENANT", TenantExtension)
186
186
 
187
+ # Load operation validator so workers can record usage metering
188
+ # for async operations (e.g. refresh_mental_model after consolidation)
189
+ operation_validator = load_extension("OPERATION_VALIDATOR", OperationValidatorExtension)
190
+ if operation_validator:
191
+ logger.info(f"Loaded operation validator: {operation_validator.__class__.__name__}")
192
+
187
193
  # Initialize MemoryEngine
188
194
  # Workers use SyncTaskBackend because they execute tasks directly,
189
195
  # they don't need to store tasks (they poll from DB)
@@ -191,6 +197,7 @@ def main():
191
197
  run_migrations=False, # Workers don't run migrations
192
198
  task_backend=SyncTaskBackend(),
193
199
  tenant_extension=tenant_extension,
200
+ operation_validator=operation_validator,
194
201
  )
195
202
 
196
203
  await memory.initialize()
@@ -222,15 +229,30 @@ def main():
222
229
  # Create the HTTP app for metrics/health
223
230
  app = create_worker_app(poller, memory)
224
231
 
225
- # Setup signal handlers for graceful shutdown
232
+ # Setup signal handlers for graceful shutdown using asyncio
226
233
  shutdown_requested = asyncio.Event()
227
-
228
- def signal_handler(signum, frame):
229
- print(f"\nReceived signal {signum}, initiating graceful shutdown...")
230
- shutdown_requested.set()
231
-
232
- signal.signal(signal.SIGINT, signal_handler)
233
- signal.signal(signal.SIGTERM, signal_handler)
234
+ force_exit = False
235
+
236
+ loop = asyncio.get_event_loop()
237
+
238
+ def signal_handler():
239
+ nonlocal force_exit
240
+ if shutdown_requested.is_set():
241
+ # Second signal = force exit
242
+ print("\nReceived second signal, forcing immediate exit...")
243
+ force_exit = True
244
+ # Restore default handler so third signal kills process
245
+ loop.remove_signal_handler(signal.SIGINT)
246
+ loop.remove_signal_handler(signal.SIGTERM)
247
+ sys.exit(1)
248
+ else:
249
+ print("\nReceived shutdown signal, initiating graceful shutdown...")
250
+ print("(Press Ctrl+C again to force immediate exit)")
251
+ shutdown_requested.set()
252
+
253
+ # Use asyncio's signal handlers which work properly with the event loop
254
+ loop.add_signal_handler(signal.SIGINT, signal_handler)
255
+ loop.add_signal_handler(signal.SIGTERM, signal_handler)
234
256
 
235
257
  # Create uvicorn config and server
236
258
  uvicorn_config = uvicorn.Config(
@@ -249,7 +271,10 @@ def main():
249
271
  print(f"Worker started. Metrics available at http://{args.http_host}:{args.http_port}/metrics")
250
272
 
251
273
  # Wait for shutdown signal
252
- await shutdown_requested.wait()
274
+ try:
275
+ await shutdown_requested.wait()
276
+ except KeyboardInterrupt:
277
+ print("\nReceived interrupt, initiating graceful shutdown...")
253
278
 
254
279
  # Graceful shutdown
255
280
  print("Shutting down HTTP server...")
@@ -72,9 +72,9 @@ class WorkerPoller:
72
72
  executor: Async function to execute tasks (typically MemoryEngine.execute_task)
73
73
  poll_interval_ms: Interval between polls when no tasks found (milliseconds)
74
74
  max_retries: Maximum retry attempts before marking task as failed
75
- schema: Database schema for single-tenant support (ignored if tenant_extension is set)
76
- tenant_extension: Extension for dynamic multi-tenant discovery. If set, list_tenants()
77
- is called on each poll cycle to discover schemas dynamically.
75
+ schema: Database schema for single-tenant support (deprecated, use tenant_extension)
76
+ tenant_extension: Extension for dynamic multi-tenant discovery. If None, creates a
77
+ DefaultTenantExtension with the configured schema.
78
78
  max_slots: Maximum concurrent tasks per worker
79
79
  consolidation_max_slots: Maximum concurrent consolidation tasks per worker
80
80
  """
@@ -84,6 +84,13 @@ class WorkerPoller:
84
84
  self._poll_interval_ms = poll_interval_ms
85
85
  self._max_retries = max_retries
86
86
  self._schema = schema
87
+ # Always set tenant extension (use DefaultTenantExtension if none provided)
88
+ if tenant_extension is None:
89
+ from ..extensions.builtin.tenant import DefaultTenantExtension
90
+
91
+ # Pass schema parameter to DefaultTenantExtension if explicitly provided
92
+ config = {"schema": schema} if schema else {}
93
+ tenant_extension = DefaultTenantExtension(config=config)
87
94
  self._tenant_extension = tenant_extension
88
95
  self._max_slots = max_slots
89
96
  self._consolidation_max_slots = consolidation_max_slots
@@ -100,14 +107,11 @@ class WorkerPoller:
100
107
 
101
108
  async def _get_schemas(self) -> list[str | None]:
102
109
  """Get list of schemas to poll. Returns [None] for default schema (no prefix)."""
103
- if self._tenant_extension is not None:
104
- from ..config import DEFAULT_DATABASE_SCHEMA
105
-
106
- tenants = await self._tenant_extension.list_tenants()
107
- # Convert default schema to None for SQL compatibility (no prefix), keep others as-is
108
- return [t.schema if t.schema != DEFAULT_DATABASE_SCHEMA else None for t in tenants]
109
- # Single schema mode
110
- return [self._schema]
110
+ from ..config import DEFAULT_DATABASE_SCHEMA
111
+
112
+ tenants = await self._tenant_extension.list_tenants()
113
+ # Convert default schema to None for SQL compatibility (no prefix), keep others as-is
114
+ return [t.schema if t.schema != DEFAULT_DATABASE_SCHEMA else None for t in tenants]
111
115
 
112
116
  async def _get_available_slots(self) -> tuple[int, int]:
113
117
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hindsight-api
3
- Version: 0.4.7
3
+ Version: 0.4.8
4
4
  Summary: Hindsight: Agent Memory That Works Like Human Memory
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: aiohttp>=3.13.3
@@ -8,6 +8,7 @@ Requires-Dist: alembic>=1.17.1
8
8
  Requires-Dist: anthropic>=0.40.0
9
9
  Requires-Dist: asyncpg>=0.29.0
10
10
  Requires-Dist: authlib>=1.6.6
11
+ Requires-Dist: claude-agent-sdk>=0.1.27
11
12
  Requires-Dist: cohere>=5.0.0
12
13
  Requires-Dist: dateparser>=1.2.2
13
14
  Requires-Dist: fastapi[standard]>=0.120.3
@@ -1,12 +1,12 @@
1
- hindsight_api/__init__.py,sha256=5V_49c-ZgcN5QMhuIKGrGI9oJ23z4-pjOX9hwvRI4HY,1197
2
- hindsight_api/banner.py,sha256=BXn-jhkXe4xi-YV4JeuaVvjYhTMs96O43XoOMv4Cd28,4591
3
- hindsight_api/config.py,sha256=mLUMuQrhZCbUd___6Wqdc-OcMXtZ_CZZmxM4b7vO7CE,32506
4
- hindsight_api/daemon.py,sha256=FAyJ2F4Z_rmWRdh5NLI3BszlwxN25ObuHDwT5yiNsVg,6111
5
- hindsight_api/main.py,sha256=-nVh2KrW-Y9y7Punv-1qUz7q4M4IY2vDHBiyAC-Igpk,15243
1
+ hindsight_api/__init__.py,sha256=H-lLDWXpU46uwagO3PyvShBWmpzixxlFVIKjj6scuwI,1197
2
+ hindsight_api/banner.py,sha256=eQeafvnm95eCbWPRjPBmGsIyBXF59SuL9For9unIEyM,4705
3
+ hindsight_api/config.py,sha256=eYorL_NBGSGWkENwuGaW4CH8h-91aJ1jETM4HbVoBlA,33878
4
+ hindsight_api/daemon.py,sha256=LMddRz7h5dg37YcyjjnquNF-Y9zkndN31OaUeNEWBSE,3423
5
+ hindsight_api/main.py,sha256=M2b0sO7SkGgUo6sR1WZDe0VGNfisi28bfnVMek8mgW4,14909
6
6
  hindsight_api/mcp_local.py,sha256=fJnCxMBc79GlBZrma94Ux6g-GVuh-W66194cqQdkKJQ,5613
7
7
  hindsight_api/mcp_tools.py,sha256=cLQ9Bdu8FoL2DscO_Z1pAGpNiCeFY2PHBvIPLZXkwE8,20493
8
8
  hindsight_api/metrics.py,sha256=zgOh_UFTT8ZtqnLaZuyErRtoPZ9SGP3mbmiHT3wX3v4,20677
9
- hindsight_api/migrations.py,sha256=V4QL_N1cMe6kNF1ejJ3lPIPFXKU2Pzbaiviws7AyMIY,14624
9
+ hindsight_api/migrations.py,sha256=sDg2nMLBifZMpfORiKC_Xxp359a5vNk4Hz0BOUuk7zM,18955
10
10
  hindsight_api/models.py,sha256=SzJ8uM2nGr3D6X-UEfE8VIT-PbS9J4DmRT_4lv5n9T8,12831
11
11
  hindsight_api/pg0.py,sha256=Ntj3FYPLfmQTskG4gHoz_NTlQ4A3DqCm2PbbXm-ivGQ,6337
12
12
  hindsight_api/server.py,sha256=MU2ZvKe3KWfxKYZq8EEJPgKMmq5diPkRqfQBaz-yOQI,2483
@@ -15,7 +15,7 @@ hindsight_api/admin/cli.py,sha256=A1qkZ_9GWjz1qOIQYnmj-qUN005cIIlpFsvYH7tZdyc,11
15
15
  hindsight_api/alembic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
16
16
  hindsight_api/alembic/env.py,sha256=I4sGdtUo8xcXe95MyD36JQeMod_Bvp9JUkW64Ve4XSM,5808
17
17
  hindsight_api/alembic/script.py.mako,sha256=04kgeBtNMa4cCnG8CfQcKt6P6rnloIfj8wy0u_DBydM,704
18
- hindsight_api/alembic/versions/5a366d414dce_initial_schema.py,sha256=g3G7fV70Z10PZxwTrTmR34OAlEZjQTLJKr-Ol54JqrQ,17665
18
+ hindsight_api/alembic/versions/5a366d414dce_initial_schema.py,sha256=JhRzHjGhVo70K840l1rr554aA2N5rTNWPvHQIl114xM,18385
19
19
  hindsight_api/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py,sha256=MaHFU4JczUIFLeUMBTKIV3ocuclil55N9fPPim-HRfk,2599
20
20
  hindsight_api/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py,sha256=ChqkHANauZb4-nBt2uepoZN3q0vRzN6aRsWTGueULiA,1146
21
21
  hindsight_api/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py,sha256=s5_B2D0JdaxO7WM-vWC5Yt6hAtTsAUzJhFGLFSkfuQU,1808
@@ -39,7 +39,7 @@ hindsight_api/alembic/versions/t5o6p7q8r9s0_rename_mental_models_to_observations
39
39
  hindsight_api/alembic/versions/u6p7q8r9s0t1_mental_models_text_id.py,sha256=uvil81f-4ag2dIxBXUGKZ5vxkqdNQRpxCWj_iVih09w,1355
40
40
  hindsight_api/alembic/versions/v7q8r9s0t1u2_add_max_tokens_to_mental_models.py,sha256=Mw68uW8PK-SaHcYcqb41vWI0R22t70SSasNS2Myeoec,1656
41
41
  hindsight_api/api/__init__.py,sha256=npF0AAy8WJhHF5a9ehkNn9_iYLk7RQOk2gdkdFb49Hk,3840
42
- hindsight_api/api/http.py,sha256=6bsLA5KTP9a1Bo4ppXRooa0UFh8vJgs7e5qm6L8zil0,134793
42
+ hindsight_api/api/http.py,sha256=yIdoTpg3TOHGOnKrYuMWhQ3L-3OpTtNxEyMc02iYcRw,136567
43
43
  hindsight_api/api/mcp.py,sha256=4ZxeEa_LHcyFRf1jK60hr4JDLXObOQdnpc3bTLJCdVI,8647
44
44
  hindsight_api/engine/__init__.py,sha256=-BwaSwG9fTT_BBO0c_2MBkxG6-tGdclSzIqsgHw4cnw,1633
45
45
  hindsight_api/engine/cross_encoder.py,sha256=Q1s-C-JOOJ246Twl1FyYbeXAJnfdXnfhcDpntScYFvQ,32301
@@ -48,8 +48,9 @@ hindsight_api/engine/db_utils.py,sha256=Fq1pXETt8ZPhkWYjrcGbgL6glrwmCGWh3_lYJgHq
48
48
  hindsight_api/engine/embeddings.py,sha256=KvK65y89E4Hxz8gvQR4G6qSGNlGoai6NBIaWdMzoV_A,27054
49
49
  hindsight_api/engine/entity_resolver.py,sha256=qVvWJHnbGEfh0iUFtc1dbM3IUNwPMsQsmg2rMgiX2DY,23794
50
50
  hindsight_api/engine/interface.py,sha256=wpJUIN-64RFJ_iYNtYWlyR4L-mDO2xijXUFqLD4tkeg,15821
51
- hindsight_api/engine/llm_wrapper.py,sha256=q0d01bdYCVcW9lwJVNxhw3hAp1Qr4YSwU3vXqM3K80Y,71399
52
- hindsight_api/engine/memory_engine.py,sha256=JzQoYsiYTZWncovZekI93KbmTkkuAJ8YyV4QBMYY7TQ,229857
51
+ hindsight_api/engine/llm_interface.py,sha256=mdeEJxv-f8f79wIULUctFTkNs6Snvy2w53o9Ygdo0_Y,4950
52
+ hindsight_api/engine/llm_wrapper.py,sha256=QKggTADJB1b0-qtWlXxtNIKgoh14rIzCkUyWSZKWHPg,22662
53
+ hindsight_api/engine/memory_engine.py,sha256=I-7Bbud8u3ShMn-AjaIG_lfgvjZldRVGJINCJ9mNfsk,231550
53
54
  hindsight_api/engine/query_analyzer.py,sha256=7APe0MjBcUxjivcMlM03PmMk_w5FjWvlEe20yAJlHlc,19741
54
55
  hindsight_api/engine/response_models.py,sha256=ZPP80NmEP205erz5qEE8IJ9-c622UHqYo17e5UOiXAE,15578
55
56
  hindsight_api/engine/task_backend.py,sha256=FFZnjUsjXrrZwww16ow--J61QIpUFwxLdcmeF1NPoYk,8500
@@ -61,6 +62,13 @@ hindsight_api/engine/directives/__init__.py,sha256=5ZxaRqZVyJckbGElaI2DMRMBtnj-q
61
62
  hindsight_api/engine/directives/models.py,sha256=PKxvmhW1-fjBITAOBu7RKX5Lj61c2jdsTaX8ADelKag,1523
62
63
  hindsight_api/engine/mental_models/__init__.py,sha256=TU6dSPyIsevFDgY6PLYctDsk5K4SA4pFSQnmQvbdRlA,488
63
64
  hindsight_api/engine/mental_models/models.py,sha256=DjgumJE7LvbMVpv90aMkGhIWOZ3ZrXM2DFAqHuGerAs,2102
65
+ hindsight_api/engine/providers/__init__.py,sha256=UEoVUTzQGGFe_A8jUmnbQINmwZ7L3P-PLpnh38w2tI8,468
66
+ hindsight_api/engine/providers/anthropic_llm.py,sha256=xv5r4p0HwzKyhcTj0cTLp_kMnW4HuAiIGWtU-PfWhBw,17228
67
+ hindsight_api/engine/providers/claude_code_llm.py,sha256=Cd9TJvO0Tl1Ql-bxU6qjTfw5nYItsxnPPepbZhLdjwQ,14386
68
+ hindsight_api/engine/providers/codex_llm.py,sha256=xdsrCXH38I7DLtEN0zKeLDaoM6h9XwzjCqU3G-Mryd0,19254
69
+ hindsight_api/engine/providers/gemini_llm.py,sha256=51peFrDYVBqhZTOoyZMQp5aMANvikVQrAwRJTSJzHkk,20175
70
+ hindsight_api/engine/providers/mock_llm.py,sha256=h2wF8oVNdqSOpDljolKgXUY-wqjYQhpxVvA3RThY1Qk,8217
71
+ hindsight_api/engine/providers/openai_compatible_llm.py,sha256=ls2XAWTjUsVzPo-KiYSR_20WJ0s2RFXbPFy7waDPFZE,33309
64
72
  hindsight_api/engine/reflect/__init__.py,sha256=r70r-Y9LElHIL3EsvImO1KIL1sT_ubr1lC0IH5kH6O0,484
65
73
  hindsight_api/engine/reflect/agent.py,sha256=mr0rUrwdnDISt9iyuspI_ZhL4qfyLTWAzJO9EAIEctM,37610
66
74
  hindsight_api/engine/reflect/models.py,sha256=ZnMCi4sta5bSVGRRNatTA2jNSun59mWEVVq6Dkmjq1Q,5185
@@ -94,19 +102,19 @@ hindsight_api/engine/search/think_utils.py,sha256=k2NBmb1eczTiDHuQZ7-VW4lsvlGt20
94
102
  hindsight_api/engine/search/trace.py,sha256=RjvbkKBK-_MZBcVhVlaDTLD0yg6krngMNyC0_zLK05Y,11748
95
103
  hindsight_api/engine/search/tracer.py,sha256=B75CZQjdoheN2UpNgqKbJkdXlDVKJjzVTdUhvBUFaLY,16212
96
104
  hindsight_api/engine/search/types.py,sha256=meIoT8Q1coal1TmV_UiCqo9emjQI6af27EXPWVZL4h4,6418
97
- hindsight_api/extensions/__init__.py,sha256=wJTsdtX4dZWnSbjSIM2a9gxyLCzviOAR9m9fVWZCMMM,2394
105
+ hindsight_api/extensions/__init__.py,sha256=Tl2ZZsReYF4mdZ2ZxebekB8zJduMeFuMIcZ09WTHIqE,2458
98
106
  hindsight_api/extensions/base.py,sha256=M7zXuM-tbqDnUwXX1mxAxiFs1eXOzNqIJutKLiUE4mU,2357
99
107
  hindsight_api/extensions/context.py,sha256=Qq-uy3hhxO6ioDmf6dPXdnIjs_pdm7lTspDiEhJJmPU,4469
100
108
  hindsight_api/extensions/http.py,sha256=c-a1g6R6rzibyReyR-WHz8DjRRGr4rVSyV9KB4UxVVU,2907
101
109
  hindsight_api/extensions/loader.py,sha256=UwGM0XH7zHGng_xfHUY0VbOQemj9DmjuDaMst1TrFi8,4170
102
- hindsight_api/extensions/operation_validator.py,sha256=hexa3ChV-xNol-62nHmf-Gj6jDAJd6Z1lbkVYQSqcZw,17177
110
+ hindsight_api/extensions/operation_validator.py,sha256=ukGjgFZuh_pze917sAhd_d_oq_ysPJH80FwVY-6kzJg,18094
103
111
  hindsight_api/extensions/tenant.py,sha256=0LraksQ1gzsOYLEGrx2q2F0or596Ywfo_MqD1FJMNRM,2617
104
112
  hindsight_api/extensions/builtin/__init__.py,sha256=hLx2oFYZ1JtZhTWfab6AYcR02SWP2gIdbEqnZezT8ek,526
105
- hindsight_api/extensions/builtin/tenant.py,sha256=R7jfNR41deGWqQB5P8Qk5njy1bZgvemcTpkXDRiAZBA,1835
113
+ hindsight_api/extensions/builtin/tenant.py,sha256=hAB88q9wuMT1Fqolq22HyP3QrBdICOfLZ1Xo7au1LxU,3325
106
114
  hindsight_api/worker/__init__.py,sha256=hzpMLvOfgL2KKrrik_9ouvEzCdvJSrH-pj5UdFK63J0,256
107
- hindsight_api/worker/main.py,sha256=pM3ASAswNLL_-nEnSEaRSxb4a88BMVH6CVB5GHZXw5w,10050
108
- hindsight_api/worker/poller.py,sha256=O2zs_7DDKxSrAaDVOz5IVhqPoEaLmt_vJ8Qq6K4_dL0,25642
109
- hindsight_api-0.4.7.dist-info/METADATA,sha256=lSWRKsf_wcMRly5nnVYX2FfPuYSoW3eilYiHn-S7C4U,5794
110
- hindsight_api-0.4.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
111
- hindsight_api-0.4.7.dist-info/entry_points.txt,sha256=1-mxPbRGL_Byf9ZrHYkPW-TEgLYFcwCiSFCxOgI_3vM,206
112
- hindsight_api-0.4.7.dist-info/RECORD,,
115
+ hindsight_api/worker/main.py,sha256=wF0c19CqXnECK4NHrUGU9zle8N8QrhuxcvaE3byOID0,11349
116
+ hindsight_api/worker/poller.py,sha256=C3IEbIN-LNgTxW0zhViZxORQotftYIDeNTYD4Bqn2jw,25912
117
+ hindsight_api-0.4.8.dist-info/METADATA,sha256=iK2IIlna5dXjiIlQ5lg055uo7-HGfu7E-hR8WS1QTZk,5834
118
+ hindsight_api-0.4.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
119
+ hindsight_api-0.4.8.dist-info/entry_points.txt,sha256=1-mxPbRGL_Byf9ZrHYkPW-TEgLYFcwCiSFCxOgI_3vM,206
120
+ hindsight_api-0.4.8.dist-info/RECORD,,