diff --git a/hindsight-api-slim/hindsight_api/api/http.py b/hindsight-api-slim/hindsight_api/api/http.py index 625c9acc4e..41a0bc1277 100644 --- a/hindsight-api-slim/hindsight_api/api/http.py +++ b/hindsight-api-slim/hindsight_api/api/http.py @@ -27,7 +27,7 @@ AuditLogStatsResponse, ) from hindsight_api.engine.llm_trace import LLMRequestListResponse, LLMRequestStatsResponse -from hindsight_api.extensions import AuthenticationError +from hindsight_api.extensions import AuthenticationError, PrecheckOperation def _parse_metadata(metadata: Any) -> dict[str, Any]: @@ -3364,7 +3364,7 @@ def get_request_context(authorization: str | None = Header(default=None)) -> Req api_key = authorization.strip() return RequestContext(api_key=api_key) - def precheck_for(operation: str): + def precheck_for(operation: PrecheckOperation): """ Build a FastAPI dependency that runs ``OperationValidator.precheck``. @@ -3615,7 +3615,7 @@ async def api_list( async def _require_dry_run_enabled() -> None: """Feature-flag gate for dry-run extraction. - Declared as a dependency BEFORE ``precheck_for("dry_run_extract")`` so a + Declared as a dependency BEFORE ``precheck_for(PrecheckOperation.DRY_RUN_EXTRACT)`` so a disabled route returns 404 regardless of tenant/billing state — FastAPI resolves path-operation dependencies in signature order, so this runs first and preserves the original "disabled → 404" contract. @@ -3645,7 +3645,7 @@ async def api_dry_run_extract( body: DryRunExtractRequest, request_context: RequestContext = Depends(get_request_context), _enabled: None = Depends(_require_dry_run_enabled), - _precheck: None = Depends(precheck_for("dry_run_extract")), + _precheck: None = Depends(precheck_for(PrecheckOperation.DRY_RUN_EXTRACT)), ): try: override_fields = ( @@ -3813,7 +3813,7 @@ async def api_recall( request: RecallRequest, http_request: Request, request_context: RequestContext = Depends(get_request_context), - _precheck: None = Depends(precheck_for("recall")), + _precheck: None = Depends(precheck_for(PrecheckOperation.RECALL)), ): """Run a recall and return results with trace.""" import time @@ -4015,7 +4015,7 @@ async def api_reflect( request: ReflectRequest, http_request: Request, request_context: RequestContext = Depends(get_request_context), - _precheck: None = Depends(precheck_for("reflect")), + _precheck: None = Depends(precheck_for(PrecheckOperation.REFLECT)), ): metrics = get_metrics_collector() @@ -4562,7 +4562,7 @@ async def api_create_mental_model( bank_id: str, body: CreateMentalModelRequest, request_context: RequestContext = Depends(get_request_context), - _precheck: None = Depends(precheck_for("mental_model_create")), + _precheck: None = Depends(precheck_for(PrecheckOperation.MENTAL_MODEL_CREATE)), ): """Create a mental model (async - returns operation_id).""" try: @@ -4611,7 +4611,7 @@ async def api_refresh_mental_model( bank_id: str, mental_model_id: str, request_context: RequestContext = Depends(get_request_context), - _precheck: None = Depends(precheck_for("mental_model_refresh")), + _precheck: None = Depends(precheck_for(PrecheckOperation.MENTAL_MODEL_REFRESH)), ): """Refresh a mental model by re-running its source query (async).""" try: @@ -6197,9 +6197,11 @@ async def api_get_bank_config(bank_id: str, request_context: RequestContext = De # Authenticate and set schema context for multi-tenant DB queries await app.state.memory._authenticate_tenant(request_context) if app.state.memory._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_bank_config", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_BANK_CONFIG, request_context=request_context + ) await app.state.memory._validate_operation( app.state.memory._operation_validator.validate_bank_read(ctx) ) @@ -6245,9 +6247,11 @@ async def api_update_bank_config( # Authenticate and set schema context for multi-tenant DB queries await app.state.memory._authenticate_tenant(request_context) if app.state.memory._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="update_bank_config", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.UPDATE_BANK_CONFIG, request_context=request_context + ) await app.state.memory._validate_operation( app.state.memory._operation_validator.validate_bank_write(ctx) ) @@ -6304,9 +6308,11 @@ async def api_reset_bank_config(bank_id: str, request_context: RequestContext = # Authenticate and set schema context for multi-tenant DB queries await app.state.memory._authenticate_tenant(request_context) if app.state.memory._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="reset_bank_config", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.RESET_BANK_CONFIG, request_context=request_context + ) await app.state.memory._validate_operation( app.state.memory._operation_validator.validate_bank_write(ctx) ) @@ -6677,7 +6683,7 @@ async def api_retain( bank_id: str, request: RetainRequest, request_context: RequestContext = Depends(get_request_context), - _precheck: None = Depends(precheck_for("retain")), + _precheck: None = Depends(precheck_for(PrecheckOperation.RETAIN)), ): """Retain memories with optional async processing.""" metrics = get_metrics_collector() @@ -6860,7 +6866,7 @@ async def api_file_retain( files: list[UploadFile] = File(..., description="Files to upload and convert"), request: str = Form(..., description="JSON string with FileRetainRequest model"), request_context: RequestContext = Depends(get_request_context), - _precheck: None = Depends(precheck_for("files_retain")), + _precheck: None = Depends(precheck_for(PrecheckOperation.FILES_RETAIN)), ): """Upload and convert files to memories.""" from hindsight_api.config import get_config diff --git a/hindsight-api-slim/hindsight_api/engine/memory_engine.py b/hindsight-api-slim/hindsight_api/engine/memory_engine.py index 848236ae71..e826bc07a0 100644 --- a/hindsight-api-slim/hindsight_api/engine/memory_engine.py +++ b/hindsight-api-slim/hindsight_api/engine/memory_engine.py @@ -5437,9 +5437,11 @@ async def get_document( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_document", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_DOCUMENT, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -5528,9 +5530,11 @@ async def delete_document( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="delete_document", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.DELETE_DOCUMENT, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() invalidated_obs = 0 @@ -5631,9 +5635,11 @@ async def update_document( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="update_document", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.UPDATE_DOCUMENT, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() invalidated_obs = 0 @@ -5918,9 +5924,11 @@ async def delete_bank( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="delete_bank", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.DELETE_BANK, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() invalidated_obs = 0 @@ -6054,9 +6062,11 @@ async def clear_observations( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="clear_observations", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.CLEAR_OBSERVATIONS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -6116,9 +6126,11 @@ async def list_observation_scopes( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_observation_scopes", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_OBSERVATION_SCOPES, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -6160,10 +6172,12 @@ async def retry_failed_consolidation( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation ctx = BankWriteContext( - bank_id=bank_id, operation="retry_failed_consolidation", request_context=request_context + bank_id=bank_id, + operation=BankWriteOperation.RETRY_FAILED_CONSOLIDATION, + request_context=request_context, ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -6214,10 +6228,12 @@ async def clear_observations_for_memory( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation ctx = BankWriteContext( - bank_id=bank_id, operation="clear_observations_for_memory", request_context=request_context + bank_id=bank_id, + operation=BankWriteOperation.CLEAR_OBSERVATIONS_FOR_MEMORY, + request_context=request_context, ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -6374,9 +6390,11 @@ def _parse_edit_date(value: str | None) -> datetime | None: await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="update_memory_unit", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.UPDATE_MEMORY_UNIT, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -6648,9 +6666,11 @@ async def run_consolidation( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="run_consolidation", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.RUN_CONSOLIDATION, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) from .consolidation import run_consolidation_job @@ -6702,9 +6722,11 @@ async def get_graph_data( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_graph_data", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_GRAPH_DATA, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -7211,9 +7233,11 @@ async def list_memory_units( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_memory_units", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_MEMORY_UNITS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) if state is not None and state not in ("valid", "invalidated"): raise ValueError(f"Invalid state '{state}': expected 'valid' or 'invalidated'.") @@ -7391,9 +7415,11 @@ async def get_memory_unit( raise ValueError(f"Invalid memory_id: '{memory_id}' is not a valid UUID") await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_memory_unit", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_MEMORY_UNIT, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -7500,9 +7526,11 @@ async def get_observation_history( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_observation_history", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_OBSERVATION_HISTORY, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -7638,9 +7666,11 @@ async def list_documents( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_documents", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_DOCUMENTS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -7804,9 +7834,11 @@ async def get_chunk( return None if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=chunk["bank_id"], operation="get_chunk", request_context=request_context) + ctx = BankReadContext( + bank_id=chunk["bank_id"], operation=BankReadOperation.GET_CHUNK, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) return { @@ -7842,9 +7874,11 @@ async def list_document_chunks( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_document_chunks", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_DOCUMENT_CHUNKS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -7916,9 +7950,11 @@ async def reprocess_document( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="reprocess_document", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.REPROCESS_DOCUMENT, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) # Fetch the document @@ -8431,9 +8467,11 @@ async def get_bank_profile( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_bank_profile", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_BANK_PROFILE, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() if not create_if_missing: @@ -8587,10 +8625,10 @@ async def update_bank_disposition( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation ctx = BankWriteContext( - bank_id=bank_id, operation="update_bank_disposition", request_context=request_context + bank_id=bank_id, operation=BankWriteOperation.UPDATE_BANK_DISPOSITION, request_context=request_context ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) await self._get_backend() @@ -8616,9 +8654,11 @@ async def set_bank_mission( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="set_bank_mission", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.SET_BANK_MISSION, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) await self._get_backend() await bank_utils.set_bank_mission(self._backend, bank_id, mission) @@ -8645,9 +8685,11 @@ async def merge_bank_mission( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="merge_bank_mission", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.MERGE_BANK_MISSION, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) await self._get_backend() return await bank_utils.merge_bank_mission(self._backend, self._reflect_llm_config, bank_id, new_info) @@ -9219,9 +9261,11 @@ async def list_entities( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_entities", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_ENTITIES, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -9298,9 +9342,11 @@ async def get_entity_graph( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_entity_graph", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_ENTITY_GRAPH, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() async with acquire_with_retry(backend) as conn: @@ -9413,9 +9459,11 @@ async def list_tags( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_tags", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_TAGS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) return await self._list_tags_from_table( table="memory_units", @@ -9442,11 +9490,11 @@ async def list_mental_model_tags( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation ctx = BankReadContext( bank_id=bank_id, - operation="list_mental_model_tags", + operation=BankReadOperation.LIST_MENTAL_MODEL_TAGS, request_context=request_context, ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) @@ -9551,9 +9599,11 @@ async def get_entity_state( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_entity_state", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_ENTITY_STATE, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) return EntityState(entity_id=entity_id, canonical_name=entity_name, observations=[]) @@ -9576,9 +9626,11 @@ async def get_bank_stats( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_bank_stats", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_BANK_STATS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) schema = get_current_schema() @@ -9722,9 +9774,11 @@ async def get_bank_freshness( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_bank_stats", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_BANK_STATS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -9791,9 +9845,11 @@ async def check_bank_llm( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_bank_stats", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_BANK_STATS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) per_operation_llm = [ @@ -9844,9 +9900,11 @@ async def get_memories_timeseries( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_memories_timeseries", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_MEMORIES_TIMESERIES, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) cfg = _MEMORIES_TIMESERIES_PERIODS.get(period) or _MEMORIES_TIMESERIES_PERIODS["7d"] @@ -9933,9 +9991,11 @@ async def get_entity( """Get entity details including metadata and observations.""" await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_entity", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_ENTITY, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -10010,9 +10070,11 @@ async def list_mental_models( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_mental_models", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_MENTAL_MODELS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -10199,9 +10261,11 @@ async def create_mental_model( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="create_mental_model", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.CREATE_MENTAL_MODEL, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -10668,9 +10732,11 @@ async def update_mental_model( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="update_mental_model", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.UPDATE_MENTAL_MODEL, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -10863,9 +10929,11 @@ async def clear_mental_model( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="clear_mental_model", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.CLEAR_MENTAL_MODEL, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -10906,9 +10974,11 @@ async def delete_mental_model( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="delete_mental_model", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.DELETE_MENTAL_MODEL, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11080,9 +11150,11 @@ async def list_directives( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_directives", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_DIRECTIVES, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -11163,9 +11235,11 @@ async def get_directive( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_directive", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_DIRECTIVE, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -11209,9 +11283,11 @@ async def create_directive( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="create_directive", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.CREATE_DIRECTIVE, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11263,9 +11339,11 @@ async def update_directive( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="update_directive", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.UPDATE_DIRECTIVE, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11333,9 +11411,11 @@ async def delete_directive( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="delete_directive", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.DELETE_DIRECTIVE, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11389,9 +11469,11 @@ async def list_operations( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_operations", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_OPERATIONS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -11483,9 +11565,11 @@ async def get_operation_status( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="get_operation_status", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.GET_OPERATION_STATUS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -11623,9 +11707,11 @@ async def cancel_operation( """Cancel a pending async operation.""" await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="cancel_operation", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.CANCEL_OPERATION, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11675,9 +11761,11 @@ async def retry_operation( from hindsight_api.extensions import OperationValidationError if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="retry_operation", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.RETRY_OPERATION, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11732,9 +11820,11 @@ async def update_bank( """Update bank name and/or mission.""" await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="update_bank", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.UPDATE_BANK, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11800,9 +11890,11 @@ async def create_webhook( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="create_webhook", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.CREATE_WEBHOOK, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11840,9 +11932,11 @@ async def list_webhooks( """List webhooks for a bank in the bank's resolved schema.""" await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_webhooks", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_WEBHOOKS, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -11872,9 +11966,11 @@ async def update_webhook( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="update_webhook", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.UPDATE_WEBHOOK, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11902,9 +11998,11 @@ async def delete_webhook( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation - ctx = BankWriteContext(bank_id=bank_id, operation="delete_webhook", request_context=request_context) + ctx = BankWriteContext( + bank_id=bank_id, operation=BankWriteOperation.DELETE_WEBHOOK, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) backend = await self._get_backend() @@ -11936,9 +12034,11 @@ async def list_webhook_deliveries( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankReadContext + from hindsight_api.extensions import BankReadContext, BankReadOperation - ctx = BankReadContext(bank_id=bank_id, operation="list_webhook_deliveries", request_context=request_context) + ctx = BankReadContext( + bank_id=bank_id, operation=BankReadOperation.LIST_WEBHOOK_DELIVERIES, request_context=request_context + ) await self._validate_operation(self._operation_validator.validate_bank_read(ctx)) backend = await self._get_backend() @@ -12465,10 +12565,12 @@ async def submit_async_consolidation( """ await self._authenticate_tenant(request_context) if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation ctx = BankWriteContext( - bank_id=bank_id, operation="submit_async_consolidation", request_context=request_context + bank_id=bank_id, + operation=BankWriteOperation.SUBMIT_ASYNC_CONSOLIDATION, + request_context=request_context, ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) @@ -12528,10 +12630,12 @@ async def submit_async_graph_maintenance( return {"operation_id": None, "no_work": True} if self._operation_validator: - from hindsight_api.extensions import BankWriteContext + from hindsight_api.extensions import BankWriteContext, BankWriteOperation ctx = BankWriteContext( - bank_id=bank_id, operation="submit_async_graph_maintenance", request_context=request_context + bank_id=bank_id, + operation=BankWriteOperation.SUBMIT_ASYNC_GRAPH_MAINTENANCE, + request_context=request_context, ) await self._validate_operation(self._operation_validator.validate_bank_write(ctx)) diff --git a/hindsight-api-slim/hindsight_api/extensions/__init__.py b/hindsight-api-slim/hindsight_api/extensions/__init__.py index 08db9f8002..a838ada270 100644 --- a/hindsight-api-slim/hindsight_api/extensions/__init__.py +++ b/hindsight-api-slim/hindsight_api/extensions/__init__.py @@ -39,7 +39,9 @@ BankListContext, BankListResult, BankReadContext, + BankReadOperation, BankWriteContext, + BankWriteOperation, # Consolidation operation ConsolidateContext, ConsolidateResult, @@ -54,6 +56,7 @@ OperationValidationError, OperationValidatorExtension, PrecheckContext, + PrecheckOperation, RecallContext, RecallResult, ReflectContext, @@ -87,6 +90,7 @@ "OperationValidationError", "OperationValidatorExtension", "PrecheckContext", + "PrecheckOperation", "RecallContext", "RecallResult", "ReflectContext", @@ -98,7 +102,9 @@ "BankListContext", "BankListResult", "BankReadContext", + "BankReadOperation", "BankWriteContext", + "BankWriteOperation", # Operation Validator - Consolidation "ConsolidateContext", "ConsolidateResult", diff --git a/hindsight-api-slim/hindsight_api/extensions/operation_validator.py b/hindsight-api-slim/hindsight_api/extensions/operation_validator.py index 6c6394add1..8325670af1 100644 --- a/hindsight-api-slim/hindsight_api/extensions/operation_validator.py +++ b/hindsight-api-slim/hindsight_api/extensions/operation_validator.py @@ -3,6 +3,7 @@ from abc import ABC, abstractmethod from dataclasses import dataclass, field from datetime import datetime +from enum import StrEnum from typing import TYPE_CHECKING from hindsight_api.extensions.base import Extension @@ -82,6 +83,18 @@ def reject(cls, reason: str, status_code: int = 403) -> "ValidationResult": # ============================================================================= +class PrecheckOperation(StrEnum): + """Route operation names passed to the pre-body-parse precheck hook.""" + + DRY_RUN_EXTRACT = "dry_run_extract" + FILES_RETAIN = "files_retain" + MENTAL_MODEL_CREATE = "mental_model_create" + MENTAL_MODEL_REFRESH = "mental_model_refresh" + RECALL = "recall" + REFLECT = "reflect" + RETAIN = "retain" + + @dataclass class PrecheckContext: """Context for a pre-body-parse precheck on an operation. @@ -91,9 +104,7 @@ class PrecheckContext: therefore intentionally carries only the cheap, already-resolved pieces of request state: - - ``operation``: a short string identifying the route, e.g. ``"retain"``, - ``"recall"``, ``"reflect"``, ``"files_retain"``, ``"mental_model_create"``, - ``"mental_model_refresh"``. + - ``operation``: a short string-compatible enum identifying the route. - ``bank_id``: parsed from the URL path. - ``request_context``: the authenticated :class:`RequestContext` (tenant already resolved by the tenant extension). @@ -108,7 +119,7 @@ class PrecheckContext: the source of truth for the precise per-call cost / quota arithmetic. """ - operation: str + operation: PrecheckOperation bank_id: str request_context: "RequestContext" content_length: int | None = None @@ -303,12 +314,77 @@ class ConsolidateResult: # ============================================================================= +class BankReadOperation(StrEnum): + """Bank-scoped read operation names passed to validate_bank_read.""" + + GET_BANK_CONFIG = "get_bank_config" + GET_BANK_PROFILE = "get_bank_profile" + GET_BANK_STATS = "get_bank_stats" + GET_CHUNK = "get_chunk" + GET_DIRECTIVE = "get_directive" + GET_DOCUMENT = "get_document" + GET_ENTITY = "get_entity" + GET_ENTITY_GRAPH = "get_entity_graph" + GET_ENTITY_STATE = "get_entity_state" + GET_GRAPH_DATA = "get_graph_data" + GET_MEMORIES_TIMESERIES = "get_memories_timeseries" + GET_MEMORY_UNIT = "get_memory_unit" + GET_OBSERVATION_HISTORY = "get_observation_history" + GET_OPERATION_STATUS = "get_operation_status" + LIST_DIRECTIVES = "list_directives" + LIST_DOCUMENT_CHUNKS = "list_document_chunks" + LIST_DOCUMENTS = "list_documents" + LIST_ENTITIES = "list_entities" + LIST_MEMORY_UNITS = "list_memory_units" + LIST_MENTAL_MODEL_TAGS = "list_mental_model_tags" + LIST_MENTAL_MODELS = "list_mental_models" + LIST_OBSERVATION_SCOPES = "list_observation_scopes" + LIST_OPERATIONS = "list_operations" + LIST_TAGS = "list_tags" + LIST_WEBHOOK_DELIVERIES = "list_webhook_deliveries" + LIST_WEBHOOKS = "list_webhooks" + + +class BankWriteOperation(StrEnum): + """Bank-scoped write operation names passed to validate_bank_write.""" + + CANCEL_OPERATION = "cancel_operation" + CLEAR_MENTAL_MODEL = "clear_mental_model" + CLEAR_OBSERVATIONS = "clear_observations" + CLEAR_OBSERVATIONS_FOR_MEMORY = "clear_observations_for_memory" + CREATE_DIRECTIVE = "create_directive" + CREATE_MENTAL_MODEL = "create_mental_model" + CREATE_WEBHOOK = "create_webhook" + DELETE_BANK = "delete_bank" + DELETE_DIRECTIVE = "delete_directive" + DELETE_DOCUMENT = "delete_document" + DELETE_MENTAL_MODEL = "delete_mental_model" + DELETE_WEBHOOK = "delete_webhook" + MERGE_BANK_MISSION = "merge_bank_mission" + REPROCESS_DOCUMENT = "reprocess_document" + RESET_BANK_CONFIG = "reset_bank_config" + RETRY_FAILED_CONSOLIDATION = "retry_failed_consolidation" + RETRY_OPERATION = "retry_operation" + RUN_CONSOLIDATION = "run_consolidation" + SET_BANK_MISSION = "set_bank_mission" + SUBMIT_ASYNC_CONSOLIDATION = "submit_async_consolidation" + SUBMIT_ASYNC_GRAPH_MAINTENANCE = "submit_async_graph_maintenance" + UPDATE_BANK = "update_bank" + UPDATE_BANK_CONFIG = "update_bank_config" + UPDATE_BANK_DISPOSITION = "update_bank_disposition" + UPDATE_DIRECTIVE = "update_directive" + UPDATE_DOCUMENT = "update_document" + UPDATE_MEMORY_UNIT = "update_memory_unit" + UPDATE_MENTAL_MODEL = "update_mental_model" + UPDATE_WEBHOOK = "update_webhook" + + @dataclass class BankReadContext: """Context for a bank read operation validation (pre-operation).""" bank_id: str - operation: str # "get_bank_profile", "get_bank_stats" + operation: BankReadOperation request_context: "RequestContext" @@ -317,7 +393,7 @@ class BankWriteContext: """Context for a bank write operation validation (pre-operation).""" bank_id: str - operation: str # "delete_bank", "update_bank", "update_bank_disposition", "set_bank_mission", "merge_bank_mission", "clear_observations", "clear_observations_for_memory" + operation: BankWriteOperation request_context: "RequestContext" diff --git a/hindsight-api-slim/tests/test_extensions.py b/hindsight-api-slim/tests/test_extensions.py index d2222267e8..4afa1346ef 100644 --- a/hindsight-api-slim/tests/test_extensions.py +++ b/hindsight-api-slim/tests/test_extensions.py @@ -9,11 +9,19 @@ from hindsight_api.extensions import ( ApiKeyTenantExtension, AuthenticationError, + BankReadContext, + BankReadOperation, + BankWriteContext, + BankWriteOperation, + # Consolidation operation + ConsolidateContext, + ConsolidateResult, Extension, HttpExtension, OperationValidationError, OperationValidatorExtension, PrecheckContext, + PrecheckOperation, RecallContext, RecallResult, ReflectContext, @@ -21,13 +29,8 @@ RequestContext, RetainContext, RetainResult, - TenantContext, - TenantExtension, ValidationResult, load_extension, - # Consolidation operation - ConsolidateContext, - ConsolidateResult, ) @@ -68,6 +71,36 @@ async def test_extension_lifecycle(self, monkeypatch): await ext.on_shutdown() assert ext.stopped + def test_operation_enums_remain_string_compatible(self): + """Operation enums centralize names without breaking string comparisons.""" + request_context = RequestContext(tenant_id="tenant-1") + + precheck_ctx = PrecheckContext( + bank_id="bank-1", + operation=PrecheckOperation.RETAIN, + request_context=request_context, + ) + read_ctx = BankReadContext( + bank_id="bank-1", + operation=BankReadOperation.GET_BANK_STATS, + request_context=request_context, + ) + write_ctx = BankWriteContext( + bank_id="bank-1", + operation=BankWriteOperation.UPDATE_BANK_CONFIG, + request_context=request_context, + ) + + assert precheck_ctx.operation is PrecheckOperation.RETAIN + assert read_ctx.operation is BankReadOperation.GET_BANK_STATS + assert write_ctx.operation is BankWriteOperation.UPDATE_BANK_CONFIG + assert precheck_ctx.operation == "retain" + assert read_ctx.operation == "get_bank_stats" + assert write_ctx.operation == "update_bank_config" + assert isinstance(precheck_ctx.operation, str) + assert isinstance(read_ctx.operation, str) + assert isinstance(write_ctx.operation, str) + class LifecycleTestExtension(Extension): """Test extension for config and lifecycle tests.""" @@ -356,6 +389,7 @@ async def test_retain_post_hook_receives_all_parameters_and_result(self, memory_ async def test_recall_pre_hook_receives_all_parameters(self, memory_with_tracking_validator): """Pre-recall hook receives all user-provided parameters.""" from datetime import datetime, timezone + from hindsight_api.engine.memory_engine import Budget memory, validator = memory_with_tracking_validator @@ -882,7 +916,7 @@ async def test_default_precheck_accepts(self): validator = RecordingPrecheckValidator(reject=False) # Bypass our override by calling the base implementation directly. ctx = PrecheckContext( - operation="retain", + operation=PrecheckOperation.RETAIN, bank_id="bank-x", request_context=RequestContext(), ) @@ -914,7 +948,7 @@ def _build_app(validator): from fastapi import Depends, FastAPI, HTTPException, Request from pydantic import BaseModel, model_validator - from hindsight_api.extensions import PrecheckContext + from hindsight_api.extensions import PrecheckContext, PrecheckOperation from hindsight_api.models import RequestContext body_parses: list[str] = [] @@ -949,7 +983,7 @@ def _record(cls, v): async def _request_context() -> RequestContext: return RequestContext() - def _precheck_for(operation: str): + def _precheck_for(operation: PrecheckOperation): async def _dep( bank_id: str, request: Request, @@ -985,7 +1019,7 @@ async def _dep( async def retain( bank_id: str, body: _RetainBody, - _: None = Depends(_precheck_for("retain")), + _: None = Depends(_precheck_for(PrecheckOperation.RETAIN)), ): return {"ok": True, "bank_id": bank_id, "n": len(body.items)} @@ -993,7 +1027,7 @@ async def retain( async def recall( bank_id: str, body: _RecallBody, - _: None = Depends(_precheck_for("recall")), + _: None = Depends(_precheck_for(PrecheckOperation.RECALL)), ): return {"ok": True} @@ -1001,7 +1035,7 @@ async def recall( async def reflect( bank_id: str, body: _ReflectBody, - _: None = Depends(_precheck_for("reflect")), + _: None = Depends(_precheck_for(PrecheckOperation.REFLECT)), ): return {"ok": True} @@ -1168,7 +1202,7 @@ async def test_precheck_context_content_length_none_when_header_missing(self): content_length = parsed ctx = PrecheckContext( - operation="retain", + operation=PrecheckOperation.RETAIN, bank_id="bank-x", request_context=RequestContext(), content_length=content_length,