codexLB-up 1.25.0b10__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.
- app/__init__.py +10 -0
- app/admin_cli.py +494 -0
- app/cli.py +339 -0
- app/codex_sessions_retag.py +487 -0
- app/core/__init__.py +0 -0
- app/core/audit/__init__.py +0 -0
- app/core/audit/service.py +216 -0
- app/core/audit/types.py +94 -0
- app/core/auth/__init__.py +236 -0
- app/core/auth/api_key_cache.py +65 -0
- app/core/auth/dashboard_access.py +429 -0
- app/core/auth/dashboard_mode.py +171 -0
- app/core/auth/dashboard_session_ttl.py +74 -0
- app/core/auth/dashboard_users_cache.py +120 -0
- app/core/auth/dependencies.py +710 -0
- app/core/auth/external_identity.py +78 -0
- app/core/auth/guardian.py +374 -0
- app/core/auth/models.py +49 -0
- app/core/auth/providers/__init__.py +129 -0
- app/core/auth/providers/oidc.py +838 -0
- app/core/auth/providers/registry.py +118 -0
- app/core/auth/refresh.py +394 -0
- app/core/auth/step_up.py +117 -0
- app/core/auth/totp.py +81 -0
- app/core/balancer/__init__.py +71 -0
- app/core/balancer/logic.py +1612 -0
- app/core/balancer/rendezvous_hash.py +21 -0
- app/core/balancer/types.py +21 -0
- app/core/bootstrap.py +172 -0
- app/core/cache/invalidation.py +426 -0
- app/core/clients/__init__.py +0 -0
- app/core/clients/codex.py +996 -0
- app/core/clients/codex_version.py +187 -0
- app/core/clients/codex_version_snapshot.py +2 -0
- app/core/clients/files.py +534 -0
- app/core/clients/headers.py +29 -0
- app/core/clients/http.py +511 -0
- app/core/clients/model_fetcher.py +276 -0
- app/core/clients/native_egress.py +1304 -0
- app/core/clients/oauth.py +477 -0
- app/core/clients/proxy.py +6089 -0
- app/core/clients/proxy_websocket.py +1411 -0
- app/core/clients/rate_limit_reset_credits.py +412 -0
- app/core/clients/stream_errors.py +12 -0
- app/core/clients/thread_cache_identity.py +347 -0
- app/core/clients/usage.py +467 -0
- app/core/clock.py +170 -0
- app/core/config/__init__.py +0 -0
- app/core/config/background_jobs.py +73 -0
- app/core/config/context_window_overrides.py +166 -0
- app/core/config/dashboard_overrides.py +145 -0
- app/core/config/inheritable.py +47 -0
- app/core/config/key_fingerprint.py +115 -0
- app/core/config/settings.py +872 -0
- app/core/config/settings_cache.py +100 -0
- app/core/config/spool_retention.py +217 -0
- app/core/config/tiers.py +174 -0
- app/core/conversation_archive.py +568 -0
- app/core/crypto.py +37 -0
- app/core/draining.py +11 -0
- app/core/errors.py +365 -0
- app/core/exceptions.py +155 -0
- app/core/handlers/__init__.py +3 -0
- app/core/handlers/exceptions.py +478 -0
- app/core/http_protocol.py +176 -0
- app/core/http_protocol_httptools.py +204 -0
- app/core/ingress_limits.py +17 -0
- app/core/metadata_store.py +18 -0
- app/core/metrics/__init__.py +0 -0
- app/core/metrics/middleware.py +74 -0
- app/core/metrics/prometheus.py +604 -0
- app/core/middleware/__init__.py +25 -0
- app/core/middleware/api_firewall.py +111 -0
- app/core/middleware/app_version.py +37 -0
- app/core/middleware/dashboard_auth_proxy.py +55 -0
- app/core/middleware/dashboard_csrf.py +177 -0
- app/core/middleware/dashboard_gzip.py +41 -0
- app/core/middleware/dashboard_overrides.py +59 -0
- app/core/middleware/firewall_cache.py +91 -0
- app/core/middleware/inflight.py +126 -0
- app/core/middleware/multipart_content_encoding.py +129 -0
- app/core/middleware/path_rewrite.py +148 -0
- app/core/middleware/request_body_limit.py +196 -0
- app/core/middleware/request_decompression.py +209 -0
- app/core/middleware/request_id.py +72 -0
- app/core/middleware/required_capability_http.py +116 -0
- app/core/middleware/trusted_proxy_headers.py +36 -0
- app/core/multipart.py +237 -0
- app/core/multipart_fields.py +91 -0
- app/core/openai/__init__.py +0 -0
- app/core/openai/chat_requests.py +493 -0
- app/core/openai/chat_responses.py +931 -0
- app/core/openai/contracts.py +46 -0
- app/core/openai/exceptions.py +24 -0
- app/core/openai/host_models.py +14 -0
- app/core/openai/images.py +413 -0
- app/core/openai/message_coercion.py +376 -0
- app/core/openai/model_refresh_scheduler.py +423 -0
- app/core/openai/model_registry.py +997 -0
- app/core/openai/model_registry_store.py +548 -0
- app/core/openai/models.py +172 -0
- app/core/openai/parsing.py +97 -0
- app/core/openai/requests.py +1980 -0
- app/core/openai/strict_schema.py +199 -0
- app/core/openai/tool_call_safety.py +99 -0
- app/core/openai/v1_requests.py +187 -0
- app/core/plan_types.py +90 -0
- app/core/prestop.py +202 -0
- app/core/rate_limiter/__init__.py +0 -0
- app/core/rate_limiter/db_rate_limiter.py +215 -0
- app/core/request_locality.py +473 -0
- app/core/resilience/__init__.py +0 -0
- app/core/resilience/backpressure.py +57 -0
- app/core/resilience/bulkhead.py +202 -0
- app/core/resilience/circuit_breaker.py +150 -0
- app/core/resilience/degradation.py +55 -0
- app/core/resilience/loop_lag_monitor.py +60 -0
- app/core/resilience/memory_monitor.py +137 -0
- app/core/resilience/network_recovery.py +256 -0
- app/core/resilience/overload.py +98 -0
- app/core/resilience/toggles.py +114 -0
- app/core/retention/__init__.py +0 -0
- app/core/retention/job.py +240 -0
- app/core/retention/scheduler.py +69 -0
- app/core/runtime_logging.py +601 -0
- app/core/scheduling/__init__.py +0 -0
- app/core/scheduling/leader_election.py +993 -0
- app/core/scheduling/leader_election_handle.py +25 -0
- app/core/server.py +140 -0
- app/core/shutdown.py +326 -0
- app/core/socket_peer.py +22 -0
- app/core/startup.py +41 -0
- app/core/timeout_invariants.py +347 -0
- app/core/tracing/__init__.py +0 -0
- app/core/tracing/otel.py +207 -0
- app/core/types.py +6 -0
- app/core/upstream_proxy/__init__.py +13 -0
- app/core/upstream_proxy/cache.py +130 -0
- app/core/upstream_proxy/resolver.py +189 -0
- app/core/upstream_proxy/types.py +104 -0
- app/core/usage/__init__.py +407 -0
- app/core/usage/depletion.py +109 -0
- app/core/usage/live_hub.py +41 -0
- app/core/usage/live_snapshots.py +174 -0
- app/core/usage/logs.py +212 -0
- app/core/usage/metadata_scheduler.py +118 -0
- app/core/usage/models.py +54 -0
- app/core/usage/pricing.py +576 -0
- app/core/usage/pricing_catalog.py +241 -0
- app/core/usage/pricing_snapshot.json +821 -0
- app/core/usage/quota.py +133 -0
- app/core/usage/refresh_policy.py +21 -0
- app/core/usage/refresh_scheduler.py +713 -0
- app/core/usage/reset_credits_refresh_scheduler.py +435 -0
- app/core/usage/types.py +168 -0
- app/core/utils/__init__.py +0 -0
- app/core/utils/json_guards.py +18 -0
- app/core/utils/locks.py +33 -0
- app/core/utils/masking.py +20 -0
- app/core/utils/proxy_env.py +104 -0
- app/core/utils/request_id.py +65 -0
- app/core/utils/retry.py +77 -0
- app/core/utils/shared_future.py +172 -0
- app/core/utils/sse.py +286 -0
- app/core/utils/time.py +24 -0
- app/db/__init__.py +0 -0
- app/db/account_identity_lock.py +56 -0
- app/db/alembic/__init__.py +1 -0
- app/db/alembic/env.py +70 -0
- app/db/alembic/revision_ids.py +43 -0
- app/db/alembic/versions/20260213_000000_base_schema.py +248 -0
- app/db/alembic/versions/20260213_000100_normalize_account_plan_types.py +45 -0
- app/db/alembic/versions/20260213_000200_add_request_logs_reasoning_effort.py +45 -0
- app/db/alembic/versions/20260213_000300_add_accounts_reset_at.py +45 -0
- app/db/alembic/versions/20260213_000400_add_accounts_chatgpt_account_id.py +45 -0
- app/db/alembic/versions/20260213_000500_add_dashboard_settings.py +70 -0
- app/db/alembic/versions/20260213_000600_add_dashboard_settings_totp.py +64 -0
- app/db/alembic/versions/20260213_000700_add_dashboard_settings_password.py +59 -0
- app/db/alembic/versions/20260213_000800_add_api_keys.py +87 -0
- app/db/alembic/versions/20260214_000000_add_api_key_limits.py +143 -0
- app/db/alembic/versions/20260215_000000_add_idx_logs_requested_at.py +38 -0
- app/db/alembic/versions/20260218_000000_add_api_key_usage_reservations.py +117 -0
- app/db/alembic/versions/20260218_000100_add_import_without_overwrite_and_drop_accounts_email_unique.py +198 -0
- app/db/alembic/versions/20260225_000000_add_dashboard_settings_routing_strategy.py +53 -0
- app/db/alembic/versions/20260228_020000_align_api_key_limit_enum_types.py +104 -0
- app/db/alembic/versions/20260228_030000_add_api_firewall_allowlist.py +42 -0
- app/db/alembic/versions/20260306_000000_add_request_logs_service_tier.py +45 -0
- app/db/alembic/versions/20260307_000000_add_api_key_enforcement_fields.py +56 -0
- app/db/alembic/versions/20260308_000000_add_sqlite_performance_indexes.py +41 -0
- app/db/alembic/versions/20260309_000000_add_additional_usage_history.py +71 -0
- app/db/alembic/versions/20260309_000000_request_logs_nullable_account_id.py +28 -0
- app/db/alembic/versions/20260310_000000_add_request_logs_transport.py +45 -0
- app/db/alembic/versions/20260310_000000_fix_postgresql_enum_value_casing.py +79 -0
- app/db/alembic/versions/20260310_120000_add_sticky_session_kinds_and_affinity_ttl.py +110 -0
- app/db/alembic/versions/20260312_000000_add_additional_usage_quota_key.py +193 -0
- app/db/alembic/versions/20260312_000000_split_sticky_sessions_primary_key_by_kind.py +96 -0
- app/db/alembic/versions/20260312_010000_merge_additional_usage_and_sticky_session_heads.py +25 -0
- app/db/alembic/versions/20260312_020000_merge_request_logs_transport_and_feature_heads.py +25 -0
- app/db/alembic/versions/20260312_020000_merge_request_logs_transport_and_sticky_heads.py +25 -0
- app/db/alembic/versions/20260312_120000_add_dashboard_upstream_stream_transport.py +62 -0
- app/db/alembic/versions/20260313_024500_merge_request_log_transport_heads.py +27 -0
- app/db/alembic/versions/20260319_100937_increase_prompt_cache_ttl_to_1800s.py +73 -0
- app/db/alembic/versions/20260319_111500_merge_prompt_cache_ttl_and_upstream_transport_heads.py +25 -0
- app/db/alembic/versions/20260319_183000_normalize_sqlite_account_status_casing.py +48 -0
- app/db/alembic/versions/20260320_000000_add_request_log_requested_actual_tiers.py +51 -0
- app/db/alembic/versions/20260321_190000_tighten_dashboard_db_indexes.py +64 -0
- app/db/alembic/versions/20260321_210000_merge_request_log_tiers_and_dashboard_index_heads.py +25 -0
- app/db/alembic/versions/20260325_000000_add_request_log_cost.py +193 -0
- app/db/alembic/versions/20260328_000000_add_rate_limit_attempts.py +48 -0
- app/db/alembic/versions/20260328_120000_add_request_log_ttft.py +37 -0
- app/db/alembic/versions/20260328_130000_add_audit_logs_table.py +45 -0
- app/db/alembic/versions/20260328_140000_add_scheduler_leader_table.py +39 -0
- app/db/alembic/versions/20260330_000000_add_cache_locality_settings.py +69 -0
- app/db/alembic/versions/20260330_010000_merge_scheduler_leader_and_cache_locality_heads.py +25 -0
- app/db/alembic/versions/20260330_020000_add_bridge_ring_members.py +46 -0
- app/db/alembic/versions/20260401_000000_add_api_key_enforced_service_tier.py +52 -0
- app/db/alembic/versions/20260401_000000_add_cache_invalidation.py +41 -0
- app/db/alembic/versions/20260401_020000_merge_cache_invalidation_and_api_key_service_tier_heads.py +22 -0
- app/db/alembic/versions/20260402_000000_switch_dashboard_routing_default_to_capacity_weighted.py +66 -0
- app/db/alembic/versions/20260403_000000_add_credit_api_key_limit_values.py +44 -0
- app/db/alembic/versions/20260406_000000_add_api_key_account_assignments.py +57 -0
- app/db/alembic/versions/20260406_010000_add_api_key_assignment_scope_flag.py +75 -0
- app/db/alembic/versions/20260407_000000_add_bridge_gateway_safe_mode.py +51 -0
- app/db/alembic/versions/20260407_010000_merge_api_key_assignment_and_bridge_gateway_heads.py +25 -0
- app/db/alembic/versions/20260408_000000_switch_import_without_overwrite_default_to_true.py +73 -0
- app/db/alembic/versions/20260408_010000_merge_import_without_overwrite_and_assignment_heads.py +25 -0
- app/db/alembic/versions/20260409_000000_add_http_bridge_sessions.py +130 -0
- app/db/alembic/versions/20260409_000000_switch_sticky_threads_and_prefer_earlier_reset_defaults_to_true.py +89 -0
- app/db/alembic/versions/20260409_010000_add_dashboard_settings_bootstrap_token.py +57 -0
- app/db/alembic/versions/20260409_010000_merge_http_bridge_and_import_without_overwrite_heads.py +25 -0
- app/db/alembic/versions/20260409_020000_fix_http_bridge_last_seen_index.py +46 -0
- app/db/alembic/versions/20260410_000000_backfill_pristine_dashboard_settings_defaults.py +77 -0
- app/db/alembic/versions/20260410_030000_restore_import_without_overwrite_default_true.py +73 -0
- app/db/alembic/versions/20260410_040000_merge_dashboard_defaults_and_import_default_heads.py +25 -0
- app/db/alembic/versions/20260413_000000_add_accounts_blocked_at.py +44 -0
- app/db/alembic/versions/20260415_160000_add_automations_tables.py +189 -0
- app/db/alembic/versions/20260415_160000_add_request_logs_response_lookup_index.py +67 -0
- app/db/alembic/versions/20260417_000000_add_request_log_plan_type.py +44 -0
- app/db/alembic/versions/20260418_190000_add_automation_runs_cycle_key.py +87 -0
- app/db/alembic/versions/20260419_000000_add_automation_run_cycle_metadata.py +56 -0
- app/db/alembic/versions/20260419_020000_add_automation_run_cycles_snapshot_tables.py +342 -0
- app/db/alembic/versions/20260421_000000_add_dashboard_session_ttl_setting.py +51 -0
- app/db/alembic/versions/20260421_120000_merge_request_log_lookup_and_plan_type_heads.py +25 -0
- app/db/alembic/versions/20260421_130000_merge_automation_and_request_log_heads.py +25 -0
- app/db/alembic/versions/20260422_103000_normalize_legacy_automation_run_cycle_keys.py +648 -0
- app/db/alembic/versions/20260423_120000_add_api_key_limit_reset_at_index.py +43 -0
- app/db/alembic/versions/20260424_000000_merge_dashboard_session_ttl_and_request_log_heads.py +25 -0
- app/db/alembic/versions/20260426_000000_add_dashboard_relative_availability_settings.py +68 -0
- app/db/alembic/versions/20260427_130000_add_warmup_model_and_request_kind.py +75 -0
- app/db/alembic/versions/20260506_000000_add_account_routing_policy.py +37 -0
- app/db/alembic/versions/20260509_000000_add_api_key_traffic_class.py +37 -0
- app/db/alembic/versions/20260509_010000_add_additional_quota_routing_policies.py +37 -0
- app/db/alembic/versions/20260513_000000_add_accounts_alias.py +44 -0
- app/db/alembic/versions/20260513_000000_add_api_key_apply_to_codex_model.py +59 -0
- app/db/alembic/versions/20260514_000000_add_request_logs_api_key_time_index.py +43 -0
- app/db/alembic/versions/20260515_000000_add_prefer_earlier_reset_window.py +47 -0
- app/db/alembic/versions/20260515_000000_soft_delete_request_logs_on_account_delete.py +83 -0
- app/db/alembic/versions/20260515_020000_add_split_sticky_budget_thresholds.py +62 -0
- app/db/alembic/versions/20260516_000000_add_sqlite_hot_path_indexes.py +75 -0
- app/db/alembic/versions/20260517_000000_merge_sqlite_hot_path_and_request_log_delete_heads.py +24 -0
- app/db/alembic/versions/20260518_000000_add_http_bridge_durable_input_prefix.py +44 -0
- app/db/alembic/versions/20260518_010000_merge_http_bridge_and_sqlite_recovery_heads.py +25 -0
- app/db/alembic/versions/20260518_120000_add_dashboard_guest_access.py +57 -0
- app/db/alembic/versions/20260520_000000_merge_api_key_and_http_bridge_heads.py +26 -0
- app/db/alembic/versions/20260520_010000_add_request_logs_api_key_account_index.py +45 -0
- app/db/alembic/versions/20260520_010000_merge_automation_and_api_key_heads.py +26 -0
- app/db/alembic/versions/20260520_030000_add_quota_planner.py +194 -0
- app/db/alembic/versions/20260520_040000_merge_quota_planner_and_request_log_index_heads.py +24 -0
- app/db/alembic/versions/20260521_000000_add_account_security_work_authorized.py +46 -0
- app/db/alembic/versions/20260521_000000_merge_dashboard_guest_and_api_key_heads.py +26 -0
- app/db/alembic/versions/20260521_000000_merge_prefer_reset_window_head.py +26 -0
- app/db/alembic/versions/20260521_000000_merge_warmup_and_request_log_index_heads.py +25 -0
- app/db/alembic/versions/20260522_000000_add_limit_warmup_trigger.py +195 -0
- app/db/alembic/versions/20260524_000000_merge_accounts_alias_and_reset_window_heads.py +24 -0
- app/db/alembic/versions/20260525_000000_add_usage_raw_window_latest_index.py +31 -0
- app/db/alembic/versions/20260526_000000_add_request_log_failure_metadata.py +100 -0
- app/db/alembic/versions/20260531_000000_add_account_workspace_identity.py +39 -0
- app/db/alembic/versions/20260531_000000_add_single_account_routing.py +42 -0
- app/db/alembic/versions/20260601_000000_merge_relative_availability_and_usage_raw_heads.py +24 -0
- app/db/alembic/versions/20260601_010000_add_api_key_usage_sections.py +58 -0
- app/db/alembic/versions/20260601_010000_add_routing_policy_persistence.py +67 -0
- app/db/alembic/versions/20260601_010000_merge_security_work_and_relative_availability_heads.py +25 -0
- app/db/alembic/versions/20260601_010000_merge_split_sticky_and_relative_usage_heads.py +25 -0
- app/db/alembic/versions/20260601_010000_merge_warmup_and_relative_availability_heads.py +25 -0
- app/db/alembic/versions/20260601_020000_merge_additional_quota_routing_and_relative_availability_heads.py +25 -0
- app/db/alembic/versions/20260601_020000_merge_quota_planner_and_relative_availability_heads.py +25 -0
- app/db/alembic/versions/20260601_020000_merge_reset_window_and_relative_availability_heads.py +25 -0
- app/db/alembic/versions/20260601_020000_merge_routing_policy_and_split_threshold_heads.py +24 -0
- app/db/alembic/versions/20260601_020000_merge_warmup_and_request_log_failure_heads.py +25 -0
- app/db/alembic/versions/20260601_030000_merge_single_account_and_routing_quota_heads.py +29 -0
- app/db/alembic/versions/20260601_040000_merge_security_work_and_routing_consolidation_heads.py +25 -0
- app/db/alembic/versions/20260601_050000_merge_quota_planner_and_routing_consolidation_heads.py +25 -0
- app/db/alembic/versions/20260602_050000_add_upstream_proxy_routing.py +164 -0
- app/db/alembic/versions/20260602_060000_merge_account_workspace_and_failure_heads.py +25 -0
- app/db/alembic/versions/20260602_070000_add_request_log_useragent_fields.py +86 -0
- app/db/alembic/versions/20260602_070000_merge_quota_planner_and_account_workspace_heads.py +25 -0
- app/db/alembic/versions/20260602_080000_merge_upstream_proxy_and_quota_planner_heads.py +25 -0
- app/db/alembic/versions/20260602_080000_merge_useragent_and_upstream_proxy_heads.py +24 -0
- app/db/alembic/versions/20260603_000000_add_weekly_pace_working_days.py +52 -0
- app/db/alembic/versions/20260603_000000_free_account_monthly_window.py +60 -0
- app/db/alembic/versions/20260604_000000_add_reauth_required_account_status.py +159 -0
- app/db/alembic/versions/20260604_010000_merge_automations_and_reauth_status_heads.py +25 -0
- app/db/alembic/versions/20260604_010000_merge_dashboard_guest_and_reauth_status_heads.py +25 -0
- app/db/alembic/versions/20260604_010000_merge_useragent_and_reauth_heads.py +24 -0
- app/db/alembic/versions/20260607_000000_merge_weekly_monthly_useragent_heads.py +28 -0
- app/db/alembic/versions/20260608_000000_add_hide_upstream_quota_from_api_keys.py +50 -0
- app/db/alembic/versions/20260611_000000_add_request_log_archive_request_id.py +47 -0
- app/db/alembic/versions/20260611_000000_merge_automations_and_weekly_monthly_useragent_heads.py +26 -0
- app/db/alembic/versions/20260611_000000_merge_dashboard_guest_and_weekly_useragent_heads.py +26 -0
- app/db/alembic/versions/20260611_010000_add_request_log_client_ip.py +57 -0
- app/db/alembic/versions/20260611_020000_merge_request_log_archive_and_client_ip_heads.py +26 -0
- app/db/alembic/versions/20260611_030000_merge_dashboard_guest_and_request_log_client_ip_heads.py +26 -0
- app/db/alembic/versions/20260613_000000_add_accounts_codex_installation_id.py +57 -0
- app/db/alembic/versions/20260613_010000_merge_installation_id_and_dashboard_weekly_heads.py +26 -0
- app/db/alembic/versions/20260615_000000_merge_automations_and_dashboard_guest_heads.py +26 -0
- app/db/alembic/versions/20260623_000000_add_limit_warmup_exhausted_threshold.py +51 -0
- app/db/alembic/versions/20260626_000000_add_http_downstream_transport_policy.py +46 -0
- app/db/alembic/versions/20260626_010000_add_request_logs_upstream_transport.py +31 -0
- app/db/alembic/versions/20260629_000000_add_dashboard_query_hot_path_indexes.py +53 -0
- app/db/alembic/versions/20260630_000000_add_limit_warmup_staggered_idle.py +47 -0
- app/db/alembic/versions/20260630_000000_merge_request_log_client_ip_and_dashboard_hot_path_heads.py +26 -0
- app/db/alembic/versions/20260630_010000_merge_warmup_and_request_log_dashboard_heads.py +26 -0
- app/db/alembic/versions/20260630_020000_merge_automations_and_main_heads.py +26 -0
- app/db/alembic/versions/20260630_020000_merge_warmup_threshold_and_main_heads.py +26 -0
- app/db/alembic/versions/20260630_030000_add_automation_run_model_snapshot.py +59 -0
- app/db/alembic/versions/20260630_040000_merge_automation_snapshot_and_warmup_threshold_heads.py +26 -0
- app/db/alembic/versions/20260630_050000_add_automation_run_prompt_snapshot.py +52 -0
- app/db/alembic/versions/20260701_000000_add_weekly_pace_smoothing_minutes.py +51 -0
- app/db/alembic/versions/20260702_000000_add_model_sources.py +176 -0
- app/db/alembic/versions/20260705_000000_add_model_source_audio_transcriptions.py +50 -0
- app/db/alembic/versions/20260705_000000_harden_dashboard_session_ttl.py +62 -0
- app/db/alembic/versions/20260706_000000_add_model_source_audio_per_minute.py +43 -0
- app/db/alembic/versions/20260707_000000_merge_model_sources_and_session_ttl.py +24 -0
- app/db/alembic/versions/20260707_010000_merge_automations_and_model_sources_heads.py +24 -0
- app/db/alembic/versions/20260707_020000_add_automation_job_account_scope.py +125 -0
- app/db/alembic/versions/20260709_000000_add_ttft_phase_observability.py +66 -0
- app/db/alembic/versions/20260711_000000_add_dashboard_prohibit_fast_mode.py +42 -0
- app/db/alembic/versions/20260711_010000_add_account_chatgpt_user_id.py +40 -0
- app/db/alembic/versions/20260711_020000_add_dashboard_account_concurrency_caps.py +71 -0
- app/db/alembic/versions/20260711_030000_add_limit_warmup_idle_threshold.py +51 -0
- app/db/alembic/versions/20260712_010000_add_account_usage_rollups.py +56 -0
- app/db/alembic/versions/20260712_020000_add_api_key_usage_rollups.py +53 -0
- app/db/alembic/versions/20260713_020000_add_model_registry_snapshot.py +42 -0
- app/db/alembic/versions/20260713_040000_add_account_refresh_claims.py +42 -0
- app/db/alembic/versions/20260713_040000_add_replica_guardrails.py +64 -0
- app/db/alembic/versions/20260713_070000_add_reset_credit_redeem_tables.py +58 -0
- app/db/alembic/versions/20260714_000000_add_oauth_flow_states.py +63 -0
- app/db/alembic/versions/20260715_000000_add_request_log_queue_latency.py +44 -0
- app/db/alembic/versions/20260716_000000_add_oauth_device_flow_slots.py +41 -0
- app/db/alembic/versions/20260716_010000_add_dashboard_retention_settings.py +48 -0
- app/db/alembic/versions/20260716_010000_add_reset_credit_display_settings.py +73 -0
- app/db/alembic/versions/20260717_000000_add_http_bridge_retry_circuits.py +47 -0
- app/db/alembic/versions/20260717_000000_merge_retention_and_reset_credit_display_heads.py +26 -0
- app/db/alembic/versions/20260717_000000_optimize_dashboard_hot_path_indexes.py +162 -0
- app/db/alembic/versions/20260717_000001_merge_retry_circuits_and_dashboard_indexes.py +22 -0
- app/db/alembic/versions/20260720_000000_add_request_log_conversation_id.py +57 -0
- app/db/alembic/versions/20260722_000000_backfill_request_log_useragent_families.py +40 -0
- app/db/alembic/versions/20260724_000000_add_request_usage_time_rollups.py +176 -0
- app/db/alembic/versions/20260724_000000_merge_request_log_schema_heads.py +33 -0
- app/db/alembic/versions/20260725_000000_add_http_bridge_pending_tool_calls.py +43 -0
- app/db/alembic/versions/20260726_000000_add_account_plan_downgrade_observations.py +44 -0
- app/db/alembic/versions/20260726_000000_repair_request_usage_rollups_after_merge.py +37 -0
- app/db/alembic/versions/20260727_000000_add_sticky_session_continuity_abandoned_at.py +45 -0
- app/db/alembic/versions/20260728_000000_merge_pending_tool_calls_and_rollup_repair_heads.py +31 -0
- app/db/alembic/versions/20260730_000000_add_api_key_fair_share_threshold.py +44 -0
- app/db/alembic/versions/20260730_000000_add_http_bridge_recovery_attempts.py +60 -0
- app/db/alembic/versions/20260731_000000_add_capability_lineage_markers.py +38 -0
- app/db/alembic/versions/20260803_000000_merge_http_bridge_recovery_and_capability_lineage_heads.py +30 -0
- app/db/alembic/versions/20260804_000000_add_http_bridge_operations.py +63 -0
- app/db/alembic/versions/20260804_000001_add_global_http_bridge_operation_fingerprint.py +53 -0
- app/db/alembic/versions/20260804_230000_add_request_log_connection_request_kind.py +43 -0
- app/db/alembic/versions/20260805_000000_add_http_bridge_operation_spool.py +75 -0
- app/db/alembic/versions/20260805_000001_finalize_http_bridge_operation_spool.py +65 -0
- app/db/alembic/versions/20260806_000000_add_additional_usage_alias_probe_indexes.py +84 -0
- app/db/alembic/versions/20260806_000000_add_anonymous_telemetry.py +49 -0
- app/db/alembic/versions/20260806_010000_add_conversation_presence_rollup.py +72 -0
- app/db/alembic/versions/20260806_020000_add_usage_history_bulk_covering_indexes.py +99 -0
- app/db/alembic/versions/20260806_030000_add_api_key_allowed_reasoning_efforts.py +65 -0
- app/db/alembic/versions/20260806_120000_add_http_bridge_owner_process_epoch.py +57 -0
- app/db/alembic/versions/20260807_000000_merge_http_bridge_operation_spool_and_latest_main.py +24 -0
- app/db/alembic/versions/20260808_000000_tune_usage_history_autovacuum.py +54 -0
- app/db/alembic/versions/20260810_000000_add_http_bridge_recovery_dispatch_count.py +44 -0
- app/db/alembic/versions/20260811_000000_add_hourly_rollup_cancelled_count.py +92 -0
- app/db/alembic/versions/20260812_000000_merge_recovery_dispatch_and_hourly_cancelled_heads.py +25 -0
- app/db/alembic/versions/20260812_120000_add_sticky_abandonment_scope.py +43 -0
- app/db/alembic/versions/20260813_000000_add_file_account_pins.py +40 -0
- app/db/alembic/versions/20260816_000000_add_account_pending_deletion.py +81 -0
- app/db/alembic/versions/20260816_000000_add_model_source_embeddings.py +50 -0
- app/db/alembic/versions/20260821_000000_add_retry_circuit_admission_generation.py +49 -0
- app/db/alembic/versions/20260826_000000_add_http_bridge_event_chunks.py +107 -0
- app/db/alembic/versions/20260828_000000_add_accounts_chatgpt_identity_index.py +55 -0
- app/db/alembic/versions/20260830_000000_add_quota_warmup_claim_expiry.py +83 -0
- app/db/alembic/versions/20260908_000000_add_guest_session_generation.py +37 -0
- app/db/alembic/versions/20260908_000000_add_subscription_overflow.py +140 -0
- app/db/alembic/versions/20260908_000000_replace_upstream_stream_transport_default_sentinel.py +50 -0
- app/db/alembic/versions/20260908_020000_merge_overflow_transport_heads.py +27 -0
- app/db/alembic/versions/20260909_000000_add_dashboard_roles.py +72 -0
- app/db/alembic/versions/20260909_010000_add_dashboard_users.py +183 -0
- app/db/alembic/versions/20260909_020000_reproject_compat_admin_credentials.py +105 -0
- app/db/alembic/versions/20260909_030000_add_audit_actor_columns.py +103 -0
- app/db/alembic/versions/20260909_030000_dashboard_resilience_toggle_settings.py +63 -0
- app/db/alembic/versions/20260909_040000_add_dashboard_user_invites.py +54 -0
- app/db/alembic/versions/20260909_040000_dashboard_timeout_settings.py +68 -0
- app/db/alembic/versions/20260909_050000_dashboard_routing_overload_settings.py +65 -0
- app/db/alembic/versions/20260909_060000_add_report_rollup.py +74 -0
- app/db/alembic/versions/20260909_070000_automation_run_claim_budget.py +50 -0
- app/db/alembic/versions/20260909_080000_dashboard_stream_bridge_budgets.py +62 -0
- app/db/alembic/versions/20260909_090000_dashboard_background_job_toggles.py +63 -0
- app/db/alembic/versions/20260909_100000_dashboard_codex_prewarm.py +49 -0
- app/db/alembic/versions/20260909_110000_model_context_window_overrides.py +45 -0
- app/db/alembic/versions/20260909_120000_dashboard_conversation_archive.py +48 -0
- app/db/alembic/versions/20260909_130000_add_request_logs_live_facet_indexes.py +96 -0
- app/db/alembic/versions/20260910_000000_add_totp_required_for_admin_role.py +44 -0
- app/db/alembic/versions/20260910_000000_request_logs_missing_cost_index.py +52 -0
- app/db/alembic/versions/20260910_010000_add_dashboard_auth_providers.py +134 -0
- app/db/alembic/versions/20260910_010000_dashboard_spool_retention.py +52 -0
- app/db/alembic/versions/20260910_020000_add_dashboard_role_mappings.py +74 -0
- app/db/alembic/versions/20260910_143000_request_log_affinity.py +28 -0
- app/db/alembic/versions/20260910_180000_merge_affinity_guest_heads.py +17 -0
- app/db/alembic/versions/20260910_200000_merge_affinity_identity_heads.py +17 -0
- app/db/alembic/versions/20260910_220000_merge_affinity_invite_heads.py +17 -0
- app/db/alembic/versions/20260911_000000_model_source_pins_kind_expires_index.py +43 -0
- app/db/alembic/versions/20260911_010000_merge_pin_index_and_affinity_heads.py +17 -0
- app/db/alembic/versions/20260911_020000_add_http_bridge_terminal_append_phase.py +54 -0
- app/db/alembic/versions/20260911_030000_add_local_login_policy.py +48 -0
- app/db/alembic/versions/20260911_040000_add_thread_cache_identity_mode.py +48 -0
- app/db/alembic/versions/20260911_060000_add_bridge_session_continuity_abandonment.py +40 -0
- app/db/alembic/versions/20260912_000000_merge_thread_cache_and_bridge_retirement_heads.py +22 -0
- app/db/alembic/versions/20260912_010000_drop_legacy_dashboard_credentials.py +140 -0
- app/db/alembic/versions/20260913_000000_add_oidc_provider_flow.py +134 -0
- app/db/alembic/versions/20260914_000000_add_scim_tokens.py +78 -0
- app/db/alembic/versions/20260914_000000_drop_subscription_overflow_schema.py +132 -0
- app/db/alembic/versions/20260918_000000_merge_scim_and_overflow_heads.py +17 -0
- app/db/alembic/versions/__init__.py +1 -0
- app/db/backup.py +64 -0
- app/db/migrate.py +1249 -0
- app/db/migration_lock.py +160 -0
- app/db/migration_url.py +18 -0
- app/db/models.py +3100 -0
- app/db/recover.py +244 -0
- app/db/session.py +1295 -0
- app/db/snapshot.py +46 -0
- app/db/sqlite_lock_retry.py +190 -0
- app/db/sqlite_utils.py +549 -0
- app/dependencies.py +462 -0
- app/main.py +1240 -0
- app/modules/__init__.py +0 -0
- app/modules/accounts/__init__.py +0 -0
- app/modules/accounts/api.py +426 -0
- app/modules/accounts/auth_manager.py +1439 -0
- app/modules/accounts/background_repository.py +160 -0
- app/modules/accounts/deletion.py +540 -0
- app/modules/accounts/mappers.py +654 -0
- app/modules/accounts/refresh_claims.py +352 -0
- app/modules/accounts/repository.py +1679 -0
- app/modules/accounts/schemas.py +308 -0
- app/modules/accounts/service.py +809 -0
- app/modules/accounts/usage_rollup.py +486 -0
- app/modules/accounts/usage_rollup_scheduler.py +75 -0
- app/modules/accounts/usage_time_rollup.py +1037 -0
- app/modules/accounts/usage_time_rollup_read.py +522 -0
- app/modules/api_keys/__init__.py +1 -0
- app/modules/api_keys/api.py +344 -0
- app/modules/api_keys/last_used_coalescer.py +216 -0
- app/modules/api_keys/limit_windows.py +41 -0
- app/modules/api_keys/repository.py +1200 -0
- app/modules/api_keys/reset_scheduler.py +85 -0
- app/modules/api_keys/schemas.py +135 -0
- app/modules/api_keys/service.py +2123 -0
- app/modules/audit/__init__.py +0 -0
- app/modules/audit/api.py +88 -0
- app/modules/audit/repository.py +74 -0
- app/modules/audit/schemas.py +33 -0
- app/modules/audit/service.py +71 -0
- app/modules/auth_providers/__init__.py +0 -0
- app/modules/auth_providers/api.py +127 -0
- app/modules/auth_providers/config.py +343 -0
- app/modules/auth_providers/repository.py +101 -0
- app/modules/auth_providers/schemas.py +88 -0
- app/modules/auth_providers/seed.py +105 -0
- app/modules/auth_providers/service.py +289 -0
- app/modules/automations/__init__.py +1 -0
- app/modules/automations/api.py +369 -0
- app/modules/automations/repository.py +1896 -0
- app/modules/automations/scheduler.py +107 -0
- app/modules/automations/schemas.py +158 -0
- app/modules/automations/service.py +2548 -0
- app/modules/cache_isolation_probe/__init__.py +0 -0
- app/modules/cache_isolation_probe/api.py +188 -0
- app/modules/cache_isolation_probe/prefix.py +144 -0
- app/modules/cache_isolation_probe/schemas.py +94 -0
- app/modules/cache_isolation_probe/sender.py +229 -0
- app/modules/cache_isolation_probe/service.py +525 -0
- app/modules/conversation_archive/__init__.py +1 -0
- app/modules/conversation_archive/api.py +101 -0
- app/modules/conversation_archive/schemas.py +28 -0
- app/modules/conversation_archive/service.py +165 -0
- app/modules/dashboard/__init__.py +1 -0
- app/modules/dashboard/api.py +106 -0
- app/modules/dashboard/builders.py +107 -0
- app/modules/dashboard/repository.py +304 -0
- app/modules/dashboard/schemas.py +148 -0
- app/modules/dashboard/service.py +534 -0
- app/modules/dashboard/timeframes.py +19 -0
- app/modules/dashboard/weekly_pace.py +617 -0
- app/modules/dashboard_auth/__init__.py +1 -0
- app/modules/dashboard_auth/api.py +1344 -0
- app/modules/dashboard_auth/oidc_api.py +753 -0
- app/modules/dashboard_auth/oidc_flows.py +330 -0
- app/modules/dashboard_auth/repository.py +452 -0
- app/modules/dashboard_auth/schemas.py +232 -0
- app/modules/dashboard_auth/service.py +1384 -0
- app/modules/dashboard_roles/__init__.py +0 -0
- app/modules/dashboard_roles/api.py +64 -0
- app/modules/dashboard_roles/repository.py +54 -0
- app/modules/dashboard_roles/schemas.py +29 -0
- app/modules/dashboard_roles/seed.py +80 -0
- app/modules/dashboard_roles/service.py +142 -0
- app/modules/dashboard_users/__init__.py +0 -0
- app/modules/dashboard_users/api.py +278 -0
- app/modules/dashboard_users/break_glass.py +169 -0
- app/modules/dashboard_users/credentials.py +18 -0
- app/modules/dashboard_users/identity_resolver.py +665 -0
- app/modules/dashboard_users/repository.py +725 -0
- app/modules/dashboard_users/schemas.py +117 -0
- app/modules/dashboard_users/service.py +1054 -0
- app/modules/firewall/__init__.py +1 -0
- app/modules/firewall/api.py +78 -0
- app/modules/firewall/repository.py +51 -0
- app/modules/firewall/schemas.py +28 -0
- app/modules/firewall/service.py +93 -0
- app/modules/fleet/__init__.py +1 -0
- app/modules/fleet/api.py +177 -0
- app/modules/fleet/mappers.py +56 -0
- app/modules/fleet/observability.py +372 -0
- app/modules/fleet/schemas.py +119 -0
- app/modules/health/__init__.py +0 -0
- app/modules/health/api.py +246 -0
- app/modules/health/schemas.py +27 -0
- app/modules/limit_warmup/__init__.py +1 -0
- app/modules/limit_warmup/repository.py +159 -0
- app/modules/limit_warmup/service.py +1001 -0
- app/modules/model_sources/__init__.py +1 -0
- app/modules/model_sources/api.py +99 -0
- app/modules/model_sources/catalog.py +307 -0
- app/modules/model_sources/forwarding.py +1435 -0
- app/modules/model_sources/projection.py +55 -0
- app/modules/model_sources/repository.py +201 -0
- app/modules/model_sources/schemas.py +79 -0
- app/modules/model_sources/selection.py +166 -0
- app/modules/model_sources/service.py +236 -0
- app/modules/oauth/__init__.py +0 -0
- app/modules/oauth/api.py +101 -0
- app/modules/oauth/repository.py +238 -0
- app/modules/oauth/schemas.py +49 -0
- app/modules/oauth/service.py +1196 -0
- app/modules/oauth/templates/oauth_success.html +122 -0
- app/modules/proxy/__init__.py +0 -0
- app/modules/proxy/_load_balancer/__init__.py +1 -0
- app/modules/proxy/_load_balancer/error_rate.py +116 -0
- app/modules/proxy/_load_balancer/latency_cohort.py +154 -0
- app/modules/proxy/_load_balancer/model_eligibility.py +250 -0
- app/modules/proxy/_load_balancer/opportunistic_admission.py +350 -0
- app/modules/proxy/_load_balancer/overload_backoff.py +394 -0
- app/modules/proxy/_load_balancer/sticky_selection.py +2417 -0
- app/modules/proxy/_load_balancer/throughput_cohort.py +233 -0
- app/modules/proxy/_load_balancer/ttft_cohort.py +214 -0
- app/modules/proxy/_load_balancer/tunables.py +97 -0
- app/modules/proxy/_load_balancer/types.py +96 -0
- app/modules/proxy/_load_balancer/unbound_selection.py +534 -0
- app/modules/proxy/_service/__init__.py +6 -0
- app/modules/proxy/_service/api_key_usage.py +745 -0
- app/modules/proxy/_service/clock_budget.py +38 -0
- app/modules/proxy/_service/codex_control.py +611 -0
- app/modules/proxy/_service/compact.py +2211 -0
- app/modules/proxy/_service/file_ops.py +749 -0
- app/modules/proxy/_service/http_bridge/__init__.py +3 -0
- app/modules/proxy/_service/http_bridge/accepted_replay.py +331 -0
- app/modules/proxy/_service/http_bridge/account_sessions.py +57 -0
- app/modules/proxy/_service/http_bridge/activity.py +178 -0
- app/modules/proxy/_service/http_bridge/helpers.py +3959 -0
- app/modules/proxy/_service/http_bridge/mixin.py +2435 -0
- app/modules/proxy/_service/http_bridge/owner_forwarding.py +609 -0
- app/modules/proxy/_service/http_bridge/protocol.py +167 -0
- app/modules/proxy/_service/http_bridge/proxy_failover.py +58 -0
- app/modules/proxy/_service/http_bridge/quarantine.py +443 -0
- app/modules/proxy/_service/http_bridge/request_submit.py +4582 -0
- app/modules/proxy/_service/http_bridge/retry_circuit.py +2442 -0
- app/modules/proxy/_service/http_bridge/service_stubs.py +492 -0
- app/modules/proxy/_service/http_bridge/session_registry.py +778 -0
- app/modules/proxy/_service/http_bridge/streaming.py +5328 -0
- app/modules/proxy/_service/http_bridge/upstream_events.py +4538 -0
- app/modules/proxy/_service/observability.py +410 -0
- app/modules/proxy/_service/rate_limit.py +361 -0
- app/modules/proxy/_service/realtime_live.py +655 -0
- app/modules/proxy/_service/refresh.py +154 -0
- app/modules/proxy/_service/request_log.py +585 -0
- app/modules/proxy/_service/response_create.py +930 -0
- app/modules/proxy/_service/streaming/__init__.py +3 -0
- app/modules/proxy/_service/streaming/helpers.py +1317 -0
- app/modules/proxy/_service/streaming/mixin.py +1100 -0
- app/modules/proxy/_service/streaming/protocol.py +32 -0
- app/modules/proxy/_service/streaming/retry.py +3762 -0
- app/modules/proxy/_service/support.py +2122 -0
- app/modules/proxy/_service/transcribe.py +434 -0
- app/modules/proxy/_service/warmup.py +483 -0
- app/modules/proxy/_service/websocket/__init__.py +3 -0
- app/modules/proxy/_service/websocket/helpers.py +2360 -0
- app/modules/proxy/_service/websocket/mixin.py +7285 -0
- app/modules/proxy/_service/websocket/protocol.py +74 -0
- app/modules/proxy/account_cache.py +229 -0
- app/modules/proxy/account_eligibility.py +87 -0
- app/modules/proxy/additional_model_limits.py +40 -0
- app/modules/proxy/affinity.py +830 -0
- app/modules/proxy/affinity_observation.py +101 -0
- app/modules/proxy/api.py +10254 -0
- app/modules/proxy/api_key_usage.py +113 -0
- app/modules/proxy/cap_partitioning.py +280 -0
- app/modules/proxy/capability_lineage.py +65 -0
- app/modules/proxy/capability_lineage_repository.py +82 -0
- app/modules/proxy/capability_routing.py +253 -0
- app/modules/proxy/continuity.py +112 -0
- app/modules/proxy/downstream_delivery.py +277 -0
- app/modules/proxy/durable_bridge_coordinator.py +1217 -0
- app/modules/proxy/durable_bridge_repository.py +4516 -0
- app/modules/proxy/durable_bridge_runtime.py +9 -0
- app/modules/proxy/durable_bridge_transcript_codec.py +122 -0
- app/modules/proxy/fair_share.py +131 -0
- app/modules/proxy/file_pin_repository.py +210 -0
- app/modules/proxy/helpers.py +439 -0
- app/modules/proxy/http_bridge_event_batcher.py +613 -0
- app/modules/proxy/http_bridge_forwarding.py +797 -0
- app/modules/proxy/http_continuation.py +76 -0
- app/modules/proxy/images_observability.py +62 -0
- app/modules/proxy/images_service.py +1054 -0
- app/modules/proxy/load_balancer.py +3016 -0
- app/modules/proxy/rate_limit_cache.py +46 -0
- app/modules/proxy/replay_safety.py +1063 -0
- app/modules/proxy/repo_bundle.py +31 -0
- app/modules/proxy/request_policy.py +1054 -0
- app/modules/proxy/ring_membership.py +251 -0
- app/modules/proxy/schemas.py +345 -0
- app/modules/proxy/selection_errors.py +41 -0
- app/modules/proxy/service.py +2600 -0
- app/modules/proxy/source_admission.py +125 -0
- app/modules/proxy/source_dispatch.py +999 -0
- app/modules/proxy/sticky_repository.py +831 -0
- app/modules/proxy/thread_anchors.py +491 -0
- app/modules/proxy/tool_call_dedupe.py +802 -0
- app/modules/proxy/types.py +54 -0
- app/modules/proxy/work_admission.py +121 -0
- app/modules/quota_planner/__init__.py +1 -0
- app/modules/quota_planner/api.py +276 -0
- app/modules/quota_planner/logic.py +743 -0
- app/modules/quota_planner/repository.py +722 -0
- app/modules/quota_planner/scheduler.py +212 -0
- app/modules/quota_planner/schemas.py +102 -0
- app/modules/quota_planner/warmup.py +693 -0
- app/modules/rate_limit_reset_credits/__init__.py +0 -0
- app/modules/rate_limit_reset_credits/api.py +601 -0
- app/modules/rate_limit_reset_credits/redeem_coordination.py +274 -0
- app/modules/rate_limit_reset_credits/store.py +114 -0
- app/modules/reports/__init__.py +1 -0
- app/modules/reports/api.py +134 -0
- app/modules/reports/cache.py +74 -0
- app/modules/reports/filters.py +27 -0
- app/modules/reports/repository.py +525 -0
- app/modules/reports/rollup.py +150 -0
- app/modules/reports/rollup_read.py +148 -0
- app/modules/reports/schemas.py +123 -0
- app/modules/reports/service.py +287 -0
- app/modules/reports/thread_identity.py +256 -0
- app/modules/request_logs/__init__.py +0 -0
- app/modules/request_logs/api.py +224 -0
- app/modules/request_logs/cost_backfill.py +154 -0
- app/modules/request_logs/mappers.py +97 -0
- app/modules/request_logs/repository.py +1765 -0
- app/modules/request_logs/schemas.py +145 -0
- app/modules/request_logs/service.py +348 -0
- app/modules/role_mappings/__init__.py +0 -0
- app/modules/role_mappings/api.py +206 -0
- app/modules/role_mappings/matching.py +55 -0
- app/modules/role_mappings/repository.py +106 -0
- app/modules/role_mappings/schemas.py +67 -0
- app/modules/role_mappings/service.py +334 -0
- app/modules/runtime/__init__.py +1 -0
- app/modules/runtime/api.py +18 -0
- app/modules/runtime/schemas.py +14 -0
- app/modules/runtime/service.py +218 -0
- app/modules/scim/__init__.py +1 -0
- app/modules/scim/api.py +194 -0
- app/modules/scim/dependencies.py +112 -0
- app/modules/scim/errors.py +77 -0
- app/modules/scim/management_api.py +156 -0
- app/modules/scim/repository.py +212 -0
- app/modules/scim/schemas.py +145 -0
- app/modules/scim/service.py +786 -0
- app/modules/scim/tokens.py +43 -0
- app/modules/settings/__init__.py +1 -0
- app/modules/settings/api.py +1677 -0
- app/modules/settings/repository.py +606 -0
- app/modules/settings/schemas.py +496 -0
- app/modules/settings/service.py +769 -0
- app/modules/shared/__init__.py +0 -0
- app/modules/shared/schemas.py +22 -0
- app/modules/sticky_sessions/__init__.py +1 -0
- app/modules/sticky_sessions/api.py +118 -0
- app/modules/sticky_sessions/cleanup_scheduler.py +487 -0
- app/modules/sticky_sessions/schemas.py +78 -0
- app/modules/sticky_sessions/service.py +196 -0
- app/modules/telemetry/__init__.py +5 -0
- app/modules/telemetry/api.py +115 -0
- app/modules/telemetry/clients.py +62 -0
- app/modules/telemetry/consent.py +115 -0
- app/modules/telemetry/scheduler.py +85 -0
- app/modules/telemetry/schemas.py +163 -0
- app/modules/telemetry/sender.py +221 -0
- app/modules/telemetry/snapshot.py +490 -0
- app/modules/usage/__init__.py +0 -0
- app/modules/usage/additional_quota_keys.py +379 -0
- app/modules/usage/api.py +45 -0
- app/modules/usage/background_repository.py +147 -0
- app/modules/usage/builders.py +559 -0
- app/modules/usage/depletion_service.py +277 -0
- app/modules/usage/live_ingest.py +356 -0
- app/modules/usage/mappers.py +29 -0
- app/modules/usage/plan_downgrade_observations.py +488 -0
- app/modules/usage/repository.py +1890 -0
- app/modules/usage/schemas.py +68 -0
- app/modules/usage/service.py +102 -0
- app/modules/usage/updater.py +1488 -0
- app/static/assets/Trans-Cj-J9mVA.js +1 -0
- app/static/assets/access-page-DHzZiXZi.js +1 -0
- app/static/assets/account-cost-donut-DGhfA4U8.js +1 -0
- app/static/assets/account-identifiers-CxbdLshZ.js +1 -0
- app/static/assets/account-status-DIsU5sUS.js +1 -0
- app/static/assets/account-trend-chart-BptlfwwQ.js +1 -0
- app/static/assets/accounts-page-Bbai8ift.js +3 -0
- app/static/assets/api-Dwa7XxPe.js +1 -0
- app/static/assets/api-client-dugX1Pti.js +55 -0
- app/static/assets/api-key-create-dialog-DnRm0oYN.js +1 -0
- app/static/assets/api-key-created-dialog-B6jkDG9f.js +1 -0
- app/static/assets/api-key-edit-dialog-Ck3Bnc3V.js +1 -0
- app/static/assets/api-trend-chart-BchCw7Hj.js +1 -0
- app/static/assets/apis-page-BvXz9c6i.js +2 -0
- app/static/assets/arrow-up-Dqh_KzJo.js +1 -0
- app/static/assets/arrow-up-down-LBRgVDGY.js +1 -0
- app/static/assets/automations-page-DQgNAJOR.js +3 -0
- app/static/assets/badge-DqMb9es0.js +1 -0
- app/static/assets/blur-email-HEvKagG2.js +1 -0
- app/static/assets/button-BjVmmiGW.js +1 -0
- app/static/assets/checkbox-apsl9vzk.js +1 -0
- app/static/assets/chevron-left-1d_pHVa5.js +1 -0
- app/static/assets/circle-alert-BS0xd_o1.js +1 -0
- app/static/assets/clsx-DB0hHKMi.js +1 -0
- app/static/assets/colors-BBy8GEtr.js +1 -0
- app/static/assets/copy-button-D7nAvOKR.js +1 -0
- app/static/assets/cost-per-day-chart-YdqlkZVM.js +1 -0
- app/static/assets/createLucideIcon-DBLzLNh2.js +1 -0
- app/static/assets/dashboard-page-CSdhBy0f.js +2 -0
- app/static/assets/distribution-metric-format-yZTy1ZEu.js +1 -0
- app/static/assets/donut-chart-Bxc69cra.js +1 -0
- app/static/assets/download-kQteIcsB.js +1 -0
- app/static/assets/ellipsis-B_5OgIre.js +1 -0
- app/static/assets/empty-state-JcA7tc8m.js +1 -0
- app/static/assets/es2015-bMH8YKZT.js +41 -0
- app/static/assets/es6-B264ni6W.js +69 -0
- app/static/assets/external-link-UVAOgMQ0.js +1 -0
- app/static/assets/i18n-BWqZ9Ua2.js +1 -0
- app/static/assets/inbox-B_RM2s1J.js +1 -0
- app/static/assets/index-DIpd264Z.js +23 -0
- app/static/assets/index-DMeLKRJx.css +2 -0
- app/static/assets/inherit-badge-QhTYVaU6.js +1 -0
- app/static/assets/invite-dialog-0CYh0GiQ.js +1 -0
- app/static/assets/iso-Bpe5Ihbb.js +1 -0
- app/static/assets/label-CGaLmLNf.js +1 -0
- app/static/assets/lazy-recharts-Pv8p9ArM.js +2 -0
- app/static/assets/loading-overlay-CzKQfHLI.js +1 -0
- app/static/assets/mini-quota-bar-cGT_t8Ae.js +1 -0
- app/static/assets/model-distribution-donut-BKjAfT48.js +1 -0
- app/static/assets/model-source-multi-select-D2d06Vc7.js +1 -0
- app/static/assets/multi-select-filter-KIA5qU6Z.js +1 -0
- app/static/assets/oauth-dialog-XeaGGDjS.js +1 -0
- app/static/assets/pagination-controls-D1Ypd0RU.js +1 -0
- app/static/assets/payload-CIYnGZz9.js +1 -0
- app/static/assets/queue-wait-chart-VoV7Yg9L.js +1 -0
- app/static/assets/report-chart-card-BXDliwcc.js +1 -0
- app/static/assets/reports-page-CGCJeMHG.js +3 -0
- app/static/assets/reset-credit-confirm-dialog-QOifTnVB.js +1 -0
- app/static/assets/rolldown-runtime-hePW80VL.js +1 -0
- app/static/assets/search-HfhqwERt.js +1 -0
- app/static/assets/select-Cl33bz-g.js +1 -0
- app/static/assets/settings-page-mZj01HYl.js +2 -0
- app/static/assets/shim-CZwyM4Q7.js +1 -0
- app/static/assets/skeleton-C_EUc4Rp.js +1 -0
- app/static/assets/sparkline-chart-DdNNsddM.js +1 -0
- app/static/assets/status-badge-CHHA5X6c.js +1 -0
- app/static/assets/switch-CzxgokcM.js +1 -0
- app/static/assets/table-DXaNSQ0G.js +1 -0
- app/static/assets/time-to-first-token-chart--68L0u_v.js +1 -0
- app/static/assets/tokens-per-day-chart-Cs82BFuE.js +1 -0
- app/static/assets/tokens-per-second-chart-AD2dfOn6.js +1 -0
- app/static/assets/totp-settings-CRHtxQ7j.js +1 -0
- app/static/assets/trash-D3KyWr1h.js +1 -0
- app/static/assets/use-account-quota-display-BPmrTBTC.js +1 -0
- app/static/assets/use-accounts-PWlVGw3z.js +1 -0
- app/static/assets/use-auth-CuDlW3iC.js +1 -0
- app/static/assets/use-chart-colors-DIu6tClI.js +1 -0
- app/static/assets/use-model-sources-Bul24JBu.js +1 -0
- app/static/assets/use-models-DUCPUuZg.js +1 -0
- app/static/assets/use-reduced-motion-hAm5r6_d.js +1 -0
- app/static/assets/useTranslation--56nHhlH.js +1 -0
- app/static/assets/useragent-distribution-donut-Dup6sf_n.js +1 -0
- app/static/assets/users-uIC3TIlE.js +1 -0
- app/static/assets/vendor-query-_bHZuxEx.js +1 -0
- app/static/assets/vendor-react-BVL0YZPW.js +9 -0
- app/static/favicon.svg +10 -0
- app/static/fonts/GeistSans-Variable.woff2 +0 -0
- app/static/fonts/jetbrains-mono-latin-ext.woff2 +0 -0
- app/static/fonts/jetbrains-mono-latin.woff2 +0 -0
- app/static/index.html +29 -0
- codexlb_up-1.25.0b10.dist-info/METADATA +124 -0
- codexlb_up-1.25.0b10.dist-info/RECORD +827 -0
- codexlb_up-1.25.0b10.dist-info/WHEEL +4 -0
- codexlb_up-1.25.0b10.dist-info/entry_points.txt +3 -0
- codexlb_up-1.25.0b10.dist-info/licenses/LICENSE +21 -0
- config/additional_quota_registry.json +11 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
import anyio
|
|
6
|
+
|
|
7
|
+
from app.core.cache.invalidation import NAMESPACE_SETTINGS, get_cache_invalidation_poller
|
|
8
|
+
from app.db.models import DashboardSettings
|
|
9
|
+
from app.db.session import SessionLocal
|
|
10
|
+
from app.modules.settings.repository import SettingsRepository
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SettingsCache:
|
|
14
|
+
def __init__(self, *, ttl_seconds: float = 5.0) -> None:
|
|
15
|
+
if ttl_seconds <= 0:
|
|
16
|
+
raise ValueError("ttl_seconds must be positive")
|
|
17
|
+
self._ttl_seconds = ttl_seconds
|
|
18
|
+
self._cached_settings: DashboardSettings | None = None
|
|
19
|
+
self._cached_at = 0.0
|
|
20
|
+
# The last row ever loaded, kept across ``invalidate`` for the
|
|
21
|
+
# fallback readers of ``cached_row`` (see its docstring).
|
|
22
|
+
self._last_loaded_settings: DashboardSettings | None = None
|
|
23
|
+
self._lock = anyio.Lock()
|
|
24
|
+
|
|
25
|
+
async def get(self) -> DashboardSettings:
|
|
26
|
+
now = time.monotonic()
|
|
27
|
+
if self._cached_settings is not None and now - self._cached_at < self._ttl_seconds:
|
|
28
|
+
return self._cached_settings
|
|
29
|
+
|
|
30
|
+
async with self._lock:
|
|
31
|
+
now = time.monotonic()
|
|
32
|
+
if self._cached_settings is not None and now - self._cached_at < self._ttl_seconds:
|
|
33
|
+
return self._cached_settings
|
|
34
|
+
|
|
35
|
+
async with SessionLocal() as session:
|
|
36
|
+
settings = await SettingsRepository(session).get_or_create()
|
|
37
|
+
self._cached_settings = settings
|
|
38
|
+
self._last_loaded_settings = settings
|
|
39
|
+
self._cached_at = now
|
|
40
|
+
return settings
|
|
41
|
+
|
|
42
|
+
async def refresh(self) -> DashboardSettings:
|
|
43
|
+
"""Load the row now and make it the current snapshot.
|
|
44
|
+
|
|
45
|
+
Registered as a cache-invalidation callback for the ``settings``
|
|
46
|
+
namespace so that a dashboard change reaches every replica on the bus
|
|
47
|
+
instead of waiting for the next request to pull it in. That bound
|
|
48
|
+
matters for readers that cannot await — the conversation archive gate
|
|
49
|
+
runs per archived frame, and a replica carrying only already-open
|
|
50
|
+
streams would otherwise keep the previous value indefinitely.
|
|
51
|
+
"""
|
|
52
|
+
async with self._lock:
|
|
53
|
+
async with SessionLocal() as session:
|
|
54
|
+
settings = await SettingsRepository(session).get_or_create()
|
|
55
|
+
self._cached_settings = settings
|
|
56
|
+
self._last_loaded_settings = settings
|
|
57
|
+
self._cached_at = time.monotonic()
|
|
58
|
+
return settings
|
|
59
|
+
|
|
60
|
+
def cached_row(self) -> DashboardSettings | None:
|
|
61
|
+
"""The last row this cache loaded, even if past its TTL or invalidated.
|
|
62
|
+
|
|
63
|
+
``None`` only before the first successful load. For callers that must
|
|
64
|
+
not fail when a refresh is impossible or has not happened yet (the
|
|
65
|
+
request-scoped dashboard overrides, the conversation archive gate) and
|
|
66
|
+
prefer the last known dashboard values over silently reverting to the
|
|
67
|
+
environment: an invalidation means "reload before trusting this as
|
|
68
|
+
current", not "the operator never configured anything".
|
|
69
|
+
"""
|
|
70
|
+
return self._last_loaded_settings
|
|
71
|
+
|
|
72
|
+
async def invalidate(self, *, propagate: bool = True) -> None:
|
|
73
|
+
"""Drop the cached settings row and, unless ``propagate`` is False, durably
|
|
74
|
+
bump the cross-replica ``settings`` namespace before returning.
|
|
75
|
+
|
|
76
|
+
Settings mutations are security-bearing (password hash, guest access, TOTP,
|
|
77
|
+
API-key auth toggle), so the bump is awaited rather than coalesced. The
|
|
78
|
+
cache-invalidation poller callback registers ``propagate=False`` so a remote
|
|
79
|
+
bump never re-bumps (feedback-loop prevention).
|
|
80
|
+
|
|
81
|
+
``cached_row`` keeps returning the last loaded row: dropping it here
|
|
82
|
+
would make the fallback readers revert to the environment values in the
|
|
83
|
+
window between an invalidation and the next load, which for a toggle
|
|
84
|
+
such as the conversation archive means the deprecated environment alias
|
|
85
|
+
could resume recording that an operator just turned off.
|
|
86
|
+
"""
|
|
87
|
+
async with self._lock:
|
|
88
|
+
self._cached_settings = None
|
|
89
|
+
self._cached_at = 0.0
|
|
90
|
+
if propagate:
|
|
91
|
+
poller = get_cache_invalidation_poller()
|
|
92
|
+
if poller is not None:
|
|
93
|
+
await poller.bump(NAMESPACE_SETTINGS)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
_settings_cache = SettingsCache()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def get_settings_cache() -> SettingsCache:
|
|
100
|
+
return _settings_cache
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""Dashboard-managed retention of the durable HTTP-bridge operation spool (R2, slop-removal 0908).
|
|
2
|
+
|
|
3
|
+
``http_responses_session_bridge_operation_spool_retention_seconds`` is a
|
|
4
|
+
nullable ``dashboard_settings`` column that inherits the deprecated
|
|
5
|
+
``CODEX_LB_*`` environment alias and then the code default (7 days), resolved
|
|
6
|
+
through :func:`resolve_inheritable`. Its home is the dashboard's data retention
|
|
7
|
+
card because the spool holds raw request payloads: a shorter window deletes
|
|
8
|
+
prompt material sooner.
|
|
9
|
+
|
|
10
|
+
The window has a floor. The spool is the replay source for durable bridge
|
|
11
|
+
recovery, so it must outlive every window in which something may still read a
|
|
12
|
+
spooled operation (:func:`operation_spool_retention_floor_seconds`). Purging
|
|
13
|
+
earlier deletes the transcript out from under a live reader -- which is why
|
|
14
|
+
abandoned durable bridge rows are already retained for the session reuse window
|
|
15
|
+
(``responses-api-compat`` "Retain completed recovery transcripts").
|
|
16
|
+
|
|
17
|
+
Neither consumer is on a request path: startup runs one bounded purge and the
|
|
18
|
+
leader-gated cleanup scheduler runs one pass per tick, each resolving the value
|
|
19
|
+
once per pass from the dashboard snapshot it already holds -- never inside a
|
|
20
|
+
runtime lock and never per operation.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import logging
|
|
26
|
+
from typing import Final
|
|
27
|
+
|
|
28
|
+
from app.core.config.inheritable import resolve_inheritable
|
|
29
|
+
from app.core.config.settings import Settings, get_settings
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
# ``dashboard_settings`` column, ``Settings`` field and provenance key share
|
|
34
|
+
# one name (configuration-tiers).
|
|
35
|
+
OPERATION_SPOOL_RETENTION_SETTING: Final = "http_responses_session_bridge_operation_spool_retention_seconds"
|
|
36
|
+
|
|
37
|
+
# NOT NULL ``dashboard_settings`` columns; no environment layer.
|
|
38
|
+
_DASHBOARD_REUSE_WINDOW_COLUMNS: Final[tuple[str, ...]] = (
|
|
39
|
+
"openai_cache_affinity_max_age_seconds",
|
|
40
|
+
"http_responses_session_bridge_prompt_cache_idle_ttl_seconds",
|
|
41
|
+
)
|
|
42
|
+
_BRIDGE_REQUEST_BUDGET_SETTING: Final = "http_responses_session_bridge_request_budget_seconds"
|
|
43
|
+
|
|
44
|
+
# Settings whose value moves the floor, so a PUT touching any of them is
|
|
45
|
+
# re-checked against it.
|
|
46
|
+
SPOOL_RETENTION_FLOOR_INPUTS: Final[tuple[str, ...]] = (
|
|
47
|
+
*_DASHBOARD_REUSE_WINDOW_COLUMNS,
|
|
48
|
+
_BRIDGE_REQUEST_BUDGET_SETTING,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
_OPERATION_SPOOL_RETENTION_DEFAULT: Final[float] = float(
|
|
52
|
+
Settings.model_fields[OPERATION_SPOOL_RETENTION_SETTING].default
|
|
53
|
+
)
|
|
54
|
+
_BRIDGE_REQUEST_BUDGET_DEFAULT: Final[float] = float(Settings.model_fields[_BRIDGE_REQUEST_BUDGET_SETTING].default)
|
|
55
|
+
# Floor of the stale-operation abandonment sweep's inactivity window
|
|
56
|
+
# (``session_registry.abandon_stale_http_bridge_operations``).
|
|
57
|
+
_STALE_OPERATION_ABANDONMENT_FLOOR_SECONDS: Final[float] = 30.0 * 60.0
|
|
58
|
+
# An ever-claimed retry circuit gets one extra TTL of grace in both
|
|
59
|
+
# ``retry_circuit`` and ``purge_retry_circuits_before``, because a claim leaves
|
|
60
|
+
# ``updated_at_epoch`` untouched.
|
|
61
|
+
_CLAIMED_RETRY_CIRCUIT_TTL_MULTIPLIER: Final[float] = 2.0
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _effective_seconds(dashboard_settings: object | None, name: str, environment_value: float, default: float) -> float:
|
|
65
|
+
"""One inheritable duration from either snapshot shape.
|
|
66
|
+
|
|
67
|
+
Accepts the ``DashboardSettings`` row (a NULL column inherits) and the
|
|
68
|
+
``DashboardSettingsData`` the settings API builds (already effective, so
|
|
69
|
+
the value resolves to itself).
|
|
70
|
+
"""
|
|
71
|
+
column_value = getattr(dashboard_settings, name, None)
|
|
72
|
+
return float(
|
|
73
|
+
resolve_inheritable(None if column_value is None else float(column_value), environment_value, default).value
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def bridge_session_reuse_window_seconds(dashboard_settings: object) -> float:
|
|
78
|
+
"""Longest window in which an idle durable bridge session stays reusable.
|
|
79
|
+
|
|
80
|
+
An idle local bridge session stays reusable until its effective idle TTL --
|
|
81
|
+
up to the prompt-cache reuse TTL for prompt-cache sessions -- which can
|
|
82
|
+
exceed the prompt-cache affinity max age. The two idle TTLs are fixed
|
|
83
|
+
constants (#2256) read through their module at call time, so a test
|
|
84
|
+
monkeypatching the attribute is honoured here too; the import is lazy
|
|
85
|
+
because this module is configuration and that module is the request-path
|
|
86
|
+
implementation owning them.
|
|
87
|
+
|
|
88
|
+
Both column terms are NOT NULL on ``dashboard_settings``, so a real row
|
|
89
|
+
always carries them; a term is skipped only for the partial snapshot fakes
|
|
90
|
+
the startup and scheduler tests build, the same tolerance
|
|
91
|
+
``warn_environment_shadowed_by_dashboard`` and ``effective_settings`` apply
|
|
92
|
+
to that row.
|
|
93
|
+
"""
|
|
94
|
+
from app.modules.proxy._service.http_bridge import helpers as _http_bridge_helpers
|
|
95
|
+
|
|
96
|
+
terms = [
|
|
97
|
+
float(_http_bridge_helpers.HTTP_BRIDGE_IDLE_TTL_SECONDS),
|
|
98
|
+
float(_http_bridge_helpers.HTTP_BRIDGE_CODEX_IDLE_TTL_SECONDS),
|
|
99
|
+
]
|
|
100
|
+
for name in _DASHBOARD_REUSE_WINDOW_COLUMNS:
|
|
101
|
+
value = getattr(dashboard_settings, name, None)
|
|
102
|
+
if value is not None:
|
|
103
|
+
terms.append(float(value))
|
|
104
|
+
return max(terms)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def spool_retention_floor_terms_seconds(
|
|
108
|
+
dashboard_settings: object,
|
|
109
|
+
*,
|
|
110
|
+
startup_settings: object | None = None,
|
|
111
|
+
) -> dict[str, float]:
|
|
112
|
+
"""Every window that may still read a spooled operation, by term name.
|
|
113
|
+
|
|
114
|
+
- ``bridge_session_reuse_window``: while the owning session is still
|
|
115
|
+
reusable, the next request on it resolves the operation ledger and may
|
|
116
|
+
replay a spooled transcript.
|
|
117
|
+
- ``stale_operation_abandonment_window``: until the abandonment sweep
|
|
118
|
+
fences an ownerless nonterminal operation, that operation is still
|
|
119
|
+
reading and appending its own spool.
|
|
120
|
+
- ``claimed_retry_circuit_lifetime``: a surviving retry circuit can admit a
|
|
121
|
+
replay of an operation whose spool must therefore still exist. A claim
|
|
122
|
+
advances only the admission generation and leaves the row timestamp
|
|
123
|
+
alone, so an ever-claimed circuit is honoured -- by both the loader and
|
|
124
|
+
the scheduled purge -- for two TTLs, not one.
|
|
125
|
+
|
|
126
|
+
The terms are read from the configuration in force, so this is a
|
|
127
|
+
steady-state bound. A live bridge session keeps the idle TTL it captured
|
|
128
|
+
(``session_registry`` only ever max-promotes it), so lowering a reuse
|
|
129
|
+
window does not shorten sessions that are already open; the abandoned-row
|
|
130
|
+
retention derived from the same windows is non-retroactive in exactly the
|
|
131
|
+
same way.
|
|
132
|
+
"""
|
|
133
|
+
from app.modules.proxy.durable_bridge_repository import DURABLE_BRIDGE_RETRY_CIRCUIT_STATE_TTL_SECONDS
|
|
134
|
+
|
|
135
|
+
startup = get_settings() if startup_settings is None else startup_settings
|
|
136
|
+
bridge_request_budget = _effective_seconds(
|
|
137
|
+
dashboard_settings,
|
|
138
|
+
_BRIDGE_REQUEST_BUDGET_SETTING,
|
|
139
|
+
float(getattr(startup, _BRIDGE_REQUEST_BUDGET_SETTING, _BRIDGE_REQUEST_BUDGET_DEFAULT)),
|
|
140
|
+
_BRIDGE_REQUEST_BUDGET_DEFAULT,
|
|
141
|
+
)
|
|
142
|
+
return {
|
|
143
|
+
"bridge_session_reuse_window": bridge_session_reuse_window_seconds(dashboard_settings),
|
|
144
|
+
"stale_operation_abandonment_window": max(_STALE_OPERATION_ABANDONMENT_FLOOR_SECONDS, bridge_request_budget),
|
|
145
|
+
"claimed_retry_circuit_lifetime": _CLAIMED_RETRY_CIRCUIT_TTL_MULTIPLIER
|
|
146
|
+
* float(DURABLE_BRIDGE_RETRY_CIRCUIT_STATE_TTL_SECONDS),
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def operation_spool_retention_floor_seconds(
|
|
151
|
+
dashboard_settings: object,
|
|
152
|
+
*,
|
|
153
|
+
startup_settings: object | None = None,
|
|
154
|
+
) -> float:
|
|
155
|
+
"""Lowest spool retention that still covers every replay window."""
|
|
156
|
+
return max(spool_retention_floor_terms_seconds(dashboard_settings, startup_settings=startup_settings).values())
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def binding_spool_retention_floor_term(
|
|
160
|
+
dashboard_settings: object,
|
|
161
|
+
*,
|
|
162
|
+
startup_settings: object | None = None,
|
|
163
|
+
) -> tuple[str, float]:
|
|
164
|
+
"""``(term name, seconds)`` of the window that binds the floor, for error messages."""
|
|
165
|
+
terms = spool_retention_floor_terms_seconds(dashboard_settings, startup_settings=startup_settings)
|
|
166
|
+
name = max(terms, key=lambda key: terms[key])
|
|
167
|
+
return name, terms[name]
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def resolve_operation_spool_retention_seconds(
|
|
171
|
+
dashboard_settings: object | None,
|
|
172
|
+
*,
|
|
173
|
+
startup_settings: object | None = None,
|
|
174
|
+
) -> float:
|
|
175
|
+
"""Effective spool retention from a dashboard-settings snapshot.
|
|
176
|
+
|
|
177
|
+
``dashboard_settings`` is a ``DashboardSettings`` row (or any object
|
|
178
|
+
exposing the same attribute; a missing attribute reads as NULL).
|
|
179
|
+
``startup_settings`` supplies the environment layer when the caller already
|
|
180
|
+
holds it; it defaults to ``get_settings()``.
|
|
181
|
+
"""
|
|
182
|
+
startup = get_settings() if startup_settings is None else startup_settings
|
|
183
|
+
return _effective_seconds(
|
|
184
|
+
dashboard_settings,
|
|
185
|
+
OPERATION_SPOOL_RETENTION_SETTING,
|
|
186
|
+
float(getattr(startup, OPERATION_SPOOL_RETENTION_SETTING, _OPERATION_SPOOL_RETENTION_DEFAULT)),
|
|
187
|
+
_OPERATION_SPOOL_RETENTION_DEFAULT,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def warn_spool_retention_below_floor(
|
|
192
|
+
dashboard_settings: object,
|
|
193
|
+
startup_settings: object | None = None,
|
|
194
|
+
) -> tuple[str, float, float] | None:
|
|
195
|
+
"""Warn once at startup when the effective spool retention is below its floor.
|
|
196
|
+
|
|
197
|
+
The environment alias alone can put a deployment below the floor while the
|
|
198
|
+
dashboard column is NULL, and the settings API never saw that value. Warning
|
|
199
|
+
here means the operator learns about it before a dashboard edit is refused.
|
|
200
|
+
Returns ``(binding term, effective retention, floor)`` when it warned, so the
|
|
201
|
+
caller can assert on it; ``None`` otherwise. Only these two numbers and the
|
|
202
|
+
term name are logged -- never the value of any other setting.
|
|
203
|
+
"""
|
|
204
|
+
retention = resolve_operation_spool_retention_seconds(dashboard_settings, startup_settings=startup_settings)
|
|
205
|
+
term, floor = binding_spool_retention_floor_term(dashboard_settings, startup_settings=startup_settings)
|
|
206
|
+
if retention >= floor:
|
|
207
|
+
return None
|
|
208
|
+
logger.warning(
|
|
209
|
+
"HTTP bridge operation spool retention is below its replay floor: %s=%gs < %gs (bound by %s). "
|
|
210
|
+
"Expired transcripts can be deleted while a recovery can still replay them; "
|
|
211
|
+
"raise the value in Settings -> Data retention. Dashboard updates that lower it further are refused.",
|
|
212
|
+
OPERATION_SPOOL_RETENTION_SETTING,
|
|
213
|
+
retention,
|
|
214
|
+
floor,
|
|
215
|
+
term,
|
|
216
|
+
)
|
|
217
|
+
return term, retention, floor
|
app/core/config/tiers.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""Configuration tiers for every ``Settings`` field (configuration-tiers capability).
|
|
2
|
+
|
|
3
|
+
Each ``CODEX_LB_*`` field belongs to exactly one tier:
|
|
4
|
+
|
|
5
|
+
- ``T0`` bootstrap: needed before the database is reachable (data dir, DB URL,
|
|
6
|
+
encryption key, migration policy, first-login token). env only.
|
|
7
|
+
- ``T1`` instance topology: legitimately differs per replica or per deployment
|
|
8
|
+
(bridge instance id/ring, bind hosts, trusted proxies, pool/worker sizes,
|
|
9
|
+
leader election, observability endpoints). env only.
|
|
10
|
+
- ``T2`` secret: encrypted in the database, env is at most a seed.
|
|
11
|
+
- ``T3`` behaviour tunable / feature flag: the dashboard (``dashboard_settings``)
|
|
12
|
+
is the management surface. A T3 field that has no ``dashboard_settings``
|
|
13
|
+
column of the same name MUST either name its existing database home in
|
|
14
|
+
``DASHBOARD_HOMES`` (``table.column``) or be listed in ``MIGRATING`` until
|
|
15
|
+
it gets one.
|
|
16
|
+
- ``T4`` incident debug: env allowed, dashboard toggle recommended.
|
|
17
|
+
|
|
18
|
+
``scripts/check_settings_tiers.py`` (run by ``make lint``) fails when a field
|
|
19
|
+
is missing here, when a T3 field has none of a same-name dashboard column, a
|
|
20
|
+
``DASHBOARD_HOMES`` mapping or a ``MIGRATING`` entry, when a ``DASHBOARD_HOMES``
|
|
21
|
+
target names a column that does not exist, or when ``.env.example`` mentions a
|
|
22
|
+
T2-T4 field. Entries for fields that no longer exist only warn, so removals can
|
|
23
|
+
land in either order.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from typing import Final, Literal
|
|
29
|
+
|
|
30
|
+
Tier = Literal["T0", "T1", "T2", "T3", "T4"]
|
|
31
|
+
|
|
32
|
+
TIERS: Final[tuple[Tier, ...]] = ("T0", "T1", "T2", "T3", "T4")
|
|
33
|
+
|
|
34
|
+
# Declaration order follows ``Settings``; the tier is the policy answer to
|
|
35
|
+
# "may this value differ between two replicas / must it exist before the DB?".
|
|
36
|
+
SETTING_TIERS: Final[dict[str, Tier]] = {
|
|
37
|
+
"data_dir": "T0",
|
|
38
|
+
"database_url": "T0",
|
|
39
|
+
"database_pool_size": "T1",
|
|
40
|
+
"database_max_overflow": "T1",
|
|
41
|
+
"database_migrate_on_startup": "T0",
|
|
42
|
+
"database_sqlite_pre_migrate_backup_enabled": "T0",
|
|
43
|
+
"database_sqlite_pre_migrate_backup_max_files": "T0",
|
|
44
|
+
"database_sqlite_startup_check_mode": "T0",
|
|
45
|
+
"database_alembic_auto_remap_enabled": "T0",
|
|
46
|
+
"database_migration_lock_timeout_seconds": "T0",
|
|
47
|
+
"upstream_base_url": "T1",
|
|
48
|
+
"upstream_connect_timeout_seconds": "T3",
|
|
49
|
+
"upstream_websocket_trust_env": "T1",
|
|
50
|
+
"proxy_request_budget_seconds": "T3",
|
|
51
|
+
"http_responses_stream_request_budget_seconds": "T3",
|
|
52
|
+
"compact_request_budget_seconds": "T3",
|
|
53
|
+
"stream_idle_timeout_seconds": "T3",
|
|
54
|
+
"sse_keepalive_interval_seconds": "T3",
|
|
55
|
+
"proxy_downstream_websocket_idle_timeout_seconds": "T3",
|
|
56
|
+
# bind host of the OAuth callback listener; policy §2 T1 example
|
|
57
|
+
"oauth_callback_host": "T1",
|
|
58
|
+
"auth_guardian_enabled": "T3",
|
|
59
|
+
"transcription_request_budget_seconds": "T3",
|
|
60
|
+
# path to a replacement quota-key registry; deployment artefact, not behaviour
|
|
61
|
+
"additional_quota_registry_file": "T1",
|
|
62
|
+
"rate_limit_reset_credits_refresh_enabled": "T3",
|
|
63
|
+
# K2 bridge: T4 kill switch for the request-path bridge, not a tunable.
|
|
64
|
+
"http_responses_session_bridge_enabled": "T4",
|
|
65
|
+
"http_responses_session_bridge_request_budget_seconds": "T3",
|
|
66
|
+
"http_responses_session_bridge_codex_prewarm_enabled": "T3",
|
|
67
|
+
"http_responses_session_bridge_max_sessions": "T1",
|
|
68
|
+
"http_responses_session_bridge_queue_limit": "T1",
|
|
69
|
+
"http_responses_session_bridge_operation_event_spool_max_bytes": "T1",
|
|
70
|
+
"http_responses_session_bridge_operation_spool_format": "T1",
|
|
71
|
+
"http_responses_session_bridge_operation_event_spool_batch_size": "T1",
|
|
72
|
+
"http_responses_session_bridge_operation_event_spool_flush_interval_seconds": "T1",
|
|
73
|
+
"http_responses_session_bridge_operation_event_spool_max_pending_events": "T1",
|
|
74
|
+
"http_responses_session_bridge_operation_event_spool_max_pending_bytes": "T1",
|
|
75
|
+
"http_responses_session_bridge_operation_spool_retention_seconds": "T3",
|
|
76
|
+
"http_responses_session_bridge_instance_id": "T1",
|
|
77
|
+
"http_responses_session_bridge_instance_ring": "T1",
|
|
78
|
+
"http_responses_session_bridge_advertise_base_url": "T1",
|
|
79
|
+
"upstream_route_cache_ttl_seconds": "T1",
|
|
80
|
+
"automations_scheduler_enabled": "T3",
|
|
81
|
+
"telemetry_enabled": "T3",
|
|
82
|
+
"telemetry_endpoint": "T1",
|
|
83
|
+
"encryption_key_file": "T0",
|
|
84
|
+
"encryption_key_fingerprint_mode": "T0",
|
|
85
|
+
"database_migrations_fail_fast": "T0",
|
|
86
|
+
"trace": "T4",
|
|
87
|
+
"conversation_archive_enabled": "T3",
|
|
88
|
+
"conversation_archive_dir": "T1",
|
|
89
|
+
"conversation_archive_queue_max_bytes": "T1",
|
|
90
|
+
"model_registry_client_version": "T1",
|
|
91
|
+
"model_registry_snapshot_max_age_seconds": "T1",
|
|
92
|
+
"model_context_window_overrides": "T3",
|
|
93
|
+
# raw socket-peer CIDRs of this replica's network namespace; sibling of the
|
|
94
|
+
# trusted-proxy CIDRs below, not of the firewall allowlist (projected IPs)
|
|
95
|
+
"proxy_unauthenticated_client_cidrs": "T1",
|
|
96
|
+
# trusted-proxy topology; policy §2 T1 example
|
|
97
|
+
"firewall_trust_proxy_headers": "T1",
|
|
98
|
+
# trusted-proxy topology; policy §2 T1 example
|
|
99
|
+
"firewall_trusted_proxy_cidrs": "T1",
|
|
100
|
+
"firewall_ip_cache_ttl_seconds": "T1",
|
|
101
|
+
# reverse-proxy trust list for scope["client"] projection (Uvicorn semantics)
|
|
102
|
+
"forwarded_allow_ips": "T1",
|
|
103
|
+
# reverse-proxy deployment dependent, self-lockout risk from the dashboard (policy D2)
|
|
104
|
+
"dashboard_auth_mode": "T1",
|
|
105
|
+
# last link of the dashboard_auth_mode trust chain: whether a loopback Host
|
|
106
|
+
# header is believed is a per-deployment reverse-proxy fact (policy D2)
|
|
107
|
+
"dashboard_trust_loopback_host_header_for_long_sessions": "T1",
|
|
108
|
+
# header name is fixed by the reverse-proxy deployment (policy D2)
|
|
109
|
+
"dashboard_auth_proxy_header": "T1",
|
|
110
|
+
# the group header the same reverse proxy sets (policy D2)
|
|
111
|
+
"dashboard_auth_proxy_groups_header": "T1",
|
|
112
|
+
"metrics_enabled": "T1",
|
|
113
|
+
"metrics_port": "T1",
|
|
114
|
+
"log_format": "T1",
|
|
115
|
+
"leader_election_enabled": "T1",
|
|
116
|
+
"leader_election_ttl_seconds": "T1",
|
|
117
|
+
"circuit_breaker_enabled": "T3",
|
|
118
|
+
"soft_drain_enabled": "T3",
|
|
119
|
+
"deterministic_failover_enabled": "T3",
|
|
120
|
+
"thread_cache_identity_mode": "T3",
|
|
121
|
+
"backpressure_max_concurrent_requests": "T1",
|
|
122
|
+
"bulkhead_proxy_limit": "T1",
|
|
123
|
+
"bulkhead_dashboard_limit": "T1",
|
|
124
|
+
# first remote login token; policy §2 lists it under T0 bootstrap, not T2
|
|
125
|
+
"dashboard_bootstrap_token": "T0",
|
|
126
|
+
# advertised client-facing address; differs per deployment
|
|
127
|
+
"connect_address": "T1",
|
|
128
|
+
# per-process asyncio.Semaphore capacity, same class as bulkhead_proxy_limit
|
|
129
|
+
"proxy_response_create_limit": "T1",
|
|
130
|
+
"proxy_account_response_create_limit": "T3",
|
|
131
|
+
"proxy_account_stream_limit": "T3",
|
|
132
|
+
"proxy_account_stream_recovery_reserve": "T3",
|
|
133
|
+
"proxy_api_key_fair_share_congestion_threshold_pct": "T3",
|
|
134
|
+
"proxy_account_inflight_penalty_pct": "T3",
|
|
135
|
+
"proxy_overload_isolation_seconds": "T3",
|
|
136
|
+
"proxy_account_error_rate_weighting_enabled": "T3",
|
|
137
|
+
"proxy_account_lease_token_weight": "T3",
|
|
138
|
+
"proxy_account_lease_ttl_seconds": "T3",
|
|
139
|
+
"proxy_account_caps_scope": "T1",
|
|
140
|
+
"proxy_account_cap_partition_scale_down_seconds": "T1",
|
|
141
|
+
"timeout_invariant_validation_strict": "T4",
|
|
142
|
+
"memory_reject_threshold_mb": "T1",
|
|
143
|
+
"event_loop_lag_warn_threshold_seconds": "T1",
|
|
144
|
+
"otel_enabled": "T1",
|
|
145
|
+
"otel_exporter_endpoint": "T1",
|
|
146
|
+
"shutdown_drain_timeout_seconds": "T1",
|
|
147
|
+
"http_connector_limit": "T1",
|
|
148
|
+
"http_connector_limit_per_host": "T1",
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# T3 fields that still live only in env. Value = target dashboard home or
|
|
152
|
+
# "backlog" while none has been designed. Remove the entry in the PR that adds
|
|
153
|
+
# the ``dashboard_settings`` column (the checker warns once it is redundant).
|
|
154
|
+
#
|
|
155
|
+
# Empty since ``constantize-token-refresh-interval``: every T3 field now has a
|
|
156
|
+
# dashboard home (a same-name ``dashboard_settings`` column or a
|
|
157
|
+
# ``DASHBOARD_HOMES`` mapping), and the last backlog entry
|
|
158
|
+
# (``token_refresh_interval_days``) became the fixed
|
|
159
|
+
# ``app/core/auth/refresh.TOKEN_REFRESH_INTERVAL_DAYS`` instead of getting a
|
|
160
|
+
# card nobody would flip. An empty registry is the intended terminal state and
|
|
161
|
+
# is not an error; the registry stays as the declared landing spot for a T3
|
|
162
|
+
# field that must ship one release ahead of its column.
|
|
163
|
+
MIGRATING: Final[dict[str, str]] = {}
|
|
164
|
+
|
|
165
|
+
# T3 fields whose database home already exists under a different column name
|
|
166
|
+
# (or in another configuration table). Value = ``table.column``; the checker
|
|
167
|
+
# fails when the column does not exist. The field's environment variable is the
|
|
168
|
+
# fallback while that column holds no decision, per the precedence rule.
|
|
169
|
+
DASHBOARD_HOMES: Final[dict[str, str]] = {
|
|
170
|
+
# persisted decision > CODEX_LB_TELEMETRY_ENABLED > default (telemetry spec)
|
|
171
|
+
"telemetry_enabled": "dashboard_settings.telemetry_consent",
|
|
172
|
+
# M4 model catalogue: one row per slug; the env dict is the per-slug fallback
|
|
173
|
+
"model_context_window_overrides": "model_context_window_overrides.context_window",
|
|
174
|
+
}
|