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,1100 @@
|
|
|
1
|
+
# pyright: reportGeneralTypeIssues=false
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import sys
|
|
6
|
+
from typing import Any, AsyncIterator, Mapping, cast
|
|
7
|
+
|
|
8
|
+
import aiohttp
|
|
9
|
+
|
|
10
|
+
from app.core.balancer.types import UpstreamError
|
|
11
|
+
from app.core.clients.files import create_file as core_create_file # noqa: F401
|
|
12
|
+
from app.core.clients.files import finalize_file as core_finalize_file # noqa: F401
|
|
13
|
+
from app.core.clients.http import lease_http_session as lease_http_session # noqa: F401
|
|
14
|
+
from app.core.clients.proxy import CodexControlResponse as CodexControlResponse
|
|
15
|
+
from app.core.clients.proxy import ( # noqa: F401 # noqa: F401
|
|
16
|
+
ImageFetchSession,
|
|
17
|
+
ProxyResponseError,
|
|
18
|
+
UpstreamProxyRouteTrace,
|
|
19
|
+
_as_image_fetch_session,
|
|
20
|
+
_inline_content_images,
|
|
21
|
+
_inline_input_image_urls,
|
|
22
|
+
_is_native_codex_request,
|
|
23
|
+
_ws_transport_payload_budget_bytes,
|
|
24
|
+
filter_inbound_headers,
|
|
25
|
+
pop_compact_timeout_overrides,
|
|
26
|
+
pop_stream_timeout_overrides,
|
|
27
|
+
pop_transcribe_timeout_overrides,
|
|
28
|
+
push_compact_timeout_overrides,
|
|
29
|
+
push_stream_timeout_overrides,
|
|
30
|
+
push_transcribe_timeout_overrides,
|
|
31
|
+
)
|
|
32
|
+
from app.core.clients.proxy import codex_control_request as core_codex_control_request # noqa: F401
|
|
33
|
+
from app.core.clients.proxy import compact_responses as core_compact_responses # noqa: F401
|
|
34
|
+
from app.core.clients.proxy import transcribe_audio as core_transcribe_audio # noqa: F401
|
|
35
|
+
from app.core.clients.thread_cache_identity import ThreadCacheIdentity
|
|
36
|
+
from app.core.clock import clock_for, scheduler_for
|
|
37
|
+
from app.core.errors import (
|
|
38
|
+
PREVIOUS_RESPONSE_NOT_FOUND_CODE as PREVIOUS_RESPONSE_NOT_FOUND_CODE,
|
|
39
|
+
)
|
|
40
|
+
from app.core.errors import (
|
|
41
|
+
PREVIOUS_RESPONSE_NOT_FOUND_MESSAGE as PREVIOUS_RESPONSE_NOT_FOUND_MESSAGE,
|
|
42
|
+
)
|
|
43
|
+
from app.core.errors import synthetic_stream_failure_event as response_failed_event
|
|
44
|
+
from app.core.openai.parsing import _LIFECYCLE_EVENT_TYPES, classify_event_type, parse_sse_event_payload
|
|
45
|
+
from app.core.openai.requests import ResponsesRequest
|
|
46
|
+
from app.core.upstream_proxy import ResolvedUpstreamRoute, UpstreamProxyRouteError
|
|
47
|
+
from app.core.utils.sse import CODEX_KEEPALIVE_FRAME as CODEX_KEEPALIVE_FRAME # noqa: F401
|
|
48
|
+
from app.core.utils.sse import format_sse_event, parse_sse_data_json
|
|
49
|
+
from app.core.utils.time import utcnow as utcnow
|
|
50
|
+
from app.db.models import (
|
|
51
|
+
Account,
|
|
52
|
+
AccountStatus, # noqa: F401
|
|
53
|
+
)
|
|
54
|
+
from app.modules.api_keys.service import ApiKeyData, ApiKeyUsageReservationData
|
|
55
|
+
from app.modules.proxy._service.api_key_usage import (
|
|
56
|
+
_API_KEY_RESERVATION_HEARTBEAT_SECONDS as _API_KEY_RESERVATION_HEARTBEAT_SECONDS,
|
|
57
|
+
)
|
|
58
|
+
from app.modules.proxy._service.compact import (
|
|
59
|
+
_service_tier_from_compact_payload as _service_tier_from_compact_payload,
|
|
60
|
+
)
|
|
61
|
+
from app.modules.proxy._service.compact import (
|
|
62
|
+
_sticky_key_for_compact_request as _sticky_key_for_compact_request,
|
|
63
|
+
)
|
|
64
|
+
from app.modules.proxy._service.compact import (
|
|
65
|
+
_sticky_key_from_compact_payload as _sticky_key_from_compact_payload,
|
|
66
|
+
)
|
|
67
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
68
|
+
_active_http_bridge_instance_ring as _active_http_bridge_instance_ring,
|
|
69
|
+
)
|
|
70
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
71
|
+
_build_http_bridge_prewarm_text as _build_http_bridge_prewarm_text,
|
|
72
|
+
)
|
|
73
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
74
|
+
_durable_bridge_lookup_active_owner as _durable_bridge_lookup_active_owner,
|
|
75
|
+
)
|
|
76
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
77
|
+
_durable_bridge_lookup_allows_local_reuse as _durable_bridge_lookup_allows_local_reuse,
|
|
78
|
+
)
|
|
79
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
80
|
+
_effective_http_bridge_idle_ttl_seconds as _effective_http_bridge_idle_ttl_seconds,
|
|
81
|
+
)
|
|
82
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
83
|
+
_forwarded_http_bridge_session_key as _forwarded_http_bridge_session_key,
|
|
84
|
+
)
|
|
85
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
86
|
+
_has_http_bridge_response_output_marker as _has_http_bridge_response_output_marker,
|
|
87
|
+
)
|
|
88
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
89
|
+
_http_bridge_allow_durable_takeover as _http_bridge_allow_durable_takeover,
|
|
90
|
+
)
|
|
91
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
92
|
+
_http_bridge_can_local_recover_without_ring as _http_bridge_can_local_recover_without_ring,
|
|
93
|
+
)
|
|
94
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
95
|
+
_http_bridge_can_recover_during_drain as _http_bridge_can_recover_during_drain,
|
|
96
|
+
)
|
|
97
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
98
|
+
_http_bridge_continuity_lost_error_envelope as _http_bridge_continuity_lost_error_envelope,
|
|
99
|
+
)
|
|
100
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
101
|
+
_http_bridge_durable_lease_ttl_seconds as _http_bridge_durable_lease_ttl_seconds,
|
|
102
|
+
)
|
|
103
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
104
|
+
_http_bridge_endpoint_matches_current_instance as _http_bridge_endpoint_matches_current_instance,
|
|
105
|
+
)
|
|
106
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
107
|
+
_http_bridge_eviction_priority as _http_bridge_eviction_priority,
|
|
108
|
+
)
|
|
109
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
110
|
+
_http_bridge_has_durable_recovery_anchor as _http_bridge_has_durable_recovery_anchor,
|
|
111
|
+
)
|
|
112
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
113
|
+
_http_bridge_input_item_type as _http_bridge_input_item_type,
|
|
114
|
+
)
|
|
115
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
116
|
+
_http_bridge_is_context_overflow_error as _http_bridge_is_context_overflow_error,
|
|
117
|
+
)
|
|
118
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
119
|
+
_http_bridge_is_previous_response_owner_unavailable as _http_bridge_is_previous_response_owner_unavailable,
|
|
120
|
+
)
|
|
121
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
122
|
+
_http_bridge_key_strength as _http_bridge_key_strength,
|
|
123
|
+
)
|
|
124
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
125
|
+
_http_bridge_owner_check_required as _http_bridge_owner_check_required,
|
|
126
|
+
)
|
|
127
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
128
|
+
_http_bridge_owner_instance as _http_bridge_owner_instance,
|
|
129
|
+
)
|
|
130
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
131
|
+
_http_bridge_owner_lookup_unavailable_error_envelope as _http_bridge_owner_lookup_unavailable_error_envelope,
|
|
132
|
+
)
|
|
133
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
134
|
+
_http_bridge_payload_looks_like_full_resend as _http_bridge_payload_looks_like_full_resend,
|
|
135
|
+
)
|
|
136
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
137
|
+
_http_bridge_payload_without_previous_response_id as _http_bridge_payload_without_previous_response_id,
|
|
138
|
+
)
|
|
139
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
140
|
+
_http_bridge_precreated_retry_failure_error as _http_bridge_precreated_retry_failure_error,
|
|
141
|
+
)
|
|
142
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
143
|
+
_http_bridge_previous_response_alias_key as _http_bridge_previous_response_alias_key,
|
|
144
|
+
)
|
|
145
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
146
|
+
_http_bridge_previous_response_error_envelope as _http_bridge_previous_response_error_envelope,
|
|
147
|
+
)
|
|
148
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
149
|
+
_http_bridge_request_counts_against_queue as _http_bridge_request_counts_against_queue,
|
|
150
|
+
)
|
|
151
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
152
|
+
_http_bridge_request_stage as _http_bridge_request_stage,
|
|
153
|
+
)
|
|
154
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
155
|
+
_http_bridge_requires_cluster_registration as _http_bridge_requires_cluster_registration,
|
|
156
|
+
)
|
|
157
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
158
|
+
_http_bridge_runtime_config as _http_bridge_runtime_config,
|
|
159
|
+
)
|
|
160
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
161
|
+
_http_bridge_session_allows_api_key as _http_bridge_session_allows_api_key,
|
|
162
|
+
)
|
|
163
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
164
|
+
_http_bridge_session_has_visible_requests as _http_bridge_session_has_visible_requests,
|
|
165
|
+
)
|
|
166
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
167
|
+
_http_bridge_session_matches_preferred_account as _http_bridge_session_matches_preferred_account,
|
|
168
|
+
)
|
|
169
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
170
|
+
_http_bridge_session_retiring_with_visible_requests as _http_bridge_session_retiring_with_visible_requests,
|
|
171
|
+
)
|
|
172
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
173
|
+
_http_bridge_session_reusable_for_request as _http_bridge_session_reusable_for_request,
|
|
174
|
+
)
|
|
175
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
176
|
+
_http_bridge_should_attempt_local_bootstrap_rebind as _http_bridge_should_attempt_local_bootstrap_rebind,
|
|
177
|
+
)
|
|
178
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
179
|
+
_http_bridge_should_attempt_local_previous_response_recovery, # noqa: F401
|
|
180
|
+
)
|
|
181
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
182
|
+
_http_bridge_should_attempt_soft_affinity_reroute as _http_bridge_should_attempt_soft_affinity_reroute,
|
|
183
|
+
)
|
|
184
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
185
|
+
_http_bridge_should_rollover_after_context_overflow as _http_bridge_should_rollover_after_context_overflow,
|
|
186
|
+
)
|
|
187
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
188
|
+
_http_bridge_should_wait_for_registration as _http_bridge_should_wait_for_registration,
|
|
189
|
+
)
|
|
190
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
191
|
+
_http_bridge_startup_wait_timeout_error as _http_bridge_startup_wait_timeout_error,
|
|
192
|
+
)
|
|
193
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
194
|
+
_http_bridge_turn_state_alias_key as _http_bridge_turn_state_alias_key,
|
|
195
|
+
)
|
|
196
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
197
|
+
_is_http_bridge_previous_response_output_item as _is_http_bridge_previous_response_output_item,
|
|
198
|
+
)
|
|
199
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
200
|
+
_is_missing_durable_bridge_table_error as _is_missing_durable_bridge_table_error,
|
|
201
|
+
)
|
|
202
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
203
|
+
_log_http_bridge_event as _log_http_bridge_event,
|
|
204
|
+
)
|
|
205
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
206
|
+
_log_http_bridge_startup_wait_timeout as _log_http_bridge_startup_wait_timeout,
|
|
207
|
+
)
|
|
208
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
209
|
+
_make_http_bridge_session_key as _make_http_bridge_session_key,
|
|
210
|
+
)
|
|
211
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
212
|
+
_normalize_http_bridge_error_event as _normalize_http_bridge_error_event,
|
|
213
|
+
)
|
|
214
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
215
|
+
_normalized_http_bridge_instance_ring as _normalized_http_bridge_instance_ring,
|
|
216
|
+
)
|
|
217
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
218
|
+
_preferred_http_bridge_reconnect_turn_state as _preferred_http_bridge_reconnect_turn_state,
|
|
219
|
+
)
|
|
220
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
221
|
+
_record_bridge_drain_recovery_allowed as _record_bridge_drain_recovery_allowed,
|
|
222
|
+
)
|
|
223
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
224
|
+
_record_bridge_first_turn_timeout as _record_bridge_first_turn_timeout,
|
|
225
|
+
)
|
|
226
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
227
|
+
_record_bridge_reattach as _record_bridge_reattach,
|
|
228
|
+
)
|
|
229
|
+
from app.modules.proxy._service.http_bridge.helpers import (
|
|
230
|
+
_trim_http_bridge_previous_response_input_items as _trim_http_bridge_previous_response_input_items,
|
|
231
|
+
)
|
|
232
|
+
from app.modules.proxy._service.observability import (
|
|
233
|
+
_hash_identifier as _hash_identifier,
|
|
234
|
+
)
|
|
235
|
+
from app.modules.proxy._service.observability import (
|
|
236
|
+
_hash_identifier_or_none as _hash_identifier_or_none,
|
|
237
|
+
)
|
|
238
|
+
from app.modules.proxy._service.observability import (
|
|
239
|
+
_interesting_header_keys as _interesting_header_keys,
|
|
240
|
+
)
|
|
241
|
+
from app.modules.proxy._service.observability import (
|
|
242
|
+
_maybe_log_proxy_request_payload as _maybe_log_proxy_request_payload,
|
|
243
|
+
)
|
|
244
|
+
from app.modules.proxy._service.observability import (
|
|
245
|
+
_maybe_log_proxy_request_shape as _maybe_log_proxy_request_shape,
|
|
246
|
+
)
|
|
247
|
+
from app.modules.proxy._service.observability import (
|
|
248
|
+
_maybe_log_proxy_service_tier_trace as _maybe_log_proxy_service_tier_trace,
|
|
249
|
+
)
|
|
250
|
+
from app.modules.proxy._service.observability import (
|
|
251
|
+
_record_continuity_fail_closed as _record_continuity_fail_closed,
|
|
252
|
+
)
|
|
253
|
+
from app.modules.proxy._service.observability import (
|
|
254
|
+
_record_continuity_owner_resolution as _record_continuity_owner_resolution,
|
|
255
|
+
)
|
|
256
|
+
from app.modules.proxy._service.observability import (
|
|
257
|
+
_summarize_input as _summarize_input,
|
|
258
|
+
)
|
|
259
|
+
from app.modules.proxy._service.observability import (
|
|
260
|
+
_tools_hash as _tools_hash,
|
|
261
|
+
)
|
|
262
|
+
from app.modules.proxy._service.observability import (
|
|
263
|
+
_truncate_identifier as _truncate_identifier,
|
|
264
|
+
)
|
|
265
|
+
from app.modules.proxy._service.streaming.helpers import (
|
|
266
|
+
_classify_terminal_stream_error_frame,
|
|
267
|
+
_mark_downstream_stream_cancelled,
|
|
268
|
+
_mark_upstream_stream_incomplete,
|
|
269
|
+
_observe_terminal_stream_error_frame,
|
|
270
|
+
_openai_error_fields,
|
|
271
|
+
_publish_http_response_owner,
|
|
272
|
+
_rewrite_malformed_stream_error_event,
|
|
273
|
+
_stamp_terminal,
|
|
274
|
+
_stream_transport_failure_event_or_raise,
|
|
275
|
+
_upstream_terminal_latency_ms,
|
|
276
|
+
)
|
|
277
|
+
from app.modules.proxy._service.streaming.helpers import (
|
|
278
|
+
_handle_stream_error as _handle_stream_error_helper,
|
|
279
|
+
)
|
|
280
|
+
from app.modules.proxy._service.streaming.helpers import _raw_stream_error_fields as _raw_error_fields
|
|
281
|
+
from app.modules.proxy._service.streaming.helpers import (
|
|
282
|
+
_resolve_upstream_route_for_account as _resolve_upstream_route_for_account_helper,
|
|
283
|
+
)
|
|
284
|
+
from app.modules.proxy._service.streaming.helpers import (
|
|
285
|
+
_select_account_with_budget_for_stream as _select_account_with_budget_for_stream_helper,
|
|
286
|
+
)
|
|
287
|
+
from app.modules.proxy._service.streaming.helpers import _settle_background_ack as _settle_bg_ack
|
|
288
|
+
from app.modules.proxy._service.streaming.protocol import _StreamingServiceProtocol
|
|
289
|
+
from app.modules.proxy._service.streaming.retry import _StreamingRetryMixin
|
|
290
|
+
from app.modules.proxy._service.support import (
|
|
291
|
+
_HARD_HTTP_BRIDGE_AFFINITY_KINDS, # noqa: F401
|
|
292
|
+
_REQUEST_TRANSPORT_WEBSOCKET, # noqa: F401
|
|
293
|
+
_WEBSOCKET_FULL_REPLAY_WAIT_MIN_ITEMS, # noqa: F401
|
|
294
|
+
_WEBSOCKET_FULL_REPLAY_WAIT_POLL_SECONDS, # noqa: F401
|
|
295
|
+
_ApiKeyReservationTouchState,
|
|
296
|
+
_finalize_ttft_latency_ms,
|
|
297
|
+
_RequestLogFailureMetadata,
|
|
298
|
+
_RetryableStreamError,
|
|
299
|
+
_StreamSettlement,
|
|
300
|
+
_TerminalStreamError,
|
|
301
|
+
_ttft_event_latency_ms,
|
|
302
|
+
_verbatim_relay_event_type,
|
|
303
|
+
_WebSocketUpstreamControl,
|
|
304
|
+
)
|
|
305
|
+
from app.modules.proxy._service.support import (
|
|
306
|
+
_HTTPBridgeOwnerForward as _HTTPBridgeOwnerForward,
|
|
307
|
+
)
|
|
308
|
+
from app.modules.proxy._service.support import (
|
|
309
|
+
_record_websocket_route_metadata as _record_websocket_route_metadata,
|
|
310
|
+
)
|
|
311
|
+
from app.modules.proxy._service.support import (
|
|
312
|
+
_websocket_route_log_kwargs as _websocket_route_log_kwargs,
|
|
313
|
+
)
|
|
314
|
+
from app.modules.proxy._service.warmup import (
|
|
315
|
+
WarmupExecutionData as WarmupExecutionData,
|
|
316
|
+
)
|
|
317
|
+
from app.modules.proxy._service.warmup import (
|
|
318
|
+
WarmupFailedAccountData as WarmupFailedAccountData,
|
|
319
|
+
)
|
|
320
|
+
from app.modules.proxy._service.warmup import (
|
|
321
|
+
WarmupSkippedAccountData as WarmupSkippedAccountData,
|
|
322
|
+
)
|
|
323
|
+
from app.modules.proxy._service.warmup import (
|
|
324
|
+
WarmupSubmittedAccountData as WarmupSubmittedAccountData,
|
|
325
|
+
)
|
|
326
|
+
from app.modules.proxy._service.warmup import (
|
|
327
|
+
_is_warmup_usage_eligible as _is_warmup_usage_eligible,
|
|
328
|
+
)
|
|
329
|
+
from app.modules.proxy._service.warmup import (
|
|
330
|
+
_materialize_warmup_account as _materialize_warmup_account,
|
|
331
|
+
)
|
|
332
|
+
from app.modules.proxy._service.warmup import (
|
|
333
|
+
_snapshot_warmup_account as _snapshot_warmup_account,
|
|
334
|
+
)
|
|
335
|
+
from app.modules.proxy._service.warmup import (
|
|
336
|
+
_WarmupAccountSnapshot as _WarmupAccountSnapshot,
|
|
337
|
+
)
|
|
338
|
+
from app.modules.proxy._service.warmup import (
|
|
339
|
+
_WarmupSubmitResult as _WarmupSubmitResult,
|
|
340
|
+
)
|
|
341
|
+
from app.modules.proxy._service.warmup import (
|
|
342
|
+
_WarmupUsageSnapshot as _WarmupUsageSnapshot,
|
|
343
|
+
)
|
|
344
|
+
from app.modules.proxy._service.websocket.helpers import (
|
|
345
|
+
_app_error_to_websocket_event, # noqa: F401
|
|
346
|
+
_assign_websocket_response_id, # noqa: F401
|
|
347
|
+
_draining_websocket_request_states, # noqa: F401
|
|
348
|
+
_find_websocket_request_state_by_response_id, # noqa: F401
|
|
349
|
+
_is_websocket_previous_response_output_item, # noqa: F401
|
|
350
|
+
_is_websocket_response_create, # noqa: F401
|
|
351
|
+
_match_websocket_request_state_for_anonymous_event, # noqa: F401
|
|
352
|
+
_match_websocket_request_state_for_precreated_terminal_event, # noqa: F401
|
|
353
|
+
_match_websocket_request_state_for_previous_response_error, # noqa: F401
|
|
354
|
+
_matching_websocket_request_states_for_missing_tool_output_error, # noqa: F401
|
|
355
|
+
_matching_websocket_request_states_for_previous_response_error, # noqa: F401
|
|
356
|
+
_maybe_rewrite_websocket_previous_response_not_found_event, # noqa: F401
|
|
357
|
+
_parse_websocket_payload, # noqa: F401
|
|
358
|
+
_pop_matching_websocket_request_states, # noqa: F401
|
|
359
|
+
_pop_replayable_precreated_websocket_request_state, # noqa: F401
|
|
360
|
+
_pop_terminal_websocket_request_state, # noqa: F401
|
|
361
|
+
_prepare_websocket_request_state_for_auth_replay, # noqa: F401
|
|
362
|
+
_prepare_websocket_request_state_for_visible_output_replay, # noqa: F401
|
|
363
|
+
_record_websocket_continuity_completion, # noqa: F401
|
|
364
|
+
_refresh_websocket_request_input_fingerprint_from_text, # noqa: F401
|
|
365
|
+
_release_websocket_response_create_gate, # noqa: F401
|
|
366
|
+
_rewrite_websocket_continuity_corruption_event, # noqa: F401
|
|
367
|
+
_rewrite_websocket_downstream_response_id, # noqa: F401
|
|
368
|
+
_rewrite_websocket_previous_response_owner_unavailable_event, # noqa: F401
|
|
369
|
+
_rewrite_websocket_suppressed_duplicate_tool_call_completion_event, # noqa: F401
|
|
370
|
+
_sanitize_websocket_connect_failure, # noqa: F401
|
|
371
|
+
_sanitize_websocket_previous_response_error, # noqa: F401
|
|
372
|
+
_sanitize_websocket_terminal_error_fields, # noqa: F401
|
|
373
|
+
_serialize_websocket_error_event, # noqa: F401
|
|
374
|
+
_trim_websocket_previous_response_input_items, # noqa: F401
|
|
375
|
+
_upstream_websocket_disconnect_message, # noqa: F401
|
|
376
|
+
_websocket_auth_failure_permanent_code, # noqa: F401
|
|
377
|
+
_websocket_auth_failure_requires_reauth, # noqa: F401
|
|
378
|
+
_websocket_auth_request_can_switch_account, # noqa: F401
|
|
379
|
+
_websocket_client_previous_response_full_resend_is_retry_safe, # noqa: F401
|
|
380
|
+
_websocket_connect_deadline, # noqa: F401
|
|
381
|
+
_websocket_continuity_anchor_for_payload, # noqa: F401
|
|
382
|
+
_websocket_continuity_error_fields, # noqa: F401
|
|
383
|
+
_websocket_continuity_response_ids, # noqa: F401
|
|
384
|
+
_websocket_downstream_response_id, # noqa: F401
|
|
385
|
+
_websocket_full_resend_conflicts_with_visible_pending, # noqa: F401
|
|
386
|
+
_websocket_input_item_type, # noqa: F401
|
|
387
|
+
_websocket_owner_pinned_quota_error_code, # noqa: F401
|
|
388
|
+
_websocket_precreated_auth_error_code, # noqa: F401
|
|
389
|
+
_websocket_precreated_retry_error_code, # noqa: F401
|
|
390
|
+
_websocket_receive_timeout_for_pending_requests, # noqa: F401
|
|
391
|
+
_websocket_response_id, # noqa: F401
|
|
392
|
+
_websocket_top_level_error_payload, # noqa: F401
|
|
393
|
+
_wrapped_websocket_error_event, # noqa: F401
|
|
394
|
+
)
|
|
395
|
+
from app.modules.proxy.affinity import (
|
|
396
|
+
_owner_lookup_session_id_from_headers,
|
|
397
|
+
_sticky_key_from_session_header, # noqa: F401
|
|
398
|
+
)
|
|
399
|
+
from app.modules.proxy.affinity_observation import AffinityObservation
|
|
400
|
+
from app.modules.proxy.durable_bridge_coordinator import (
|
|
401
|
+
DurableBridgeLookup as DurableBridgeLookup,
|
|
402
|
+
)
|
|
403
|
+
from app.modules.proxy.helpers import (
|
|
404
|
+
_header_account_id,
|
|
405
|
+
_normalize_error_code,
|
|
406
|
+
_parse_openai_error,
|
|
407
|
+
_upstream_error_from_openai,
|
|
408
|
+
)
|
|
409
|
+
from app.modules.proxy.http_bridge_forwarding import (
|
|
410
|
+
HTTPBridgeForwardContext as HTTPBridgeForwardContext,
|
|
411
|
+
)
|
|
412
|
+
from app.modules.proxy.http_bridge_forwarding import (
|
|
413
|
+
OwnerForwardRelayFailure as OwnerForwardRelayFailure,
|
|
414
|
+
)
|
|
415
|
+
from app.modules.proxy.load_balancer import AccountConcurrencyCaps, AccountLease
|
|
416
|
+
from app.modules.proxy.tool_call_dedupe import mark_duplicate_tool_call_downstream_event
|
|
417
|
+
from app.modules.proxy.tool_call_dedupe import (
|
|
418
|
+
response_id_from_payload as tool_call_response_id_from_payload,
|
|
419
|
+
)
|
|
420
|
+
from app.modules.proxy.tool_call_dedupe import (
|
|
421
|
+
rewrite_parallel_tool_call_sse_line as _rewrite_tool_call_line,
|
|
422
|
+
)
|
|
423
|
+
from app.modules.proxy.work_admission import AdmissionLease
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _facade() -> Any:
|
|
427
|
+
return sys.modules["app.modules.proxy.service"]
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
_REQUEST_TRANSPORT_HTTP = "http"
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
class _StreamingMixin(_StreamingRetryMixin):
|
|
434
|
+
_handle_stream_error = _handle_stream_error_helper
|
|
435
|
+
_resolve_upstream_route_for_account = _resolve_upstream_route_for_account_helper
|
|
436
|
+
_select_account_with_budget_for_stream = _select_account_with_budget_for_stream_helper
|
|
437
|
+
|
|
438
|
+
def stream_responses(
|
|
439
|
+
self,
|
|
440
|
+
payload: ResponsesRequest,
|
|
441
|
+
headers: Mapping[str, str],
|
|
442
|
+
*,
|
|
443
|
+
codex_session_affinity: bool = False,
|
|
444
|
+
propagate_http_errors: bool = False,
|
|
445
|
+
openai_cache_affinity: bool = False,
|
|
446
|
+
api_key: ApiKeyData | None = None,
|
|
447
|
+
api_key_reservation: ApiKeyUsageReservationData | None = None,
|
|
448
|
+
suppress_text_done_events: bool = False,
|
|
449
|
+
request_transport: str = _REQUEST_TRANSPORT_HTTP,
|
|
450
|
+
client_ip: str | None = None,
|
|
451
|
+
enforce_openai_sdk_contract: bool = True,
|
|
452
|
+
) -> AsyncIterator[str]:
|
|
453
|
+
proxy = cast(_StreamingServiceProtocol, self)
|
|
454
|
+
_maybe_log_proxy_request_payload("stream", payload, headers)
|
|
455
|
+
filtered = _facade().filter_inbound_headers(headers)
|
|
456
|
+
return proxy._stream_with_retry(
|
|
457
|
+
payload,
|
|
458
|
+
filtered,
|
|
459
|
+
codex_session_affinity=codex_session_affinity,
|
|
460
|
+
propagate_http_errors=propagate_http_errors,
|
|
461
|
+
openai_cache_affinity=openai_cache_affinity,
|
|
462
|
+
api_key=api_key,
|
|
463
|
+
api_key_reservation=api_key_reservation,
|
|
464
|
+
suppress_text_done_events=suppress_text_done_events,
|
|
465
|
+
request_transport=request_transport,
|
|
466
|
+
client_ip=client_ip,
|
|
467
|
+
enforce_openai_sdk_contract=enforce_openai_sdk_contract,
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
async def _stream_once(
|
|
471
|
+
self,
|
|
472
|
+
account: Account,
|
|
473
|
+
payload: ResponsesRequest,
|
|
474
|
+
headers: Mapping[str, str],
|
|
475
|
+
request_id: str,
|
|
476
|
+
allow_retry: bool,
|
|
477
|
+
*,
|
|
478
|
+
affinity_observation: AffinityObservation | None = None,
|
|
479
|
+
request_started_at: float,
|
|
480
|
+
allow_transient_retry: bool = False,
|
|
481
|
+
api_key: ApiKeyData | None,
|
|
482
|
+
api_key_reservation: ApiKeyUsageReservationData | None,
|
|
483
|
+
settlement: _StreamSettlement,
|
|
484
|
+
suppress_text_done_events: bool,
|
|
485
|
+
upstream_stream_transport: str | None,
|
|
486
|
+
request_transport: str,
|
|
487
|
+
concurrency_caps: AccountConcurrencyCaps | None = None,
|
|
488
|
+
useragent: str | None = None,
|
|
489
|
+
useragent_group: str | None = None,
|
|
490
|
+
conversation_id: str | None = None,
|
|
491
|
+
client_ip: str | None = None,
|
|
492
|
+
preferred_account_id: str | None = None,
|
|
493
|
+
tool_call_dedupe: _WebSocketUpstreamControl | None = None,
|
|
494
|
+
enforce_openai_sdk_contract: bool = True,
|
|
495
|
+
thread_cache_identity: ThreadCacheIdentity | None = None,
|
|
496
|
+
) -> AsyncIterator[str]:
|
|
497
|
+
proxy = cast(_StreamingServiceProtocol, self)
|
|
498
|
+
clock = clock_for(proxy)
|
|
499
|
+
preserve_native_failure_lifecycle = not enforce_openai_sdk_contract and _is_native_codex_request(headers)
|
|
500
|
+
account_id_value = account.id
|
|
501
|
+
access_token = proxy._encryptor.decrypt(account.access_token_encrypted)
|
|
502
|
+
account_id = _header_account_id(account.chatgpt_account_id)
|
|
503
|
+
model = payload.model
|
|
504
|
+
requested_service_tier = payload.service_tier
|
|
505
|
+
service_tier = requested_service_tier
|
|
506
|
+
actual_service_tier: str | None = None
|
|
507
|
+
reasoning_effort = payload.reasoning.effort if payload.reasoning else None
|
|
508
|
+
session_id = _owner_lookup_session_id_from_headers(headers)
|
|
509
|
+
# Keep selection/failover waits out of latency and TTFT, record them as
|
|
510
|
+
# queue time, then re-anchor after this attempt's admission wait.
|
|
511
|
+
attempt_started_at = start = clock.monotonic()
|
|
512
|
+
latency_queue_ms = max(0, int((start - request_started_at) * 1000))
|
|
513
|
+
status, error_code, error_message = "success", None, None
|
|
514
|
+
failure_metadata = _RequestLogFailureMetadata()
|
|
515
|
+
response_id = request_id
|
|
516
|
+
usage = None
|
|
517
|
+
route: ResolvedUpstreamRoute | None = None
|
|
518
|
+
route_trace = UpstreamProxyRouteTrace()
|
|
519
|
+
route_fail_closed_reason: str | None = None
|
|
520
|
+
saw_text_delta = terminal_event_seen = suppressed_duplicate_tool_call = False
|
|
521
|
+
latency_first_token_ms: int | None = None
|
|
522
|
+
ttft_reasoning_deltas: dict[tuple[str | None, int | None, int | None], Any] = {}
|
|
523
|
+
if tool_call_dedupe is None:
|
|
524
|
+
tool_call_dedupe = _WebSocketUpstreamControl()
|
|
525
|
+
response_create_lease = AdmissionLease(None, stage="response_create", request_id=request_id)
|
|
526
|
+
account_response_create_lease: AccountLease | None = None
|
|
527
|
+
api_key_reservation_touch_state = _ApiKeyReservationTouchState(last_touch_at=start)
|
|
528
|
+
|
|
529
|
+
async def _touch_api_key_reservation() -> None:
|
|
530
|
+
api_key_reservation_touch_state.last_touch_at = await proxy._maybe_touch_api_key_reservation(
|
|
531
|
+
api_key=api_key,
|
|
532
|
+
reservation=api_key_reservation,
|
|
533
|
+
last_touch_at=api_key_reservation_touch_state.last_touch_at,
|
|
534
|
+
request_id=request_id,
|
|
535
|
+
surface="stream",
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
async def _record_or_defer_owner_recovery_health(error: UpstreamError, code: str | None) -> None:
|
|
539
|
+
if code is None:
|
|
540
|
+
return
|
|
541
|
+
if api_key_reservation is None:
|
|
542
|
+
await proxy._handle_stream_error(account, error, code)
|
|
543
|
+
return
|
|
544
|
+
settlement.error_code = code
|
|
545
|
+
settlement.account_health_error = True
|
|
546
|
+
settlement.settlement_order_required = True
|
|
547
|
+
|
|
548
|
+
api_key_reservation_heartbeat_stop = asyncio.Event()
|
|
549
|
+
api_key_reservation_heartbeat_task: asyncio.Task[None] | None = None
|
|
550
|
+
if api_key_reservation is not None:
|
|
551
|
+
api_key_reservation_heartbeat_task = scheduler_for(proxy).create_task(
|
|
552
|
+
proxy._run_api_key_reservation_heartbeat(
|
|
553
|
+
api_key=api_key,
|
|
554
|
+
reservation=api_key_reservation,
|
|
555
|
+
touch_state=api_key_reservation_touch_state,
|
|
556
|
+
request_id=request_id,
|
|
557
|
+
surface="stream",
|
|
558
|
+
stop_event=api_key_reservation_heartbeat_stop,
|
|
559
|
+
)
|
|
560
|
+
)
|
|
561
|
+
try:
|
|
562
|
+
route = await proxy._resolve_upstream_route_for_account(account, operation="responses")
|
|
563
|
+
account_response_create_lease = await proxy._acquire_account_response_create_lease_or_overload(
|
|
564
|
+
account_id=account.id,
|
|
565
|
+
request_id=request_id,
|
|
566
|
+
surface="stream",
|
|
567
|
+
concurrency_caps=concurrency_caps or _facade().effective_account_concurrency_caps(),
|
|
568
|
+
)
|
|
569
|
+
response_create_lease = await proxy._get_work_admission().acquire_response_create()
|
|
570
|
+
attempt_started_at = clock.monotonic()
|
|
571
|
+
latency_queue_ms = max(0, int((attempt_started_at - request_started_at) * 1000))
|
|
572
|
+
stream_optional_kwargs: dict[str, object] = {
|
|
573
|
+
"route": route,
|
|
574
|
+
"allow_direct_egress": route is None,
|
|
575
|
+
"route_trace": route_trace,
|
|
576
|
+
"codex_installation_id": account.codex_installation_id,
|
|
577
|
+
"enforce_openai_sdk_contract": enforce_openai_sdk_contract,
|
|
578
|
+
"codex_lb_account_id": account.id,
|
|
579
|
+
# Selected subscription Account, independent of optional legacy header.
|
|
580
|
+
"synthesize_routing_hint": True,
|
|
581
|
+
"thread_cache_identity": thread_cache_identity,
|
|
582
|
+
}
|
|
583
|
+
if upstream_stream_transport is not None:
|
|
584
|
+
stream_optional_kwargs["upstream_stream_transport_override"] = upstream_stream_transport
|
|
585
|
+
stream = _facade()._call_stream_with_supported_optional_kwargs(
|
|
586
|
+
_facade().core_stream_responses,
|
|
587
|
+
payload,
|
|
588
|
+
headers,
|
|
589
|
+
access_token,
|
|
590
|
+
account_id,
|
|
591
|
+
optional_kwargs=stream_optional_kwargs,
|
|
592
|
+
raise_for_status=True,
|
|
593
|
+
)
|
|
594
|
+
iterator = _facade()._stream_iterator_after_capacity_admission(stream)
|
|
595
|
+
try:
|
|
596
|
+
first = await iterator.__anext__()
|
|
597
|
+
except StopAsyncIteration:
|
|
598
|
+
response_create_lease.release()
|
|
599
|
+
await proxy._load_balancer.release_account_lease(account_response_create_lease)
|
|
600
|
+
account_response_create_lease = None
|
|
601
|
+
status = "error"
|
|
602
|
+
error_code = "stream_incomplete"
|
|
603
|
+
error_message = "Upstream websocket closed before response.completed"
|
|
604
|
+
settlement.record_success = False
|
|
605
|
+
terminal_event_seen = settlement.account_health_error = True
|
|
606
|
+
settlement.error = {"message": error_message}
|
|
607
|
+
yield _stream_transport_failure_event_or_raise(
|
|
608
|
+
error_code,
|
|
609
|
+
error_message,
|
|
610
|
+
response_id=request_id,
|
|
611
|
+
preserve_native_failure_lifecycle=preserve_native_failure_lifecycle,
|
|
612
|
+
)
|
|
613
|
+
return
|
|
614
|
+
except (aiohttp.ClientError, asyncio.TimeoutError) as exc:
|
|
615
|
+
response_create_lease.release()
|
|
616
|
+
await proxy._load_balancer.release_account_lease(account_response_create_lease)
|
|
617
|
+
account_response_create_lease = None
|
|
618
|
+
status = "error"
|
|
619
|
+
error_code = "upstream_unavailable"
|
|
620
|
+
error_message = str(exc) or "Request to upstream timed out"
|
|
621
|
+
settlement.record_success = False
|
|
622
|
+
terminal_event_seen = settlement.account_health_error = True
|
|
623
|
+
settlement.error = {"message": error_message}
|
|
624
|
+
yield _stream_transport_failure_event_or_raise(
|
|
625
|
+
error_code,
|
|
626
|
+
error_message,
|
|
627
|
+
response_id=request_id,
|
|
628
|
+
preserve_native_failure_lifecycle=preserve_native_failure_lifecycle,
|
|
629
|
+
)
|
|
630
|
+
return
|
|
631
|
+
response_create_lease.release()
|
|
632
|
+
await proxy._load_balancer.release_account_lease(account_response_create_lease)
|
|
633
|
+
account_response_create_lease = None
|
|
634
|
+
first_payload = parse_sse_data_json(first)
|
|
635
|
+
event_type = classify_event_type(first_payload)
|
|
636
|
+
event = parse_sse_event_payload(first_payload) if event_type in _LIFECYCLE_EVENT_TYPES else None
|
|
637
|
+
_publish_http_response_owner(proxy, event, first_payload, first, account_id_value, api_key, session_id)
|
|
638
|
+
preserve_raw_sse_line = not enforce_openai_sdk_contract and event_type == "error"
|
|
639
|
+
malformed_error_rewrite = _rewrite_malformed_stream_error_event(
|
|
640
|
+
enforce_openai_sdk_contract=enforce_openai_sdk_contract,
|
|
641
|
+
event=event,
|
|
642
|
+
event_type=event_type,
|
|
643
|
+
event_payload=first_payload,
|
|
644
|
+
response_id=response_id,
|
|
645
|
+
)
|
|
646
|
+
if malformed_error_rewrite is not None:
|
|
647
|
+
first, event, first_payload, event_type = malformed_error_rewrite
|
|
648
|
+
terminal_event_seen, response_id, usage = _settle_bg_ack(settlement, payload, first_payload, response_id)
|
|
649
|
+
if event_type not in {"response.completed", "response.failed", "response.incomplete", "error"}:
|
|
650
|
+
await _touch_api_key_reservation()
|
|
651
|
+
event_service_tier = _facade()._service_tier_from_event_payload(first_payload)
|
|
652
|
+
if event_service_tier is not None:
|
|
653
|
+
actual_service_tier = event_service_tier
|
|
654
|
+
service_tier = event_service_tier
|
|
655
|
+
if event and event.response and event.response.id:
|
|
656
|
+
response_id = event.response.id
|
|
657
|
+
settlement.response_id = response_id
|
|
658
|
+
terminal_stream_error: _TerminalStreamError | None = None
|
|
659
|
+
if event and event.type in ("response.failed", "error"):
|
|
660
|
+
if event.type == "response.failed":
|
|
661
|
+
response = event.response
|
|
662
|
+
error = response.error if response else None
|
|
663
|
+
else:
|
|
664
|
+
error = event.error
|
|
665
|
+
response_id = (
|
|
666
|
+
event.response.id
|
|
667
|
+
if event.type == "response.failed" and event.response and event.response.id
|
|
668
|
+
else request_id
|
|
669
|
+
)
|
|
670
|
+
if preserve_raw_sse_line and error is None:
|
|
671
|
+
raw_error_type, raw_error_message, raw_error_param, code = _raw_error_fields(
|
|
672
|
+
event_type,
|
|
673
|
+
first_payload,
|
|
674
|
+
)
|
|
675
|
+
settlement.error = cast(UpstreamError, {"message": raw_error_message or "Upstream error"})
|
|
676
|
+
else:
|
|
677
|
+
raw_error_type = error.type if error else None
|
|
678
|
+
raw_error_message = error.message if error else None
|
|
679
|
+
raw_error_param = error.param_state if error else None
|
|
680
|
+
code = _normalize_error_code(
|
|
681
|
+
error.code if error else None,
|
|
682
|
+
raw_error_type,
|
|
683
|
+
)
|
|
684
|
+
code = _classify_terminal_stream_error_frame(event_type, first_payload, code, raw_error_message)
|
|
685
|
+
rewritten_error = _facade()._rewrite_previous_response_stream_error(
|
|
686
|
+
previous_response_id=payload.previous_response_id,
|
|
687
|
+
preferred_account_id=preferred_account_id,
|
|
688
|
+
error_code=code,
|
|
689
|
+
error_type=raw_error_type,
|
|
690
|
+
error_message=raw_error_message,
|
|
691
|
+
error_param=raw_error_param,
|
|
692
|
+
)
|
|
693
|
+
status = "error"
|
|
694
|
+
if not (preserve_raw_sse_line and error is None):
|
|
695
|
+
settlement.error = _upstream_error_from_openai(error)
|
|
696
|
+
upstream_error: UpstreamError = settlement.error or cast(UpstreamError, {"message": "Upstream error"})
|
|
697
|
+
settlement.record_success = False
|
|
698
|
+
if rewritten_error is not None:
|
|
699
|
+
rewritten_code, rewritten_message, upstream_error_code = rewritten_error
|
|
700
|
+
first, event, first_payload, event_type = _facade()._build_rewritten_stream_response_failed_event(
|
|
701
|
+
response_id=response_id,
|
|
702
|
+
error_code=rewritten_code,
|
|
703
|
+
error_message=rewritten_message,
|
|
704
|
+
)
|
|
705
|
+
error_code = rewritten_code
|
|
706
|
+
error_message = rewritten_message
|
|
707
|
+
await _record_or_defer_owner_recovery_health(upstream_error, upstream_error_code)
|
|
708
|
+
upstream_error = cast(
|
|
709
|
+
UpstreamError, {"message": rewritten_message, "type": "upstream_error", "code": rewritten_code}
|
|
710
|
+
)
|
|
711
|
+
else:
|
|
712
|
+
error_code = code
|
|
713
|
+
error_message = raw_error_message
|
|
714
|
+
if error_code == "stream_incomplete":
|
|
715
|
+
failure_metadata = _RequestLogFailureMetadata(
|
|
716
|
+
failure_phase="upstream", failure_detail="upstream_eof_before_terminal_event"
|
|
717
|
+
)
|
|
718
|
+
settlement.account_health_error = _facade()._should_penalize_stream_error(code, error_message)
|
|
719
|
+
if allow_retry and code == "stream_idle_timeout":
|
|
720
|
+
raise _RetryableStreamError(code, upstream_error, exclude_account=True)
|
|
721
|
+
if allow_retry and _facade()._is_security_work_authorization_required_error(code, error_message):
|
|
722
|
+
error_code = _facade()._SECURITY_WORK_AUTHORIZATION_REQUIRED_CODE
|
|
723
|
+
raise _RetryableStreamError(
|
|
724
|
+
_facade()._SECURITY_WORK_AUTHORIZATION_REQUIRED_CODE,
|
|
725
|
+
upstream_error,
|
|
726
|
+
)
|
|
727
|
+
if allow_retry and _facade()._should_retry_stream_error(code, error_message):
|
|
728
|
+
raise _RetryableStreamError(code, upstream_error, exclude_account=True)
|
|
729
|
+
terminal_stream_error = _TerminalStreamError(
|
|
730
|
+
error_code or code,
|
|
731
|
+
upstream_error,
|
|
732
|
+
)
|
|
733
|
+
if allow_retry:
|
|
734
|
+
_facade().logger.info(
|
|
735
|
+
"Not retrying non-recoverable stream failure request_id=%s account_id=%s code=%s",
|
|
736
|
+
request_id,
|
|
737
|
+
account_id_value,
|
|
738
|
+
error_code or code,
|
|
739
|
+
)
|
|
740
|
+
elif preserve_raw_sse_line:
|
|
741
|
+
_, error_message, _, code = _raw_error_fields(event_type, first_payload)
|
|
742
|
+
status = "error"
|
|
743
|
+
error_code = code
|
|
744
|
+
settlement.error = {"message": error_message or "Upstream error"}
|
|
745
|
+
settlement.record_success = False
|
|
746
|
+
settlement.account_health_error = False
|
|
747
|
+
if event and event.type in ("response.completed", "response.incomplete"):
|
|
748
|
+
usage = event.response.usage if event.response else None
|
|
749
|
+
if event.response and event.response.id:
|
|
750
|
+
response_id = event.response.id
|
|
751
|
+
if event.type == "response.incomplete":
|
|
752
|
+
status = "error"
|
|
753
|
+
|
|
754
|
+
if event_type in _facade()._TEXT_DELTA_EVENT_TYPES:
|
|
755
|
+
saw_text_delta = True
|
|
756
|
+
if not _facade()._should_suppress_text_done_event(
|
|
757
|
+
event_type=event_type,
|
|
758
|
+
payload=first_payload,
|
|
759
|
+
suppress_text_done_events=suppress_text_done_events,
|
|
760
|
+
saw_text_delta=saw_text_delta,
|
|
761
|
+
):
|
|
762
|
+
first, first_payload, event, event_type = _rewrite_tool_call_line(first, first_payload, event=event)
|
|
763
|
+
if mark_duplicate_tool_call_downstream_event(
|
|
764
|
+
first_payload,
|
|
765
|
+
seen_tool_call_keys=tool_call_dedupe.seen_tool_call_keys,
|
|
766
|
+
response_id=tool_call_response_id_from_payload(first_payload) or request_id,
|
|
767
|
+
scope_side_effects_by_response_id=False,
|
|
768
|
+
):
|
|
769
|
+
suppressed_duplicate_tool_call = True
|
|
770
|
+
else:
|
|
771
|
+
if first_payload is not None and not preserve_raw_sse_line:
|
|
772
|
+
first = format_sse_event(first_payload)
|
|
773
|
+
terminal_event_seen = terminal_event_seen or _stamp_terminal(settlement, event_type, clock)
|
|
774
|
+
if latency_first_token_ms is None:
|
|
775
|
+
latency_first_token_ms = _ttft_event_latency_ms(
|
|
776
|
+
event_type, first_payload, ttft_reasoning_deltas, attempt_started_at, now=clock.monotonic()
|
|
777
|
+
)
|
|
778
|
+
settlement.downstream_visible = True
|
|
779
|
+
if event_type in _facade()._TEXT_DELTA_EVENT_TYPES:
|
|
780
|
+
settlement.downstream_text_visible = True
|
|
781
|
+
yield first
|
|
782
|
+
if terminal_stream_error is not None:
|
|
783
|
+
raise terminal_stream_error
|
|
784
|
+
async for line in iterator:
|
|
785
|
+
if verbatim_type := _verbatim_relay_event_type(line, latency_first_token_ms, ttft_reasoning_deltas):
|
|
786
|
+
await _touch_api_key_reservation()
|
|
787
|
+
if verbatim_type in _facade()._TEXT_DELTA_EVENT_TYPES:
|
|
788
|
+
saw_text_delta = settlement.downstream_text_visible = True
|
|
789
|
+
settlement.downstream_visible = True
|
|
790
|
+
yield line
|
|
791
|
+
continue
|
|
792
|
+
event_payload = parse_sse_data_json(line)
|
|
793
|
+
event_type = classify_event_type(event_payload)
|
|
794
|
+
event = parse_sse_event_payload(event_payload) if event_type in _LIFECYCLE_EVENT_TYPES else None
|
|
795
|
+
_publish_http_response_owner(proxy, event, event_payload, line, account_id_value, api_key, session_id)
|
|
796
|
+
preserve_raw_sse_line = not enforce_openai_sdk_contract and event_type == "error"
|
|
797
|
+
malformed_error_rewrite = _rewrite_malformed_stream_error_event(
|
|
798
|
+
enforce_openai_sdk_contract=enforce_openai_sdk_contract,
|
|
799
|
+
event=event,
|
|
800
|
+
event_type=event_type,
|
|
801
|
+
event_payload=event_payload,
|
|
802
|
+
response_id=response_id,
|
|
803
|
+
)
|
|
804
|
+
if malformed_error_rewrite is not None:
|
|
805
|
+
line, event, event_payload, event_type = malformed_error_rewrite
|
|
806
|
+
if event_type not in {"response.completed", "response.failed", "response.incomplete", "error"}:
|
|
807
|
+
await _touch_api_key_reservation()
|
|
808
|
+
event_service_tier = _facade()._service_tier_from_event_payload(event_payload)
|
|
809
|
+
if event_service_tier is not None:
|
|
810
|
+
actual_service_tier = event_service_tier
|
|
811
|
+
service_tier = event_service_tier
|
|
812
|
+
line, event_payload, event, event_type = _rewrite_tool_call_line(line, event_payload, event=event)
|
|
813
|
+
if event_type in _facade()._TEXT_DELTA_EVENT_TYPES:
|
|
814
|
+
saw_text_delta = True
|
|
815
|
+
if _facade()._should_suppress_text_done_event(
|
|
816
|
+
event_type=event_type,
|
|
817
|
+
payload=event_payload,
|
|
818
|
+
suppress_text_done_events=suppress_text_done_events,
|
|
819
|
+
saw_text_delta=saw_text_delta,
|
|
820
|
+
):
|
|
821
|
+
continue
|
|
822
|
+
if event:
|
|
823
|
+
if event_type in ("response.failed", "error"):
|
|
824
|
+
status = "error"
|
|
825
|
+
if event_type == "response.failed":
|
|
826
|
+
response = event.response
|
|
827
|
+
error = response.error if response else None
|
|
828
|
+
if response and response.id:
|
|
829
|
+
response_id = response.id
|
|
830
|
+
settlement.response_id = response_id
|
|
831
|
+
else:
|
|
832
|
+
error = event.error
|
|
833
|
+
raw_error_type, raw_error_message, raw_error_param = _openai_error_fields(error)
|
|
834
|
+
if preserve_raw_sse_line and error is None:
|
|
835
|
+
raw_error_type, raw_error_message, raw_error_param, raw_error_code = _raw_error_fields(
|
|
836
|
+
event_type,
|
|
837
|
+
event_payload,
|
|
838
|
+
)
|
|
839
|
+
upstream_error = cast(UpstreamError, {"message": raw_error_message or "Upstream error"})
|
|
840
|
+
else:
|
|
841
|
+
raw_error_code = _normalize_error_code(error.code if error else None, raw_error_type)
|
|
842
|
+
upstream_error = _upstream_error_from_openai(error)
|
|
843
|
+
raw_error_code = _classify_terminal_stream_error_frame(
|
|
844
|
+
event_type, event_payload, raw_error_code, raw_error_message
|
|
845
|
+
)
|
|
846
|
+
rewritten_error = _facade()._rewrite_previous_response_stream_error(
|
|
847
|
+
previous_response_id=payload.previous_response_id,
|
|
848
|
+
preferred_account_id=preferred_account_id,
|
|
849
|
+
error_code=raw_error_code,
|
|
850
|
+
error_type=raw_error_type,
|
|
851
|
+
error_message=raw_error_message,
|
|
852
|
+
error_param=raw_error_param,
|
|
853
|
+
)
|
|
854
|
+
if rewritten_error is not None:
|
|
855
|
+
response_id = (
|
|
856
|
+
event.response.id
|
|
857
|
+
if event_type == "response.failed" and event.response and event.response.id
|
|
858
|
+
else request_id
|
|
859
|
+
)
|
|
860
|
+
rewritten_code, rewritten_message, upstream_error_code = rewritten_error
|
|
861
|
+
(
|
|
862
|
+
line,
|
|
863
|
+
event,
|
|
864
|
+
event_payload,
|
|
865
|
+
event_type,
|
|
866
|
+
) = _facade()._build_rewritten_stream_response_failed_event(
|
|
867
|
+
response_id=response_id,
|
|
868
|
+
error_code=rewritten_code,
|
|
869
|
+
error_message=rewritten_message,
|
|
870
|
+
)
|
|
871
|
+
error_code = rewritten_code
|
|
872
|
+
error_message = rewritten_message
|
|
873
|
+
settlement.error = _upstream_error_from_openai(error)
|
|
874
|
+
settlement.record_success = False
|
|
875
|
+
await _record_or_defer_owner_recovery_health(
|
|
876
|
+
_upstream_error_from_openai(error), upstream_error_code
|
|
877
|
+
)
|
|
878
|
+
else:
|
|
879
|
+
error_code = raw_error_code
|
|
880
|
+
error_message = raw_error_message
|
|
881
|
+
settlement.error = upstream_error
|
|
882
|
+
settlement.record_success = False
|
|
883
|
+
if error_code == "stream_incomplete":
|
|
884
|
+
failure_metadata = _RequestLogFailureMetadata(
|
|
885
|
+
failure_phase="upstream",
|
|
886
|
+
failure_detail="upstream_eof_before_terminal_event",
|
|
887
|
+
)
|
|
888
|
+
if preserve_raw_sse_line and error is None:
|
|
889
|
+
settlement.account_health_error = not saw_text_delta
|
|
890
|
+
else:
|
|
891
|
+
settlement.account_health_error = (
|
|
892
|
+
_facade()._should_penalize_stream_error(error_code, error_message)
|
|
893
|
+
and not saw_text_delta
|
|
894
|
+
)
|
|
895
|
+
elif preserve_raw_sse_line:
|
|
896
|
+
_, raw_error_message, _, raw_error_code = _raw_error_fields(
|
|
897
|
+
event_type,
|
|
898
|
+
event_payload,
|
|
899
|
+
)
|
|
900
|
+
_observe_terminal_stream_error_frame(raw_error_code, raw_error_message)
|
|
901
|
+
status = "error"
|
|
902
|
+
error_code = raw_error_code
|
|
903
|
+
error_message = raw_error_message
|
|
904
|
+
settlement.error = {"message": raw_error_message or "Upstream error"}
|
|
905
|
+
settlement.record_success = False
|
|
906
|
+
settlement.account_health_error = not saw_text_delta
|
|
907
|
+
if event_type in ("response.completed", "response.incomplete"):
|
|
908
|
+
response = event.response if event is not None else None
|
|
909
|
+
usage = response.usage if response else None
|
|
910
|
+
if response and response.id:
|
|
911
|
+
response_id = response.id
|
|
912
|
+
settlement.response_id = response_id
|
|
913
|
+
if event_type == "response.incomplete":
|
|
914
|
+
status = "error"
|
|
915
|
+
if event_type == "response.completed" and suppressed_duplicate_tool_call:
|
|
916
|
+
(
|
|
917
|
+
line,
|
|
918
|
+
event,
|
|
919
|
+
event_payload,
|
|
920
|
+
event_type,
|
|
921
|
+
) = _facade()._build_rewritten_stream_response_failed_event(
|
|
922
|
+
response_id=response_id,
|
|
923
|
+
error_code=_facade()._SUPPRESSED_DUPLICATE_TOOL_CALL_ERROR_CODE,
|
|
924
|
+
error_message=_facade()._SUPPRESSED_DUPLICATE_TOOL_CALL_MESSAGE,
|
|
925
|
+
)
|
|
926
|
+
status = "error"
|
|
927
|
+
error_code = _facade()._SUPPRESSED_DUPLICATE_TOOL_CALL_ERROR_CODE
|
|
928
|
+
error_message = _facade()._SUPPRESSED_DUPLICATE_TOOL_CALL_MESSAGE
|
|
929
|
+
settlement.record_success = False
|
|
930
|
+
settlement.account_health_error = False
|
|
931
|
+
if latency_first_token_ms is None:
|
|
932
|
+
latency_first_token_ms = _ttft_event_latency_ms(
|
|
933
|
+
event_type, event_payload, ttft_reasoning_deltas, attempt_started_at, now=clock.monotonic()
|
|
934
|
+
)
|
|
935
|
+
if mark_duplicate_tool_call_downstream_event(
|
|
936
|
+
event_payload,
|
|
937
|
+
seen_tool_call_keys=tool_call_dedupe.seen_tool_call_keys,
|
|
938
|
+
response_id=tool_call_response_id_from_payload(event_payload) or request_id,
|
|
939
|
+
scope_side_effects_by_response_id=False,
|
|
940
|
+
):
|
|
941
|
+
suppressed_duplicate_tool_call = True
|
|
942
|
+
continue
|
|
943
|
+
if event_payload is not None and not preserve_raw_sse_line:
|
|
944
|
+
line = format_sse_event(event_payload)
|
|
945
|
+
settlement.downstream_visible = True
|
|
946
|
+
if event_type in _facade()._TEXT_DELTA_EVENT_TYPES:
|
|
947
|
+
settlement.downstream_text_visible = True
|
|
948
|
+
terminal_event_seen = terminal_event_seen or _stamp_terminal(settlement, event_type, clock)
|
|
949
|
+
yield line
|
|
950
|
+
if not terminal_event_seen:
|
|
951
|
+
status, error_code, error_message, failure_metadata = _mark_upstream_stream_incomplete(settlement)
|
|
952
|
+
except ProxyResponseError as exc:
|
|
953
|
+
response_create_lease.release()
|
|
954
|
+
failure_metadata = _facade()._request_log_failure_metadata(exc)
|
|
955
|
+
error = _parse_openai_error(exc.payload)
|
|
956
|
+
rewritten_error = _facade()._rewrite_previous_response_stream_error(
|
|
957
|
+
previous_response_id=payload.previous_response_id,
|
|
958
|
+
preferred_account_id=preferred_account_id,
|
|
959
|
+
error_code=_normalize_error_code(
|
|
960
|
+
error.code if error else None,
|
|
961
|
+
error.type if error else None,
|
|
962
|
+
),
|
|
963
|
+
error_type=error.type if error else None,
|
|
964
|
+
error_message=error.message if error else None,
|
|
965
|
+
error_param=error.param_state if error else None,
|
|
966
|
+
)
|
|
967
|
+
if rewritten_error is not None:
|
|
968
|
+
rewritten_code, rewritten_message, upstream_error_code = rewritten_error
|
|
969
|
+
status = "error"
|
|
970
|
+
error_code = rewritten_code
|
|
971
|
+
error_message = rewritten_message
|
|
972
|
+
settlement.record_success = False
|
|
973
|
+
settlement.error = _upstream_error_from_openai(error)
|
|
974
|
+
await _record_or_defer_owner_recovery_health(_upstream_error_from_openai(error), upstream_error_code)
|
|
975
|
+
yield _facade()._build_rewritten_stream_response_failed_event(
|
|
976
|
+
response_id=request_id,
|
|
977
|
+
error_code=rewritten_code,
|
|
978
|
+
error_message=rewritten_message,
|
|
979
|
+
)[0]
|
|
980
|
+
return
|
|
981
|
+
status = "error"
|
|
982
|
+
error_code = _normalize_error_code(
|
|
983
|
+
error.code if error else None,
|
|
984
|
+
error.type if error else None,
|
|
985
|
+
)
|
|
986
|
+
error_message = error.message if error else None
|
|
987
|
+
settlement.record_success = False
|
|
988
|
+
settlement.account_health_error = _facade()._should_penalize_stream_error(error_code, error_message)
|
|
989
|
+
raise
|
|
990
|
+
except UpstreamProxyRouteError as exc:
|
|
991
|
+
route_fail_closed_reason = exc.reason
|
|
992
|
+
status = "error"
|
|
993
|
+
error_code = "upstream_proxy_unavailable"
|
|
994
|
+
error_message = f"Upstream proxy route unavailable: {exc.reason}"
|
|
995
|
+
settlement.record_success = False
|
|
996
|
+
settlement.account_health_error = False
|
|
997
|
+
settlement.error = {"message": error_message}
|
|
998
|
+
yield format_sse_event(
|
|
999
|
+
response_failed_event(
|
|
1000
|
+
"upstream_proxy_unavailable",
|
|
1001
|
+
error_message,
|
|
1002
|
+
response_id=request_id,
|
|
1003
|
+
)
|
|
1004
|
+
)
|
|
1005
|
+
return
|
|
1006
|
+
except _TerminalStreamError:
|
|
1007
|
+
raise
|
|
1008
|
+
except (asyncio.CancelledError, GeneratorExit):
|
|
1009
|
+
if not terminal_event_seen:
|
|
1010
|
+
status, error_code, error_message, failure_metadata = _mark_downstream_stream_cancelled(settlement)
|
|
1011
|
+
raise
|
|
1012
|
+
except Exception:
|
|
1013
|
+
if settlement.downstream_visible:
|
|
1014
|
+
status, error_code, error_message, failure_metadata = _mark_upstream_stream_incomplete(settlement)
|
|
1015
|
+
yield _stream_transport_failure_event_or_raise(
|
|
1016
|
+
error_code,
|
|
1017
|
+
error_message,
|
|
1018
|
+
response_id=request_id,
|
|
1019
|
+
preserve_native_failure_lifecycle=preserve_native_failure_lifecycle,
|
|
1020
|
+
)
|
|
1021
|
+
return
|
|
1022
|
+
raise
|
|
1023
|
+
finally:
|
|
1024
|
+
api_key_reservation_heartbeat_stop.set()
|
|
1025
|
+
if api_key_reservation_heartbeat_task is not None:
|
|
1026
|
+
proxy._cancel_api_key_reservation_heartbeat_task(api_key_reservation_heartbeat_task)
|
|
1027
|
+
response_create_lease.release()
|
|
1028
|
+
await proxy._load_balancer.release_account_lease(account_response_create_lease)
|
|
1029
|
+
input_tokens = usage.input_tokens if usage else None
|
|
1030
|
+
output_tokens = usage.output_tokens if usage else None
|
|
1031
|
+
cached_input_tokens = (
|
|
1032
|
+
usage.input_tokens_details.cached_tokens if usage and usage.input_tokens_details else None
|
|
1033
|
+
)
|
|
1034
|
+
reasoning_tokens = (
|
|
1035
|
+
usage.output_tokens_details.reasoning_tokens if usage and usage.output_tokens_details else None
|
|
1036
|
+
)
|
|
1037
|
+
if latency_first_token_ms is None:
|
|
1038
|
+
latency_first_token_ms = _finalize_ttft_latency_ms(
|
|
1039
|
+
ttft_reasoning_deltas, attempt_started_at, now=clock.monotonic()
|
|
1040
|
+
)
|
|
1041
|
+
settlement.status = status
|
|
1042
|
+
settlement.model = model
|
|
1043
|
+
settlement.service_tier = service_tier
|
|
1044
|
+
settlement.input_tokens = input_tokens
|
|
1045
|
+
settlement.output_tokens = output_tokens
|
|
1046
|
+
settlement.cached_input_tokens = cached_input_tokens
|
|
1047
|
+
if settlement.error_code is None:
|
|
1048
|
+
settlement.error_code = error_code
|
|
1049
|
+
settlement.error_message = error_message
|
|
1050
|
+
await proxy._write_request_log(
|
|
1051
|
+
affinity_observation=affinity_observation,
|
|
1052
|
+
account_id=account_id_value,
|
|
1053
|
+
api_key=api_key,
|
|
1054
|
+
request_id=response_id,
|
|
1055
|
+
archive_request_id=request_id,
|
|
1056
|
+
model=model,
|
|
1057
|
+
latency_ms=int((clock.monotonic() - attempt_started_at) * 1000),
|
|
1058
|
+
status=status,
|
|
1059
|
+
error_code=error_code,
|
|
1060
|
+
error_message=error_message,
|
|
1061
|
+
input_tokens=input_tokens,
|
|
1062
|
+
output_tokens=output_tokens,
|
|
1063
|
+
cached_input_tokens=cached_input_tokens,
|
|
1064
|
+
reasoning_tokens=reasoning_tokens,
|
|
1065
|
+
reasoning_effort=reasoning_effort,
|
|
1066
|
+
transport=request_transport,
|
|
1067
|
+
upstream_transport=upstream_stream_transport,
|
|
1068
|
+
service_tier=service_tier,
|
|
1069
|
+
requested_service_tier=requested_service_tier,
|
|
1070
|
+
actual_service_tier=actual_service_tier,
|
|
1071
|
+
latency_first_token_ms=latency_first_token_ms,
|
|
1072
|
+
latency_queue_ms=latency_queue_ms,
|
|
1073
|
+
latency_upstream_send_ms=0, # attempt_started_at is re-anchored right before the upstream send
|
|
1074
|
+
latency_upstream_terminal_ms=_upstream_terminal_latency_ms(settlement, attempt_started_at),
|
|
1075
|
+
session_id=session_id,
|
|
1076
|
+
failure_phase=failure_metadata.failure_phase,
|
|
1077
|
+
failure_detail=failure_metadata.failure_detail,
|
|
1078
|
+
failure_exception_type=failure_metadata.failure_exception_type,
|
|
1079
|
+
upstream_status_code=failure_metadata.upstream_status_code,
|
|
1080
|
+
upstream_error_code=failure_metadata.upstream_error_code,
|
|
1081
|
+
bridge_stage=failure_metadata.bridge_stage,
|
|
1082
|
+
upstream_proxy_route_mode=route_trace.mode or (route.mode if route is not None else None),
|
|
1083
|
+
upstream_proxy_pool_id=route_trace.pool_id or (route.pool_id if route is not None else None),
|
|
1084
|
+
upstream_proxy_endpoint_id=route_trace.endpoint_id or (route.endpoint_id if route else None),
|
|
1085
|
+
upstream_proxy_fallback_used=(
|
|
1086
|
+
route_trace.fallback_used
|
|
1087
|
+
if route_trace.endpoint_id is not None
|
|
1088
|
+
else (False if route is not None else None)
|
|
1089
|
+
),
|
|
1090
|
+
upstream_proxy_fail_closed_reason=route_fail_closed_reason,
|
|
1091
|
+
useragent=useragent,
|
|
1092
|
+
useragent_group=useragent_group,
|
|
1093
|
+
conversation_id=conversation_id,
|
|
1094
|
+
client_ip=client_ip,
|
|
1095
|
+
)
|
|
1096
|
+
_maybe_log_proxy_service_tier_trace(
|
|
1097
|
+
"stream",
|
|
1098
|
+
requested_service_tier=requested_service_tier,
|
|
1099
|
+
actual_service_tier=actual_service_tier,
|
|
1100
|
+
)
|