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,96 @@
|
|
|
1
|
+
"""Add live-row partial indexes for the unfiltered request-log facet skip scan.
|
|
2
|
+
|
|
3
|
+
The unfiltered ``GET /api/request-logs/options`` facets are computed with a
|
|
4
|
+
recursive ``facet_skip`` CTE: one ``min(column) WHERE deleted_at IS NULL AND
|
|
5
|
+
column > previous`` probe per distinct value. The existing facet indexes
|
|
6
|
+
(``idx_logs_model_effort_time``, ``idx_logs_status_error_time``,
|
|
7
|
+
``idx_logs_api_key_time``) carry soft-deleted rows too, so every probe walks
|
|
8
|
+
the whole soft-deleted cohort that shares a value before reaching the next
|
|
9
|
+
live one, and probe cost grows with the number of soft-deleted rows instead of
|
|
10
|
+
the number of distinct values. Partial indexes whose predicate matches the
|
|
11
|
+
probe's ``deleted_at IS NULL`` restore the bounded-probe contract. Account ids
|
|
12
|
+
need no live index: soft deletion detaches ``account_id`` (NULL), which an
|
|
13
|
+
``account_id > previous`` probe never walks.
|
|
14
|
+
|
|
15
|
+
PostgreSQL builds the indexes with ``CREATE INDEX CONCURRENTLY`` outside the
|
|
16
|
+
migration transaction so the proxy write path keeps inserting, and rebuilds a
|
|
17
|
+
leftover invalid index from an interrupted concurrent build instead of letting
|
|
18
|
+
``IF NOT EXISTS`` accept it by name. SQLite uses plain partial indexes.
|
|
19
|
+
|
|
20
|
+
Revision ID: 20260909_130000_add_request_logs_live_facet_indexes
|
|
21
|
+
Revises: 20260909_120000_dashboard_conversation_archive
|
|
22
|
+
Create Date: 2026-09-09
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import sqlalchemy as sa
|
|
28
|
+
from alembic import op
|
|
29
|
+
|
|
30
|
+
revision = "20260909_130000_add_request_logs_live_facet_indexes"
|
|
31
|
+
down_revision = "20260909_120000_dashboard_conversation_archive"
|
|
32
|
+
branch_labels = None
|
|
33
|
+
depends_on = None
|
|
34
|
+
|
|
35
|
+
_TABLE_NAME = "request_logs"
|
|
36
|
+
_LIVE_ROW_PREDICATE = "deleted_at IS NULL"
|
|
37
|
+
_LIVE_FACET_INDEXES: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
38
|
+
("idx_logs_live_api_key", ("api_key_id",)),
|
|
39
|
+
("idx_logs_live_model_effort", ("model", "reasoning_effort")),
|
|
40
|
+
("idx_logs_live_status_error", ("status", "error_code")),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _drop_invalid_postgres_index(index_name: str) -> None:
|
|
45
|
+
"""Drop a leftover invalid index from an interrupted CREATE INDEX CONCURRENTLY.
|
|
46
|
+
|
|
47
|
+
``IF NOT EXISTS`` would silently accept the invalid index by name, leaving
|
|
48
|
+
the facet probes without a usable live-row index.
|
|
49
|
+
"""
|
|
50
|
+
bind = op.get_bind()
|
|
51
|
+
invalid = bind.execute(
|
|
52
|
+
sa.text(
|
|
53
|
+
"SELECT 1 FROM pg_index i JOIN pg_class c ON c.oid = i.indexrelid "
|
|
54
|
+
"WHERE c.relname = :name AND NOT i.indisvalid"
|
|
55
|
+
),
|
|
56
|
+
{"name": index_name},
|
|
57
|
+
).scalar()
|
|
58
|
+
if invalid:
|
|
59
|
+
op.execute(sa.text(f"DROP INDEX CONCURRENTLY IF EXISTS {index_name}"))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def upgrade() -> None:
|
|
63
|
+
bind = op.get_bind()
|
|
64
|
+
|
|
65
|
+
if bind.dialect.name == "postgresql":
|
|
66
|
+
with op.get_context().autocommit_block():
|
|
67
|
+
for index_name, columns in _LIVE_FACET_INDEXES:
|
|
68
|
+
_drop_invalid_postgres_index(index_name)
|
|
69
|
+
op.execute(
|
|
70
|
+
sa.text(
|
|
71
|
+
f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {index_name} "
|
|
72
|
+
f"ON {_TABLE_NAME} ({', '.join(columns)}) WHERE {_LIVE_ROW_PREDICATE}"
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
for index_name, columns in _LIVE_FACET_INDEXES:
|
|
78
|
+
op.execute(
|
|
79
|
+
sa.text(
|
|
80
|
+
f"CREATE INDEX IF NOT EXISTS {index_name} "
|
|
81
|
+
f"ON {_TABLE_NAME} ({', '.join(columns)}) WHERE {_LIVE_ROW_PREDICATE}"
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def downgrade() -> None:
|
|
87
|
+
bind = op.get_bind()
|
|
88
|
+
|
|
89
|
+
if bind.dialect.name == "postgresql":
|
|
90
|
+
with op.get_context().autocommit_block():
|
|
91
|
+
for index_name, _columns in _LIVE_FACET_INDEXES:
|
|
92
|
+
op.execute(sa.text(f"DROP INDEX CONCURRENTLY IF EXISTS {index_name}"))
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
for index_name, _columns in _LIVE_FACET_INDEXES:
|
|
96
|
+
op.drop_index(index_name, table_name=_TABLE_NAME, if_exists=True)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Add dashboard_settings.totp_required_for_admin_role (D9: TOTP required for admin-level accounts).
|
|
2
|
+
|
|
3
|
+
Revision ID: 20260910_000000_add_totp_required_for_admin_role
|
|
4
|
+
Revises: 20260909_040000_add_dashboard_user_invites
|
|
5
|
+
Create Date: 2026-09-10
|
|
6
|
+
|
|
7
|
+
Boolean, NOT NULL, server default false: existing installs keep today's
|
|
8
|
+
behaviour (only the global ``totp_required_on_login`` toggle applies) until an
|
|
9
|
+
admin turns the new option on from the Settings page. No data backfill.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import sqlalchemy as sa
|
|
15
|
+
from alembic import op
|
|
16
|
+
from sqlalchemy.engine import Connection
|
|
17
|
+
|
|
18
|
+
revision = "20260910_000000_add_totp_required_for_admin_role"
|
|
19
|
+
down_revision = "20260909_040000_add_dashboard_user_invites"
|
|
20
|
+
branch_labels = None
|
|
21
|
+
depends_on = None
|
|
22
|
+
|
|
23
|
+
_TABLE = "dashboard_settings"
|
|
24
|
+
_COLUMN = "totp_required_for_admin_role"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _columns(connection: Connection) -> set[str]:
|
|
28
|
+
if not sa.inspect(connection).has_table(_TABLE):
|
|
29
|
+
return set()
|
|
30
|
+
return {column["name"] for column in sa.inspect(connection).get_columns(_TABLE)}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def upgrade() -> None:
|
|
34
|
+
columns = _columns(op.get_bind())
|
|
35
|
+
if columns and _COLUMN not in columns:
|
|
36
|
+
with op.batch_alter_table(_TABLE) as batch_op:
|
|
37
|
+
batch_op.add_column(sa.Column(_COLUMN, sa.Boolean(), server_default=sa.false(), nullable=False))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def downgrade() -> None:
|
|
41
|
+
columns = _columns(op.get_bind())
|
|
42
|
+
if columns and _COLUMN in columns:
|
|
43
|
+
with op.batch_alter_table(_TABLE) as batch_op:
|
|
44
|
+
batch_op.drop_column(_COLUMN)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Index eligible missing costs so background repair never scans priced history."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sqlalchemy as sa
|
|
6
|
+
from alembic import op
|
|
7
|
+
|
|
8
|
+
revision = "20260910_000000_request_logs_missing_cost_index"
|
|
9
|
+
down_revision = "20260909_130000_add_request_logs_live_facet_indexes"
|
|
10
|
+
branch_labels = None
|
|
11
|
+
depends_on = None
|
|
12
|
+
|
|
13
|
+
_NAME = "idx_logs_missing_cost"
|
|
14
|
+
_PREDICATE = (
|
|
15
|
+
"cost_usd IS NULL AND model_source_id IS NULL AND input_tokens IS NOT NULL "
|
|
16
|
+
"AND (output_tokens IS NOT NULL OR reasoning_tokens IS NOT NULL) "
|
|
17
|
+
"AND (model_source_kind IS NULL OR model_source_kind = 'subscription')"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
if op.get_bind().dialect.name == "postgresql":
|
|
23
|
+
with op.get_context().autocommit_block():
|
|
24
|
+
invalid = (
|
|
25
|
+
op.get_bind()
|
|
26
|
+
.execute(
|
|
27
|
+
sa.text(
|
|
28
|
+
"SELECT 1 FROM pg_index i JOIN pg_class c ON c.oid = i.indexrelid "
|
|
29
|
+
"WHERE c.relname = :name AND NOT i.indisvalid"
|
|
30
|
+
),
|
|
31
|
+
{"name": _NAME},
|
|
32
|
+
)
|
|
33
|
+
.scalar()
|
|
34
|
+
)
|
|
35
|
+
if invalid:
|
|
36
|
+
op.execute(sa.text(f"DROP INDEX CONCURRENTLY IF EXISTS {_NAME}"))
|
|
37
|
+
op.execute(
|
|
38
|
+
sa.text(
|
|
39
|
+
f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {_NAME} "
|
|
40
|
+
f"ON request_logs (model_source_id, id) WHERE {_PREDICATE}"
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
return
|
|
44
|
+
op.execute(sa.text(f"CREATE INDEX IF NOT EXISTS {_NAME} ON request_logs (model_source_id, id) WHERE {_PREDICATE}"))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def downgrade() -> None:
|
|
48
|
+
if op.get_bind().dialect.name == "postgresql":
|
|
49
|
+
with op.get_context().autocommit_block():
|
|
50
|
+
op.execute(sa.text(f"DROP INDEX CONCURRENTLY IF EXISTS {_NAME}"))
|
|
51
|
+
return
|
|
52
|
+
op.drop_index(_NAME, table_name="request_logs", if_exists=True)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Add dashboard_auth_providers and the invite's expected identity columns.
|
|
2
|
+
|
|
3
|
+
Revision ID: 20260910_010000_add_dashboard_auth_providers
|
|
4
|
+
Revises: 20260909_040000_add_dashboard_user_invites
|
|
5
|
+
Create Date: 2026-09-10
|
|
6
|
+
|
|
7
|
+
One row per sign-in method. The two built-in rows (password, trusted header)
|
|
8
|
+
are seeded with "do nothing on conflict" so a re-run never overwrites an
|
|
9
|
+
operator's settings. The trusted-header row defaults unknown identities to the
|
|
10
|
+
admin preset (D10): an upgraded reverse-proxy install keeps admitting every
|
|
11
|
+
identity the proxy vouches for, now as its own account. ``enabled`` is not a
|
|
12
|
+
copy of ``CODEX_LB_DASHBOARD_AUTH_MODE``; the mode is read at request time.
|
|
13
|
+
|
|
14
|
+
``dashboard_user_invites`` gains the nullable ``expected_*`` triple a
|
|
15
|
+
pre-created account waits for. Existing invites keep NULL (nothing to link).
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import sqlalchemy as sa
|
|
21
|
+
from alembic import op
|
|
22
|
+
|
|
23
|
+
from app.modules.auth_providers.seed import seed_default_auth_providers
|
|
24
|
+
|
|
25
|
+
revision = "20260910_010000_add_dashboard_auth_providers"
|
|
26
|
+
down_revision = "20260910_000000_add_totp_required_for_admin_role"
|
|
27
|
+
branch_labels = None
|
|
28
|
+
depends_on = None
|
|
29
|
+
|
|
30
|
+
_TABLE = "dashboard_auth_providers"
|
|
31
|
+
_INVITES = "dashboard_user_invites"
|
|
32
|
+
_INVITE_COLUMNS: tuple[str, ...] = ("expected_provider", "expected_provider_key", "expected_subject")
|
|
33
|
+
_EXPECTED_IDENTITY_INDEX = "uq_dashboard_user_invites_expected_identity"
|
|
34
|
+
_OPEN_INVITE = "consumed_at IS NULL AND revoked_at IS NULL"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _provider_columns() -> tuple[sa.Column, ...]:
|
|
38
|
+
"""Fresh Column objects per call: a Column may be bound to one table only."""
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
sa.Column("id", sa.String(length=36), primary_key=True),
|
|
42
|
+
sa.Column("kind", sa.String(length=32), nullable=False),
|
|
43
|
+
sa.Column("provider_key", sa.String(length=64), nullable=False),
|
|
44
|
+
sa.Column("enabled", sa.Boolean(), server_default=sa.true(), nullable=False),
|
|
45
|
+
sa.Column("label", sa.String(length=64), nullable=False),
|
|
46
|
+
sa.Column("config_encrypted", sa.LargeBinary(), nullable=True),
|
|
47
|
+
sa.Column("unknown_identity_role_id", sa.String(length=36), nullable=True),
|
|
48
|
+
sa.Column("no_match_role_id", sa.String(length=36), nullable=True),
|
|
49
|
+
sa.Column("link_by_email", sa.Boolean(), server_default=sa.false(), nullable=False),
|
|
50
|
+
sa.Column("skip_role_sync", sa.Boolean(), server_default=sa.false(), nullable=False),
|
|
51
|
+
sa.Column("idp_mfa_enforced", sa.Boolean(), server_default=sa.false(), nullable=False),
|
|
52
|
+
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
|
53
|
+
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _create_providers_table() -> None:
|
|
58
|
+
op.create_table(
|
|
59
|
+
_TABLE,
|
|
60
|
+
*_provider_columns(),
|
|
61
|
+
sa.ForeignKeyConstraint(["unknown_identity_role_id"], ["dashboard_roles.id"], ondelete="SET NULL"),
|
|
62
|
+
sa.ForeignKeyConstraint(["no_match_role_id"], ["dashboard_roles.id"], ondelete="SET NULL"),
|
|
63
|
+
sa.UniqueConstraint("kind", "provider_key", name="uq_dashboard_auth_providers_kind_key"),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _seed_table() -> sa.Table:
|
|
68
|
+
"""Revision-pinned column list for the seed INSERT (no constraints needed to insert)."""
|
|
69
|
+
|
|
70
|
+
return sa.Table(_TABLE, sa.MetaData(), *_provider_columns())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _invite_columns() -> tuple[sa.Column, ...]:
|
|
74
|
+
"""Fresh Column objects per call: a Column may be bound to one table only."""
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
sa.Column("expected_provider", sa.String(length=32), nullable=True),
|
|
78
|
+
sa.Column("expected_provider_key", sa.String(length=128), nullable=True),
|
|
79
|
+
sa.Column("expected_subject", sa.String(length=512), nullable=True),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _existing_columns(inspector: sa.Inspector, table: str) -> set[str]:
|
|
84
|
+
if not inspector.has_table(table):
|
|
85
|
+
return set()
|
|
86
|
+
return {column["name"] for column in inspector.get_columns(table)}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def upgrade() -> None:
|
|
90
|
+
bind = op.get_bind()
|
|
91
|
+
inspector = sa.inspect(bind)
|
|
92
|
+
if not inspector.has_table(_TABLE):
|
|
93
|
+
_create_providers_table()
|
|
94
|
+
# Outside the table guard so a re-run after a partial failure still seeds.
|
|
95
|
+
seed_default_auth_providers(bind, _seed_table())
|
|
96
|
+
|
|
97
|
+
existing = _existing_columns(inspector, _INVITES)
|
|
98
|
+
missing = [column for column in _invite_columns() if column.name not in existing]
|
|
99
|
+
if missing:
|
|
100
|
+
with op.batch_alter_table(_INVITES) as batch_op:
|
|
101
|
+
for column in missing:
|
|
102
|
+
batch_op.add_column(column)
|
|
103
|
+
if inspector.has_table(_INVITES) and _EXPECTED_IDENTITY_INDEX not in _index_names(bind):
|
|
104
|
+
# One open invite per expected identity (partial: consumed/revoked rows do not count).
|
|
105
|
+
op.create_index(
|
|
106
|
+
_EXPECTED_IDENTITY_INDEX,
|
|
107
|
+
_INVITES,
|
|
108
|
+
list(_INVITE_COLUMNS),
|
|
109
|
+
unique=True,
|
|
110
|
+
postgresql_where=sa.text(_OPEN_INVITE),
|
|
111
|
+
sqlite_where=sa.text(_OPEN_INVITE),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _index_names(bind: sa.engine.Connection) -> set[str]:
|
|
116
|
+
inspector = sa.inspect(bind)
|
|
117
|
+
if not inspector.has_table(_INVITES):
|
|
118
|
+
return set()
|
|
119
|
+
return {name for index in inspector.get_indexes(_INVITES) if isinstance(name := index.get("name"), str)}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def downgrade() -> None:
|
|
123
|
+
bind = op.get_bind()
|
|
124
|
+
inspector = sa.inspect(bind)
|
|
125
|
+
if _EXPECTED_IDENTITY_INDEX in _index_names(bind):
|
|
126
|
+
op.drop_index(_EXPECTED_IDENTITY_INDEX, table_name=_INVITES)
|
|
127
|
+
present = _existing_columns(inspector, _INVITES)
|
|
128
|
+
to_drop = [name for name in _INVITE_COLUMNS if name in present]
|
|
129
|
+
if to_drop:
|
|
130
|
+
with op.batch_alter_table(_INVITES) as batch_op:
|
|
131
|
+
for name in to_drop:
|
|
132
|
+
batch_op.drop_column(name)
|
|
133
|
+
if inspector.has_table(_TABLE):
|
|
134
|
+
op.drop_table(_TABLE)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""add dashboard-managed HTTP bridge operation spool retention column
|
|
2
|
+
|
|
3
|
+
One nullable ``dashboard_settings`` FLOAT column named after the ``Settings``
|
|
4
|
+
field it takes over:
|
|
5
|
+
``http_responses_session_bridge_operation_spool_retention_seconds``. NULL means
|
|
6
|
+
"inherit": the deprecated
|
|
7
|
+
``CODEX_LB_HTTP_RESPONSES_SESSION_BRIDGE_OPERATION_SPOOL_RETENTION_SECONDS``
|
|
8
|
+
environment alias, then the code default (7 days), keep applying until an
|
|
9
|
+
operator sets a value in the dashboard's data retention card. The environment
|
|
10
|
+
value is never copied into the column (configuration-tiers; slop-removal
|
|
11
|
+
campaign 0908, R2).
|
|
12
|
+
|
|
13
|
+
Revision ID: 20260910_010000_dashboard_spool_retention
|
|
14
|
+
Revises: 20260910_000000_request_logs_missing_cost_index
|
|
15
|
+
Create Date: 2026-09-10
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import sqlalchemy as sa
|
|
21
|
+
from alembic import op
|
|
22
|
+
from sqlalchemy.engine import Connection
|
|
23
|
+
|
|
24
|
+
revision = "20260910_010000_dashboard_spool_retention"
|
|
25
|
+
down_revision = "20260910_000000_request_logs_missing_cost_index"
|
|
26
|
+
branch_labels = None
|
|
27
|
+
depends_on = None
|
|
28
|
+
|
|
29
|
+
_SETTINGS_TABLE = "dashboard_settings"
|
|
30
|
+
_COLUMN_NAME = "http_responses_session_bridge_operation_spool_retention_seconds"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _column_names(connection: Connection, table_name: str) -> set[str]:
|
|
34
|
+
inspector = sa.inspect(connection)
|
|
35
|
+
if not inspector.has_table(table_name):
|
|
36
|
+
return set()
|
|
37
|
+
return {str(column["name"]) for column in inspector.get_columns(table_name) if column.get("name") is not None}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def upgrade() -> None:
|
|
41
|
+
bind = op.get_bind()
|
|
42
|
+
existing_columns = _column_names(bind, _SETTINGS_TABLE)
|
|
43
|
+
if existing_columns and _COLUMN_NAME not in existing_columns:
|
|
44
|
+
with op.batch_alter_table(_SETTINGS_TABLE) as batch_op:
|
|
45
|
+
batch_op.add_column(sa.Column(_COLUMN_NAME, sa.Float(), nullable=True))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def downgrade() -> None:
|
|
49
|
+
bind = op.get_bind()
|
|
50
|
+
if _COLUMN_NAME in _column_names(bind, _SETTINGS_TABLE):
|
|
51
|
+
with op.batch_alter_table(_SETTINGS_TABLE) as batch_op:
|
|
52
|
+
batch_op.drop_column(_COLUMN_NAME)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Add dashboard_role_mappings.
|
|
2
|
+
|
|
3
|
+
Revision ID: 20260910_020000_add_dashboard_role_mappings
|
|
4
|
+
Revises: 20260910_010000_add_dashboard_auth_providers
|
|
5
|
+
Create Date: 2026-09-10
|
|
6
|
+
|
|
7
|
+
One row per "identities like this get that role" rule of a sign-in provider.
|
|
8
|
+
The table is created empty: an upgrade introduces no rule, and a provider
|
|
9
|
+
without rules re-evaluates nobody (D10), so the behaviour of an existing
|
|
10
|
+
install is unchanged until an operator adds the first rule.
|
|
11
|
+
|
|
12
|
+
``UNIQUE(provider, provider_key, priority)`` is declared inline because SQLite
|
|
13
|
+
cannot add a constraint to an existing table; ``role_id`` is RESTRICT so a role
|
|
14
|
+
a rule hands out cannot be deleted while the rule exists.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import sqlalchemy as sa
|
|
20
|
+
from alembic import op
|
|
21
|
+
|
|
22
|
+
revision = "20260910_020000_add_dashboard_role_mappings"
|
|
23
|
+
down_revision = "20260910_010000_add_dashboard_auth_providers"
|
|
24
|
+
branch_labels = None
|
|
25
|
+
depends_on = None
|
|
26
|
+
|
|
27
|
+
_TABLE = "dashboard_role_mappings"
|
|
28
|
+
_PROVIDER_INDEX = "idx_dashboard_role_mappings_provider"
|
|
29
|
+
_PRIORITY_CONSTRAINT = "uq_dashboard_role_mappings_priority"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _columns() -> tuple[sa.Column, ...]:
|
|
33
|
+
"""Fresh Column objects per call: a Column may be bound to one table only."""
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
sa.Column("id", sa.String(length=36), primary_key=True),
|
|
37
|
+
sa.Column("provider", sa.String(length=32), nullable=False),
|
|
38
|
+
sa.Column("provider_key", sa.String(length=64), nullable=False),
|
|
39
|
+
sa.Column("claim_name", sa.String(length=32), nullable=False),
|
|
40
|
+
sa.Column("claim_value", sa.String(length=320), nullable=False),
|
|
41
|
+
sa.Column("role_id", sa.String(length=36), nullable=False),
|
|
42
|
+
sa.Column("priority", sa.Integer(), nullable=False),
|
|
43
|
+
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
|
44
|
+
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _index_names(bind: sa.engine.Connection) -> set[str]:
|
|
49
|
+
inspector = sa.inspect(bind)
|
|
50
|
+
if not inspector.has_table(_TABLE):
|
|
51
|
+
return set()
|
|
52
|
+
return {name for index in inspector.get_indexes(_TABLE) if isinstance(name := index.get("name"), str)}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def upgrade() -> None:
|
|
56
|
+
bind = op.get_bind()
|
|
57
|
+
inspector = sa.inspect(bind)
|
|
58
|
+
if not inspector.has_table(_TABLE):
|
|
59
|
+
op.create_table(
|
|
60
|
+
_TABLE,
|
|
61
|
+
*_columns(),
|
|
62
|
+
sa.ForeignKeyConstraint(["role_id"], ["dashboard_roles.id"], ondelete="RESTRICT"),
|
|
63
|
+
sa.UniqueConstraint("provider", "provider_key", "priority", name=_PRIORITY_CONSTRAINT),
|
|
64
|
+
)
|
|
65
|
+
if _PROVIDER_INDEX not in _index_names(bind):
|
|
66
|
+
op.create_index(_PROVIDER_INDEX, _TABLE, ["provider", "provider_key"])
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def downgrade() -> None:
|
|
70
|
+
bind = op.get_bind()
|
|
71
|
+
if _PROVIDER_INDEX in _index_names(bind):
|
|
72
|
+
op.drop_index(_PROVIDER_INDEX, table_name=_TABLE)
|
|
73
|
+
if sa.inspect(bind).has_table(_TABLE):
|
|
74
|
+
op.drop_table(_TABLE)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Persist nullable resolved affinity metadata on request logs."""
|
|
2
|
+
|
|
3
|
+
import sqlalchemy as sa
|
|
4
|
+
from alembic import op
|
|
5
|
+
|
|
6
|
+
revision = "20260910_143000_request_log_affinity"
|
|
7
|
+
down_revision = "20260910_010000_dashboard_spool_retention"
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
_COLUMNS = ("sticky_key_source", "sticky_kind", "sticky_key_hash")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def upgrade() -> None:
|
|
15
|
+
existing = {column["name"] for column in sa.inspect(op.get_bind()).get_columns("request_logs")}
|
|
16
|
+
# Legacy bootstrap can start with the current ORM schema already present.
|
|
17
|
+
with op.batch_alter_table("request_logs") as batch_op:
|
|
18
|
+
for name in _COLUMNS:
|
|
19
|
+
if name not in existing:
|
|
20
|
+
batch_op.add_column(sa.Column(name, sa.String(), nullable=True))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def downgrade() -> None:
|
|
24
|
+
existing = {column["name"] for column in sa.inspect(op.get_bind()).get_columns("request_logs")}
|
|
25
|
+
with op.batch_alter_table("request_logs") as batch_op:
|
|
26
|
+
for name in reversed(_COLUMNS):
|
|
27
|
+
if name in existing:
|
|
28
|
+
batch_op.drop_column(name)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Merge affinity observation and guest-session migration histories."""
|
|
2
|
+
|
|
3
|
+
revision = "20260910_180000_merge_affinity_guest_heads"
|
|
4
|
+
down_revision = (
|
|
5
|
+
"20260910_143000_request_log_affinity",
|
|
6
|
+
"20260908_000000_add_guest_session_generation",
|
|
7
|
+
)
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def upgrade() -> None:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def downgrade() -> None:
|
|
17
|
+
pass
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Merge affinity observation and dashboard identity migration histories."""
|
|
2
|
+
|
|
3
|
+
revision = "20260910_200000_merge_affinity_identity_heads"
|
|
4
|
+
down_revision = (
|
|
5
|
+
"20260910_180000_merge_affinity_guest_heads",
|
|
6
|
+
"20260909_030000_add_audit_actor_columns",
|
|
7
|
+
)
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def upgrade() -> None:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def downgrade() -> None:
|
|
17
|
+
pass
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Merge published affinity identity and dashboard invite histories."""
|
|
2
|
+
|
|
3
|
+
revision = "20260910_220000_merge_affinity_invite_heads"
|
|
4
|
+
down_revision = (
|
|
5
|
+
"20260910_200000_merge_affinity_identity_heads",
|
|
6
|
+
"20260909_040000_add_dashboard_user_invites",
|
|
7
|
+
)
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def upgrade() -> None:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def downgrade() -> None:
|
|
17
|
+
pass
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Index the live thread-pin count so a dashboard poll never walks model_source_pins."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sqlalchemy as sa
|
|
6
|
+
from alembic import op
|
|
7
|
+
|
|
8
|
+
revision = "20260911_000000_model_source_pins_kind_expires_index"
|
|
9
|
+
down_revision = "20260910_020000_add_dashboard_role_mappings"
|
|
10
|
+
branch_labels = None
|
|
11
|
+
depends_on = None
|
|
12
|
+
|
|
13
|
+
_NAME = "ix_model_source_pins_kind_expires_at"
|
|
14
|
+
_COLUMNS = "(kind, expires_at)"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def upgrade() -> None:
|
|
18
|
+
if op.get_bind().dialect.name == "postgresql":
|
|
19
|
+
with op.get_context().autocommit_block():
|
|
20
|
+
invalid = (
|
|
21
|
+
op.get_bind()
|
|
22
|
+
.execute(
|
|
23
|
+
sa.text(
|
|
24
|
+
"SELECT 1 FROM pg_index i JOIN pg_class c ON c.oid = i.indexrelid "
|
|
25
|
+
"WHERE c.relname = :name AND NOT i.indisvalid"
|
|
26
|
+
),
|
|
27
|
+
{"name": _NAME},
|
|
28
|
+
)
|
|
29
|
+
.scalar()
|
|
30
|
+
)
|
|
31
|
+
if invalid:
|
|
32
|
+
op.execute(sa.text(f"DROP INDEX CONCURRENTLY IF EXISTS {_NAME}"))
|
|
33
|
+
op.execute(sa.text(f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {_NAME} ON model_source_pins {_COLUMNS}"))
|
|
34
|
+
return
|
|
35
|
+
op.execute(sa.text(f"CREATE INDEX IF NOT EXISTS {_NAME} ON model_source_pins {_COLUMNS}"))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def downgrade() -> None:
|
|
39
|
+
if op.get_bind().dialect.name == "postgresql":
|
|
40
|
+
with op.get_context().autocommit_block():
|
|
41
|
+
op.execute(sa.text(f"DROP INDEX CONCURRENTLY IF EXISTS {_NAME}"))
|
|
42
|
+
return
|
|
43
|
+
op.drop_index(_NAME, table_name="model_source_pins", if_exists=True)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Merge the model-source pin index and published affinity histories."""
|
|
2
|
+
|
|
3
|
+
revision = "20260911_010000_merge_pin_index_and_affinity_heads"
|
|
4
|
+
down_revision = (
|
|
5
|
+
"20260911_000000_model_source_pins_kind_expires_index",
|
|
6
|
+
"20260910_220000_merge_affinity_invite_heads",
|
|
7
|
+
)
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def upgrade() -> None:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def downgrade() -> None:
|
|
17
|
+
pass
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""record where an HTTP bridge operation stands in its terminal append
|
|
2
|
+
|
|
3
|
+
Revision ID: 20260911_020000_add_http_bridge_terminal_append_phase
|
|
4
|
+
Revises: 20260911_010000_merge_pin_index_and_affinity_heads
|
|
5
|
+
Create Date: 2026-09-11
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import sqlalchemy as sa
|
|
11
|
+
from alembic import op
|
|
12
|
+
from sqlalchemy.engine import Connection
|
|
13
|
+
|
|
14
|
+
revision = "20260911_020000_add_http_bridge_terminal_append_phase"
|
|
15
|
+
down_revision = "20260911_010000_merge_pin_index_and_affinity_heads"
|
|
16
|
+
branch_labels = None
|
|
17
|
+
depends_on = None
|
|
18
|
+
|
|
19
|
+
_TABLE = "http_bridge_operations"
|
|
20
|
+
_COLUMN = "terminal_append_phase"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _has_table(connection: Connection) -> bool:
|
|
24
|
+
return sa.inspect(connection).has_table(_TABLE)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _has_column(connection: Connection) -> bool:
|
|
28
|
+
return any(item["name"] == _COLUMN for item in sa.inspect(connection).get_columns(_TABLE))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def upgrade() -> None:
|
|
32
|
+
bind = op.get_bind()
|
|
33
|
+
if not _has_table(bind) or _has_column(bind):
|
|
34
|
+
return
|
|
35
|
+
# ``pending`` for every existing row is the correct backfill. The column
|
|
36
|
+
# fences the terminal transcript write of one dispatch, and no row written
|
|
37
|
+
# before this revision carries such a fence: a legacy terminal append
|
|
38
|
+
# committed ``event_spool_complete = true`` in the same transaction, and
|
|
39
|
+
# the legacy fallback settlement left no distinguishing mark. Backfilling
|
|
40
|
+
# anything stricter would refuse the terminal append of operations that are
|
|
41
|
+
# in flight across the upgrade, which is precisely the fail-closed shape
|
|
42
|
+
# this column exists to avoid: an ordinary operation is already
|
|
43
|
+
# ``state = completed`` with an incomplete spool while its terminal append
|
|
44
|
+
# runs, because the relay publishes the operation state first.
|
|
45
|
+
op.add_column(
|
|
46
|
+
_TABLE,
|
|
47
|
+
sa.Column(_COLUMN, sa.String(length=16), nullable=False, server_default=sa.text("'pending'")),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def downgrade() -> None:
|
|
52
|
+
bind = op.get_bind()
|
|
53
|
+
if _has_table(bind) and _has_column(bind):
|
|
54
|
+
op.drop_column(_TABLE, _COLUMN)
|