alysis-code 0.13.0__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.
- alysis_code/__init__.py +3 -0
- alysis_code/__main__.py +4 -0
- alysis_code/_build_info.py +14 -0
- alysis_code/account_login.py +468 -0
- alysis_code/agent/README.md +35 -0
- alysis_code/agent/__init__.py +11 -0
- alysis_code/agent/acceptance_contract.py +2217 -0
- alysis_code/agent/blast_radius.py +1403 -0
- alysis_code/agent/cache_keepalive.py +227 -0
- alysis_code/agent/completion_certificate.py +366 -0
- alysis_code/agent/completion_gate.py +306 -0
- alysis_code/agent/empty_response_stall.py +403 -0
- alysis_code/agent/errors.py +28 -0
- alysis_code/agent/llm_calls.py +475 -0
- alysis_code/agent/mutation_classification.py +227 -0
- alysis_code/agent/prompt_context.py +2508 -0
- alysis_code/agent/read_ledger.py +253 -0
- alysis_code/agent/regression_baseline.py +642 -0
- alysis_code/agent/reproduction_first.py +610 -0
- alysis_code/agent/sensitive_output.py +629 -0
- alysis_code/agent/session.py +3218 -0
- alysis_code/agent/steering.py +191 -0
- alysis_code/agent/subagent_execution.py +5177 -0
- alysis_code/agent/subagent_workspace.py +666 -0
- alysis_code/agent/tools_assembly.py +4728 -0
- alysis_code/agent/turn/__init__.py +101 -0
- alysis_code/agent/turn/core.py +8483 -0
- alysis_code/agent/turn/events.py +113 -0
- alysis_code/agent/turn/exploration.py +590 -0
- alysis_code/agent/turn/interventions.py +65 -0
- alysis_code/agent/turn/read_cache.py +420 -0
- alysis_code/agent/turn/snapshot.py +179 -0
- alysis_code/agent/turn_contract.py +661 -0
- alysis_code/agent/turn_path.py +129 -0
- alysis_code/agent/verification.py +2885 -0
- alysis_code/agent/verification_commands.py +512 -0
- alysis_code/agent/verification_evidence.py +738 -0
- alysis_code/agent_loop.py +693 -0
- alysis_code/agent_runtimes/__init__.py +51 -0
- alysis_code/agent_runtimes/base.py +114 -0
- alysis_code/agent_runtimes/builtins.py +129 -0
- alysis_code/agent_runtimes/codex_cli.py +664 -0
- alysis_code/agent_runtimes/host.py +263 -0
- alysis_code/agent_runtimes/registry.py +64 -0
- alysis_code/agent_runtimes/service.py +150 -0
- alysis_code/agentbox_client.py +416 -0
- alysis_code/agentbox_integration.py +310 -0
- alysis_code/alysis_cloud.py +152 -0
- alysis_code/approval_scope.py +276 -0
- alysis_code/assets/README.md +33 -0
- alysis_code/assets/__init__.py +126 -0
- alysis_code/assets/asset_read_core.py +281 -0
- alysis_code/assets/budget_allocator.py +456 -0
- alysis_code/assets/comprehender.py +759 -0
- alysis_code/assets/index.py +654 -0
- alysis_code/assets/ingestion.py +275 -0
- alysis_code/assets/legacy_migration.py +413 -0
- alysis_code/assets/models.py +263 -0
- alysis_code/assets/ocr.py +239 -0
- alysis_code/assets/owl/ascii/f-000.txt +13 -0
- alysis_code/assets/owl/ascii/f-001.txt +13 -0
- alysis_code/assets/owl/ascii/f-002.txt +13 -0
- alysis_code/assets/owl/ascii/f-003.txt +13 -0
- alysis_code/assets/owl/ascii/f-004.txt +13 -0
- alysis_code/assets/owl/ascii/f-005.txt +13 -0
- alysis_code/assets/owl/ascii/f-006.txt +13 -0
- alysis_code/assets/owl/ascii/f-007.txt +13 -0
- alysis_code/assets/owl/ascii/f-008.txt +13 -0
- alysis_code/assets/owl/ascii/f-009.txt +13 -0
- alysis_code/assets/owl/ascii/f-010.txt +13 -0
- alysis_code/assets/owl/ascii/f-011.txt +13 -0
- alysis_code/assets/owl/ascii/f-012.txt +13 -0
- alysis_code/assets/owl/ascii/f-013.txt +13 -0
- alysis_code/assets/owl/ascii/f-014.txt +13 -0
- alysis_code/assets/owl/ascii/f-015.txt +13 -0
- alysis_code/assets/owl/ascii/f-016.txt +13 -0
- alysis_code/assets/owl/ascii/f-017.txt +13 -0
- alysis_code/assets/owl/ascii/f-018.txt +13 -0
- alysis_code/assets/owl/ascii/f-019.txt +13 -0
- alysis_code/assets/owl/ascii/f-020.txt +13 -0
- alysis_code/assets/owl/index.html +98 -0
- alysis_code/assets/owl/show-owl.sh +761 -0
- alysis_code/assets/paths.py +49 -0
- alysis_code/assets/plan_binding.py +326 -0
- alysis_code/assets/planner_context.py +466 -0
- alysis_code/assets/planner_tools.py +184 -0
- alysis_code/assets/prompts.py +101 -0
- alysis_code/assets/replanner_context.py +239 -0
- alysis_code/assets/surface.py +521 -0
- alysis_code/assets/untrusted_content.py +48 -0
- alysis_code/assets/usage_logger.py +94 -0
- alysis_code/assets/worker_mirror.py +428 -0
- alysis_code/assets/worker_section.py +303 -0
- alysis_code/assets/worker_tools.py +468 -0
- alysis_code/atomic_io.py +83 -0
- alysis_code/auth_diagnostics.py +272 -0
- alysis_code/background_runner.py +366 -0
- alysis_code/branding.py +270 -0
- alysis_code/budget_policy.py +390 -0
- alysis_code/build_identity.py +465 -0
- alysis_code/builtin_hooks/__init__.py +7 -0
- alysis_code/builtin_hooks/notify_done_windows.py +65 -0
- alysis_code/bwrap_etc.py +76 -0
- alysis_code/cancellation.py +41 -0
- alysis_code/capabilities.py +137 -0
- alysis_code/chatgpt_codex_static_provider.py +133 -0
- alysis_code/cli.py +51 -0
- alysis_code/cli_impl/__init__.py +1 -0
- alysis_code/cli_impl/assets_cli.py +537 -0
- alysis_code/cli_impl/assets_modal.py +412 -0
- alysis_code/cli_impl/chat/__init__.py +156 -0
- alysis_code/cli_impl/chat/commands.py +2616 -0
- alysis_code/cli_impl/chat/loop.py +4508 -0
- alysis_code/cli_impl/chat/mid_turn_policy.py +125 -0
- alysis_code/cli_impl/chat/rendering.py +444 -0
- alysis_code/cli_impl/chat/state.py +124 -0
- alysis_code/cli_impl/chat_resume.py +830 -0
- alysis_code/cli_impl/chat_slash_completer.py +258 -0
- alysis_code/cli_impl/commands/__init__.py +11 -0
- alysis_code/cli_impl/commands/_shared.py +89 -0
- alysis_code/cli_impl/commands/auth.py +623 -0
- alysis_code/cli_impl/commands/chat_resume_helpers.py +1531 -0
- alysis_code/cli_impl/commands/chat_state.py +158 -0
- alysis_code/cli_impl/commands/chat_status.py +1248 -0
- alysis_code/cli_impl/commands/chat_terminal.py +942 -0
- alysis_code/cli_impl/commands/chat_tui_panels.py +1018 -0
- alysis_code/cli_impl/commands/cli_common.py +1223 -0
- alysis_code/cli_impl/commands/cli_surface.py +77 -0
- alysis_code/cli_impl/commands/config.py +131 -0
- alysis_code/cli_impl/commands/conventions.py +85 -0
- alysis_code/cli_impl/commands/execution_helpers.py +350 -0
- alysis_code/cli_impl/commands/extensions.py +401 -0
- alysis_code/cli_impl/commands/forge.py +1282 -0
- alysis_code/cli_impl/commands/forge_asset_view.py +121 -0
- alysis_code/cli_impl/commands/forge_helpers.py +1215 -0
- alysis_code/cli_impl/commands/hooks.py +737 -0
- alysis_code/cli_impl/commands/ide_bridge.py +31 -0
- alysis_code/cli_impl/commands/mcp.py +700 -0
- alysis_code/cli_impl/commands/profile.py +453 -0
- alysis_code/cli_impl/commands/prompt_helpers.py +307 -0
- alysis_code/cli_impl/commands/report.py +88 -0
- alysis_code/cli_impl/commands/root.py +1118 -0
- alysis_code/cli_impl/commands/sandbox.py +184 -0
- alysis_code/cli_impl/commands/server.py +54 -0
- alysis_code/cli_impl/commands/sessions.py +252 -0
- alysis_code/cli_impl/commands/skills.py +404 -0
- alysis_code/cli_impl/commands/startup.py +946 -0
- alysis_code/cli_impl/commands/tools.py +335 -0
- alysis_code/cli_impl/commands/update.py +364 -0
- alysis_code/cli_impl/commands/welcome.py +972 -0
- alysis_code/cli_impl/config_menu.py +3882 -0
- alysis_code/cli_impl/forge.py +4509 -0
- alysis_code/cli_impl/forge_recovery.py +485 -0
- alysis_code/cli_impl/setup_wizard.py +2409 -0
- alysis_code/cli_impl/tui/__init__.py +58 -0
- alysis_code/cli_impl/tui/app.py +4551 -0
- alysis_code/cli_impl/tui/config.py +32 -0
- alysis_code/cli_impl/tui/config_flow.py +2754 -0
- alysis_code/cli_impl/tui/config_overlay.py +566 -0
- alysis_code/cli_impl/tui/content.py +78 -0
- alysis_code/cli_impl/tui/footer.py +218 -0
- alysis_code/cli_impl/tui/forge_status.py +136 -0
- alysis_code/cli_impl/tui/markdown.py +244 -0
- alysis_code/cli_impl/tui/owl.py +109 -0
- alysis_code/cli_impl/tui/plan_meta.py +477 -0
- alysis_code/cli_impl/tui/setup_app.py +519 -0
- alysis_code/cli_impl/tui/setup_flow.py +1622 -0
- alysis_code/cli_impl/tui/state.py +101 -0
- alysis_code/cli_impl/tui/subagent_identity.py +66 -0
- alysis_code/cli_impl/tui/subagent_panel.py +186 -0
- alysis_code/cli_impl/tui/surface.py +796 -0
- alysis_code/cli_impl/tui/transcript.py +514 -0
- alysis_code/cli_impl/tui/update_prompt.py +79 -0
- alysis_code/cli_impl/tui/workspace_guard.py +384 -0
- alysis_code/clipboard.py +172 -0
- alysis_code/code_review.py +1211 -0
- alysis_code/compaction/__init__.py +28 -0
- alysis_code/compaction/conversation_compactor.py +2932 -0
- alysis_code/compaction/importance.py +177 -0
- alysis_code/compaction/settings.py +297 -0
- alysis_code/compaction/tool_output_offload.py +447 -0
- alysis_code/config.py +3509 -0
- alysis_code/conflict_auto_resolver.py +895 -0
- alysis_code/context/__init__.py +1 -0
- alysis_code/context/tool_schema_budgeter.py +220 -0
- alysis_code/crash_diagnostics.py +282 -0
- alysis_code/custom_tools/README.md +34 -0
- alysis_code/custom_tools/__init__.py +43 -0
- alysis_code/custom_tools/discovery.py +903 -0
- alysis_code/custom_tools/runtime.py +1516 -0
- alysis_code/custom_tools/session.py +227 -0
- alysis_code/custom_tools/trust.py +232 -0
- alysis_code/diff_paths.py +113 -0
- alysis_code/direction_change.py +293 -0
- alysis_code/dispatch_timing.py +306 -0
- alysis_code/durable_service_manager.py +1236 -0
- alysis_code/edit_discipline.py +659 -0
- alysis_code/error_text.py +73 -0
- alysis_code/execution_budget.py +411 -0
- alysis_code/execution_context.py +915 -0
- alysis_code/execution_deadline.py +1065 -0
- alysis_code/execution_shared.py +1904 -0
- alysis_code/extensions/README.md +30 -0
- alysis_code/extensions/__init__.py +93 -0
- alysis_code/extensions/activation.py +138 -0
- alysis_code/extensions/install.py +1436 -0
- alysis_code/extensions/manifest.py +487 -0
- alysis_code/extensions/models.py +74 -0
- alysis_code/extensions/paths.py +56 -0
- alysis_code/extensions/registry.json +4 -0
- alysis_code/extensions/registry.py +52 -0
- alysis_code/extensions/state.py +83 -0
- alysis_code/extensions/workspace_trust.py +101 -0
- alysis_code/failed_task_evidence.py +369 -0
- alysis_code/failure_category.py +315 -0
- alysis_code/feedback_report.py +1647 -0
- alysis_code/file_classification.py +485 -0
- alysis_code/forge.py +2064 -0
- alysis_code/forge_completion.py +362 -0
- alysis_code/forge_events.py +475 -0
- alysis_code/frontmatter_utils.py +95 -0
- alysis_code/git_evidence.py +1181 -0
- alysis_code/git_ops.py +560 -0
- alysis_code/git_safe.py +62 -0
- alysis_code/git_worktrees.py +190 -0
- alysis_code/hooks/README.md +33 -0
- alysis_code/hooks/__init__.py +67 -0
- alysis_code/hooks/audit.py +171 -0
- alysis_code/hooks/config.py +225 -0
- alysis_code/hooks/dispatcher.py +1110 -0
- alysis_code/hooks/models.py +447 -0
- alysis_code/hooks/trust.py +202 -0
- alysis_code/host_actions.py +543 -0
- alysis_code/host_browser.py +103 -0
- alysis_code/ide/__init__.py +5 -0
- alysis_code/ide/activity_events.py +399 -0
- alysis_code/ide/approvals.py +337 -0
- alysis_code/ide/artifacts.py +153 -0
- alysis_code/ide/browser_egress_proxy.py +1076 -0
- alysis_code/ide/cdp_websocket_transport.py +1192 -0
- alysis_code/ide/change_ledger.py +1721 -0
- alysis_code/ide/context_blocks.py +979 -0
- alysis_code/ide/event_stream.py +531 -0
- alysis_code/ide/forge_protocol.py +3112 -0
- alysis_code/ide/forge_request_ledger.py +737 -0
- alysis_code/ide/health.py +965 -0
- alysis_code/ide/managed_browser.py +2251 -0
- alysis_code/ide/management_protocol.py +3414 -0
- alysis_code/ide/mcp_oauth_coordinator.py +744 -0
- alysis_code/ide/mcp_oauth_lifecycle.py +1504 -0
- alysis_code/ide/prompt_queue.py +1070 -0
- alysis_code/ide/protocol.py +191 -0
- alysis_code/ide/resumable_swarm.py +1543 -0
- alysis_code/ide/session_search.py +295 -0
- alysis_code/ide/stdio_bridge.py +9935 -0
- alysis_code/ide/structured_state.py +1579 -0
- alysis_code/ide/swarm_protocol.py +816 -0
- alysis_code/integration_gate.py +506 -0
- alysis_code/interactive_input_guard.py +39 -0
- alysis_code/interactive_plan_mode.py +26 -0
- alysis_code/internal_artifacts.py +179 -0
- alysis_code/knowledge_base.py +1409 -0
- alysis_code/knowledge_capture.py +1190 -0
- alysis_code/knowledge_librarian.py +605 -0
- alysis_code/language_policy.py +34 -0
- alysis_code/litellm_static_provider.py +535 -0
- alysis_code/llm/__init__.py +1 -0
- alysis_code/llm/anthropic_messages.py +2288 -0
- alysis_code/llm/base.py +71 -0
- alysis_code/llm/cache_capabilities.py +985 -0
- alysis_code/llm/cache_control_blocks.py +244 -0
- alysis_code/llm/cache_policy.py +388 -0
- alysis_code/llm/factory.py +373 -0
- alysis_code/llm/gemini_generate_content.py +2652 -0
- alysis_code/llm/gemini_interactions.py +739 -0
- alysis_code/llm/metadata.py +450 -0
- alysis_code/llm/openai_compat.py +2947 -0
- alysis_code/llm/openai_responses.py +2604 -0
- alysis_code/llm/protocols.py +609 -0
- alysis_code/llm/provider_limits.py +525 -0
- alysis_code/llm/request_plan.py +389 -0
- alysis_code/llm/request_shape.py +238 -0
- alysis_code/llm/streaming.py +108 -0
- alysis_code/llm/temperature_compat.py +78 -0
- alysis_code/llm/types.py +195 -0
- alysis_code/llm/usage_normalization.py +222 -0
- alysis_code/llm_error_display.py +315 -0
- alysis_code/logging_redaction.py +326 -0
- alysis_code/managed_host_deadline.py +196 -0
- alysis_code/mcp/README.md +33 -0
- alysis_code/mcp/__init__.py +24 -0
- alysis_code/mcp/client.py +1137 -0
- alysis_code/mcp/config.py +597 -0
- alysis_code/mcp/errors.py +113 -0
- alysis_code/mcp/forge_scope.py +154 -0
- alysis_code/mcp/jsonrpc.py +214 -0
- alysis_code/mcp/manager.py +2308 -0
- alysis_code/mcp/models.py +666 -0
- alysis_code/mcp/oauth.py +972 -0
- alysis_code/mcp/oauth_runtime.py +310 -0
- alysis_code/mcp/oauth_store.py +276 -0
- alysis_code/mcp/prompts.py +329 -0
- alysis_code/mcp/resources.py +295 -0
- alysis_code/mcp/roots.py +106 -0
- alysis_code/mcp/server_requests.py +75 -0
- alysis_code/mcp/token_store.py +859 -0
- alysis_code/mcp/transport_http.py +1338 -0
- alysis_code/mcp/transport_stdio.py +1267 -0
- alysis_code/mcp/untrusted_content.py +119 -0
- alysis_code/merge_conflict_reviewer.py +729 -0
- alysis_code/model_catalog/__init__.py +1 -0
- alysis_code/model_catalog/chatgpt_codex_subscription_snapshot.json +186 -0
- alysis_code/model_catalog/litellm_model_prices_snapshot.json +44715 -0
- alysis_code/model_catalog/litellm_model_prices_snapshot.meta.json +17 -0
- alysis_code/model_metadata_policy.py +223 -0
- alysis_code/model_metadata_utils.py +103 -0
- alysis_code/model_registry.py +1420 -0
- alysis_code/model_router.py +147 -0
- alysis_code/permission_policy.py +1016 -0
- alysis_code/personas.py +451 -0
- alysis_code/pipeline_facts.py +233 -0
- alysis_code/plan_assistant.py +4763 -0
- alysis_code/plan_mode.py +393 -0
- alysis_code/plan_reconciliation.py +1228 -0
- alysis_code/plan_repair.py +652 -0
- alysis_code/plan_validation.py +1099 -0
- alysis_code/planning_constraints.py +904 -0
- alysis_code/policy.py +95 -0
- alysis_code/preview_server.py +457 -0
- alysis_code/process_reaping.py +566 -0
- alysis_code/profile_presets.py +1834 -0
- alysis_code/profiles.py +666 -0
- alysis_code/provider_auth/__init__.py +29 -0
- alysis_code/provider_auth/base.py +99 -0
- alysis_code/provider_auth/openai_codex.py +951 -0
- alysis_code/provider_auth/registry.py +76 -0
- alysis_code/provider_auth/store.py +125 -0
- alysis_code/provider_diagnostics.py +1209 -0
- alysis_code/provider_model_catalog.py +685 -0
- alysis_code/provider_telemetry.py +1699 -0
- alysis_code/provider_url.py +75 -0
- alysis_code/reasoning_contracts.py +911 -0
- alysis_code/remote_sync.py +350 -0
- alysis_code/replanning.py +1195 -0
- alysis_code/repo_scan.py +1152 -0
- alysis_code/request_estimation.py +296 -0
- alysis_code/review_gate.py +617 -0
- alysis_code/run_lock.py +1141 -0
- alysis_code/run_outcome.py +58 -0
- alysis_code/run_provenance.py +774 -0
- alysis_code/run_state.py +445 -0
- alysis_code/runtime_artifacts.py +116 -0
- alysis_code/runtime_context_features.py +78 -0
- alysis_code/runtime_kind.py +52 -0
- alysis_code/safety/__init__.py +11 -0
- alysis_code/safety/mcp_sanitize.py +29 -0
- alysis_code/safety/safe_http.py +297 -0
- alysis_code/safety/subagent_report.py +184 -0
- alysis_code/sandbox_doctor.py +682 -0
- alysis_code/sandbox_runner.py +1025 -0
- alysis_code/sandbox_settings.py +423 -0
- alysis_code/serialized_paths.py +355 -0
- alysis_code/server/__init__.py +3 -0
- alysis_code/server/app.py +367 -0
- alysis_code/server/auth.py +34 -0
- alysis_code/server/job_config.py +30 -0
- alysis_code/server/settings.py +215 -0
- alysis_code/server/store.py +193 -0
- alysis_code/server/worker_runner.py +657 -0
- alysis_code/service_persistence.py +355 -0
- alysis_code/session_artifacts.py +108 -0
- alysis_code/session_metrics.py +331 -0
- alysis_code/session_store.py +624 -0
- alysis_code/skills/README.md +34 -0
- alysis_code/skills/__init__.py +104 -0
- alysis_code/skills/conventions.py +84 -0
- alysis_code/skills/discovery.py +176 -0
- alysis_code/skills/eval_models.py +232 -0
- alysis_code/skills/eval_runner.py +372 -0
- alysis_code/skills/evals.py +1344 -0
- alysis_code/skills/install.py +293 -0
- alysis_code/skills/loader.py +118 -0
- alysis_code/skills/matching.py +103 -0
- alysis_code/skills/models.py +71 -0
- alysis_code/skills/paths.py +56 -0
- alysis_code/skills/prompting.py +500 -0
- alysis_code/skills/scaffold.py +142 -0
- alysis_code/skills/state.py +441 -0
- alysis_code/skills/transactions.py +125 -0
- alysis_code/skills/validation.py +304 -0
- alysis_code/step_budget.py +238 -0
- alysis_code/subagent_labels.py +49 -0
- alysis_code/subagents.py +1072 -0
- alysis_code/surface/__init__.py +80 -0
- alysis_code/surface/base.py +305 -0
- alysis_code/surface/console.py +387 -0
- alysis_code/surface/events.py +372 -0
- alysis_code/surface/hidden_surface.py +529 -0
- alysis_code/surface/noop_surface.py +219 -0
- alysis_code/surface/rich_surface.py +1555 -0
- alysis_code/surface/styles.py +67 -0
- alysis_code/surface/theme.py +455 -0
- alysis_code/surface/types.py +100 -0
- alysis_code/swarm_backend.py +926 -0
- alysis_code/swarm_orchestrator.py +4020 -0
- alysis_code/swarm_scheduler.py +441 -0
- alysis_code/swarm_trace.py +429 -0
- alysis_code/swarm_worker.py +2119 -0
- alysis_code/swarm_write_guard.py +348 -0
- alysis_code/task_dependencies.py +170 -0
- alysis_code/task_readiness.py +992 -0
- alysis_code/task_scope.py +2148 -0
- alysis_code/terminal_manager.py +762 -0
- alysis_code/terminal_ownership.py +460 -0
- alysis_code/text_normalization.py +30 -0
- alysis_code/token_budget.py +97 -0
- alysis_code/tools/README.md +34 -0
- alysis_code/tools/__init__.py +1 -0
- alysis_code/tools/artifacts.py +127 -0
- alysis_code/tools/availability.py +188 -0
- alysis_code/tools/fs.py +1456 -0
- alysis_code/tools/git.py +461 -0
- alysis_code/tools/history.py +229 -0
- alysis_code/tools/http_timeout.py +78 -0
- alysis_code/tools/image_generation.py +552 -0
- alysis_code/tools/registry.py +2936 -0
- alysis_code/tools/repo_map.py +476 -0
- alysis_code/tools/search.py +563 -0
- alysis_code/tools/shell.py +135 -0
- alysis_code/tools/symbols.py +1350 -0
- alysis_code/tools/test_discovery.py +643 -0
- alysis_code/tools/web.py +482 -0
- alysis_code/tools/web_search.py +2012 -0
- alysis_code/tools/web_search_dashscope.py +557 -0
- alysis_code/tools/web_search_ddgs.py +221 -0
- alysis_code/tools/web_search_provider_adapters.py +1429 -0
- alysis_code/tools/web_search_tavily.py +194 -0
- alysis_code/updates.py +933 -0
- alysis_code/usage_tracker.py +1990 -0
- alysis_code/verification_command_analysis.py +1004 -0
- alysis_code/verification_contract.py +574 -0
- alysis_code/verification_failure_summary.py +273 -0
- alysis_code/verification_repair.py +385 -0
- alysis_code/verify_gate.py +3129 -0
- alysis_code/web_research.py +1872 -0
- alysis_code/web_search_adapters.py +66 -0
- alysis_code/web_search_policy.py +27 -0
- alysis_code/workspace_binding.py +389 -0
- alysis_code/workspace_binding_ui.py +408 -0
- alysis_code/workspace_context.py +273 -0
- alysis_code/workspace_isolation.py +138 -0
- alysis_code/workspace_provisioning.py +455 -0
- alysis_code-0.13.0.dist-info/METADATA +507 -0
- alysis_code-0.13.0.dist-info/RECORD +458 -0
- alysis_code-0.13.0.dist-info/WHEEL +4 -0
- alysis_code-0.13.0.dist-info/entry_points.txt +3 -0
- alysis_code-0.13.0.dist-info/licenses/LICENSE +176 -0
- alysis_code-0.13.0.dist-info/licenses/NOTICE +4 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from functools import lru_cache
|
|
8
|
+
from importlib import resources
|
|
9
|
+
from typing import Any
|
|
10
|
+
from urllib.parse import urlparse
|
|
11
|
+
|
|
12
|
+
from .model_metadata_utils import (
|
|
13
|
+
model_name_variants,
|
|
14
|
+
normalize_base_url,
|
|
15
|
+
parse_bool,
|
|
16
|
+
parse_non_negative_float,
|
|
17
|
+
parse_positive_int,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
_PROVIDER_TOKEN_RE = re.compile(r"[a-z0-9]+")
|
|
21
|
+
_GENERIC_PROVIDER_TOKENS = {
|
|
22
|
+
"api",
|
|
23
|
+
"apis",
|
|
24
|
+
"ai",
|
|
25
|
+
"app",
|
|
26
|
+
"coding",
|
|
27
|
+
"compat",
|
|
28
|
+
"compatible",
|
|
29
|
+
"com",
|
|
30
|
+
"cn",
|
|
31
|
+
"http",
|
|
32
|
+
"https",
|
|
33
|
+
"intl",
|
|
34
|
+
"net",
|
|
35
|
+
"org",
|
|
36
|
+
"paas",
|
|
37
|
+
"v1",
|
|
38
|
+
"v2",
|
|
39
|
+
"v3",
|
|
40
|
+
"v4",
|
|
41
|
+
"www",
|
|
42
|
+
}
|
|
43
|
+
_BUNDLED_CATALOG_PACKAGE = "alysis_code.model_catalog"
|
|
44
|
+
_BUNDLED_CATALOG_FILENAME = "litellm_model_prices_snapshot.json"
|
|
45
|
+
_BUNDLED_CATALOG_META_FILENAME = "litellm_model_prices_snapshot.meta.json"
|
|
46
|
+
BUNDLED_MODEL_CATALOG_SOURCE = "bundled_litellm_snapshot"
|
|
47
|
+
_BUNDLED_MODEL_CATALOG_REFRESH_POLICY = "manual_reviewed_only"
|
|
48
|
+
_NON_MODEL_TOP_LEVEL_KEYS = {"sample_spec"}
|
|
49
|
+
_FULL_SHA_RE = re.compile(r"^[0-9a-f]{40}$")
|
|
50
|
+
_FULL_SHA256_RE = re.compile(r"^[0-9a-f]{64}$")
|
|
51
|
+
_STRICT_UTC_TIMESTAMP_RE = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(frozen=True)
|
|
55
|
+
class LiteLLMStaticMetadata:
|
|
56
|
+
model_key: str | None
|
|
57
|
+
context_window_tokens: int | None
|
|
58
|
+
max_output_tokens: int | None
|
|
59
|
+
supports_vision: bool | None
|
|
60
|
+
input_cost_per_token: float | None
|
|
61
|
+
output_cost_per_token: float | None
|
|
62
|
+
raw_metadata: dict[str, Any]
|
|
63
|
+
error: str | None
|
|
64
|
+
cache_read_input_cost_per_token: float | None = None
|
|
65
|
+
cache_creation_input_cost_per_token: float | None = None
|
|
66
|
+
cache_creation_5m_input_cost_per_token: float | None = None
|
|
67
|
+
cache_creation_1h_input_cost_per_token: float | None = None
|
|
68
|
+
reasoning_output_cost_per_token: float | None = None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class BundledModelCatalogProvenance:
|
|
73
|
+
schema_version: int | None
|
|
74
|
+
source: str | None
|
|
75
|
+
refresh_policy: str | None
|
|
76
|
+
fetched_at_utc: str | None
|
|
77
|
+
upstream_commit_sha: str | None
|
|
78
|
+
upstream_blob_url: str | None
|
|
79
|
+
bundled_json_sha256: str | None
|
|
80
|
+
bundled_json_size_bytes: int | None
|
|
81
|
+
top_level_entry_count: int | None
|
|
82
|
+
raw_metadata: dict[str, Any]
|
|
83
|
+
error: str | None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _empty_metadata(error: str) -> LiteLLMStaticMetadata:
|
|
87
|
+
return LiteLLMStaticMetadata(
|
|
88
|
+
model_key=None,
|
|
89
|
+
context_window_tokens=None,
|
|
90
|
+
max_output_tokens=None,
|
|
91
|
+
supports_vision=None,
|
|
92
|
+
input_cost_per_token=None,
|
|
93
|
+
output_cost_per_token=None,
|
|
94
|
+
cache_read_input_cost_per_token=None,
|
|
95
|
+
cache_creation_input_cost_per_token=None,
|
|
96
|
+
cache_creation_5m_input_cost_per_token=None,
|
|
97
|
+
cache_creation_1h_input_cost_per_token=None,
|
|
98
|
+
reasoning_output_cost_per_token=None,
|
|
99
|
+
raw_metadata={},
|
|
100
|
+
error=error,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _empty_provenance(error: str) -> BundledModelCatalogProvenance:
|
|
105
|
+
return BundledModelCatalogProvenance(
|
|
106
|
+
schema_version=None,
|
|
107
|
+
source=None,
|
|
108
|
+
refresh_policy=None,
|
|
109
|
+
fetched_at_utc=None,
|
|
110
|
+
upstream_commit_sha=None,
|
|
111
|
+
upstream_blob_url=None,
|
|
112
|
+
bundled_json_sha256=None,
|
|
113
|
+
bundled_json_size_bytes=None,
|
|
114
|
+
top_level_entry_count=None,
|
|
115
|
+
raw_metadata={},
|
|
116
|
+
error=error,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _provider_tokens(*values: str) -> set[str]:
|
|
121
|
+
tokens: set[str] = set()
|
|
122
|
+
for value in values:
|
|
123
|
+
for token in _PROVIDER_TOKEN_RE.findall(value.casefold()):
|
|
124
|
+
if token in _GENERIC_PROVIDER_TOKENS:
|
|
125
|
+
continue
|
|
126
|
+
tokens.add(token)
|
|
127
|
+
return tokens
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _preferred_provider_tokens(
|
|
131
|
+
base_url: str | None,
|
|
132
|
+
provider_hint: str | None,
|
|
133
|
+
) -> set[str]:
|
|
134
|
+
values: list[str] = []
|
|
135
|
+
normalized = normalize_base_url(base_url) if base_url is not None else ""
|
|
136
|
+
if normalized:
|
|
137
|
+
try:
|
|
138
|
+
hostname = urlparse(normalized).hostname
|
|
139
|
+
except ValueError:
|
|
140
|
+
hostname = None
|
|
141
|
+
values.append(hostname or normalized)
|
|
142
|
+
if str(provider_hint or "").strip():
|
|
143
|
+
values.append(str(provider_hint))
|
|
144
|
+
return _provider_tokens(*values)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _catalog_route_token_sets(
|
|
148
|
+
*,
|
|
149
|
+
key: str,
|
|
150
|
+
raw_metadata: dict[str, Any],
|
|
151
|
+
) -> tuple[set[str], set[str]]:
|
|
152
|
+
"""Return route/provider identity without treating the model family as a route.
|
|
153
|
+
|
|
154
|
+
A model name such as ``sambanova/MiniMax-M2.7`` contains both a route and a
|
|
155
|
+
model family. Matching the whole key makes a MiniMax endpoint look compatible
|
|
156
|
+
with SambaNova merely because the model suffix contains ``MiniMax``. Only the
|
|
157
|
+
catalog provider and the first route namespace participate in route matching;
|
|
158
|
+
nested model-family namespaces do not.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
key_route = key.split("/", 1)[0] if "/" in key else ""
|
|
162
|
+
return (
|
|
163
|
+
_provider_tokens(key_route),
|
|
164
|
+
_provider_tokens(str(raw_metadata.get("litellm_provider") or "")),
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _is_model_catalog_entry(key: Any, value: Any) -> bool:
|
|
169
|
+
if not isinstance(key, str) or not isinstance(value, dict):
|
|
170
|
+
return False
|
|
171
|
+
return key.casefold() not in _NON_MODEL_TOP_LEVEL_KEYS
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _candidate_rank(
|
|
175
|
+
*,
|
|
176
|
+
key: str,
|
|
177
|
+
raw_metadata: dict[str, Any],
|
|
178
|
+
direct_match: bool,
|
|
179
|
+
preferred_provider_tokens: set[str],
|
|
180
|
+
) -> tuple[int, int, int, int, int]:
|
|
181
|
+
key_route_tokens, metadata_provider_tokens = _catalog_route_token_sets(
|
|
182
|
+
key=key,
|
|
183
|
+
raw_metadata=raw_metadata,
|
|
184
|
+
)
|
|
185
|
+
key_route_score = len(key_route_tokens & preferred_provider_tokens)
|
|
186
|
+
metadata_provider_score = len(metadata_provider_tokens & preferred_provider_tokens)
|
|
187
|
+
return (
|
|
188
|
+
key_route_score,
|
|
189
|
+
metadata_provider_score,
|
|
190
|
+
1 if direct_match else 0,
|
|
191
|
+
-key.count("/"),
|
|
192
|
+
-len(key),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _lookup_model_info(
|
|
197
|
+
model_cost: dict[str, Any],
|
|
198
|
+
requested_model: str,
|
|
199
|
+
*,
|
|
200
|
+
base_url: str | None = None,
|
|
201
|
+
provider_hint: str | None = None,
|
|
202
|
+
) -> tuple[str, dict[str, Any]] | None:
|
|
203
|
+
lower_index: dict[str, list[str]] = {}
|
|
204
|
+
alias_index: dict[str, list[str]] = {}
|
|
205
|
+
for key, value in model_cost.items():
|
|
206
|
+
if not _is_model_catalog_entry(key, value):
|
|
207
|
+
continue
|
|
208
|
+
lower_index.setdefault(key.casefold(), []).append(key)
|
|
209
|
+
for alias in model_name_variants(key):
|
|
210
|
+
alias_index.setdefault(alias.casefold(), []).append(key)
|
|
211
|
+
|
|
212
|
+
preferred_provider_tokens = _preferred_provider_tokens(base_url, provider_hint)
|
|
213
|
+
candidates: list[tuple[tuple[int, int, int, int, int], str, dict[str, Any]]] = []
|
|
214
|
+
seen: set[str] = set()
|
|
215
|
+
for variant in model_name_variants(requested_model):
|
|
216
|
+
direct = model_cost.get(variant)
|
|
217
|
+
if _is_model_catalog_entry(variant, direct):
|
|
218
|
+
seen.add(variant)
|
|
219
|
+
candidates.append(
|
|
220
|
+
(
|
|
221
|
+
_candidate_rank(
|
|
222
|
+
key=variant,
|
|
223
|
+
raw_metadata=direct,
|
|
224
|
+
direct_match=True,
|
|
225
|
+
preferred_provider_tokens=preferred_provider_tokens,
|
|
226
|
+
),
|
|
227
|
+
variant,
|
|
228
|
+
direct,
|
|
229
|
+
)
|
|
230
|
+
)
|
|
231
|
+
for key in alias_index.get(variant.casefold(), []):
|
|
232
|
+
if key in seen:
|
|
233
|
+
continue
|
|
234
|
+
aliased = model_cost.get(key)
|
|
235
|
+
if not isinstance(aliased, dict):
|
|
236
|
+
continue
|
|
237
|
+
seen.add(key)
|
|
238
|
+
candidates.append(
|
|
239
|
+
(
|
|
240
|
+
_candidate_rank(
|
|
241
|
+
key=key,
|
|
242
|
+
raw_metadata=aliased,
|
|
243
|
+
direct_match=False,
|
|
244
|
+
preferred_provider_tokens=preferred_provider_tokens,
|
|
245
|
+
),
|
|
246
|
+
key,
|
|
247
|
+
aliased,
|
|
248
|
+
)
|
|
249
|
+
)
|
|
250
|
+
for key in lower_index.get(variant.casefold(), []):
|
|
251
|
+
if key in seen:
|
|
252
|
+
continue
|
|
253
|
+
aliased = model_cost.get(key)
|
|
254
|
+
if not isinstance(aliased, dict):
|
|
255
|
+
continue
|
|
256
|
+
seen.add(key)
|
|
257
|
+
candidates.append(
|
|
258
|
+
(
|
|
259
|
+
_candidate_rank(
|
|
260
|
+
key=key,
|
|
261
|
+
raw_metadata=aliased,
|
|
262
|
+
direct_match=False,
|
|
263
|
+
preferred_provider_tokens=preferred_provider_tokens,
|
|
264
|
+
),
|
|
265
|
+
key,
|
|
266
|
+
aliased,
|
|
267
|
+
)
|
|
268
|
+
)
|
|
269
|
+
if candidates:
|
|
270
|
+
# A known preset route must never silently borrow limits or prices from
|
|
271
|
+
# another host that happens to expose the same model name. Custom routes
|
|
272
|
+
# keep the historical best-effort behavior because no route identity is
|
|
273
|
+
# available unless the user configures one.
|
|
274
|
+
if str(provider_hint or "").strip():
|
|
275
|
+
candidates = [
|
|
276
|
+
candidate for candidate in candidates if candidate[0][0] > 0 or candidate[0][1] > 0
|
|
277
|
+
]
|
|
278
|
+
if not candidates:
|
|
279
|
+
return None
|
|
280
|
+
_rank, key, metadata = max(candidates, key=lambda item: item[0])
|
|
281
|
+
return key, metadata
|
|
282
|
+
return None
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def _resolve_capacity_metadata(
|
|
286
|
+
raw_metadata: dict[str, Any],
|
|
287
|
+
) -> tuple[int | None, int | None]:
|
|
288
|
+
raw_total = parse_positive_int(raw_metadata.get("max_tokens"))
|
|
289
|
+
raw_input = parse_positive_int(raw_metadata.get("max_input_tokens"))
|
|
290
|
+
raw_output = parse_positive_int(raw_metadata.get("max_output_tokens"))
|
|
291
|
+
|
|
292
|
+
if raw_input is not None and raw_output is not None:
|
|
293
|
+
return raw_input + raw_output, raw_output
|
|
294
|
+
|
|
295
|
+
if raw_input is not None and raw_total is not None:
|
|
296
|
+
if raw_total > raw_input:
|
|
297
|
+
return raw_total, raw_total - raw_input
|
|
298
|
+
return raw_input + raw_total, raw_total
|
|
299
|
+
|
|
300
|
+
if raw_total is not None:
|
|
301
|
+
return raw_total, raw_output
|
|
302
|
+
|
|
303
|
+
if raw_input is not None:
|
|
304
|
+
return raw_input, raw_output
|
|
305
|
+
|
|
306
|
+
return None, raw_output
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _first_non_negative_float(raw_metadata: dict[str, Any], *keys: str) -> float | None:
|
|
310
|
+
for key in keys:
|
|
311
|
+
value = parse_non_negative_float(raw_metadata.get(key))
|
|
312
|
+
if value is not None:
|
|
313
|
+
return value
|
|
314
|
+
return None
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _parse_full_hex_digest(value: Any, *, digits: int) -> str | None:
|
|
318
|
+
if not isinstance(value, str):
|
|
319
|
+
return None
|
|
320
|
+
clean = value.strip().lower()
|
|
321
|
+
matcher = _FULL_SHA_RE if digits == 40 else _FULL_SHA256_RE
|
|
322
|
+
if not matcher.fullmatch(clean):
|
|
323
|
+
return None
|
|
324
|
+
return clean
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _parse_strict_utc_timestamp(value: Any) -> str | None:
|
|
328
|
+
if not isinstance(value, str):
|
|
329
|
+
return None
|
|
330
|
+
clean = value.strip()
|
|
331
|
+
if not _STRICT_UTC_TIMESTAMP_RE.fullmatch(clean):
|
|
332
|
+
return None
|
|
333
|
+
try:
|
|
334
|
+
datetime.strptime(clean, "%Y-%m-%dT%H:%M:%SZ")
|
|
335
|
+
except ValueError:
|
|
336
|
+
return None
|
|
337
|
+
return clean
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
@lru_cache(maxsize=1)
|
|
341
|
+
def _load_bundled_model_catalog() -> dict[str, Any]:
|
|
342
|
+
try:
|
|
343
|
+
text = (
|
|
344
|
+
resources.files(_BUNDLED_CATALOG_PACKAGE)
|
|
345
|
+
.joinpath(_BUNDLED_CATALOG_FILENAME)
|
|
346
|
+
.read_text(encoding="utf-8")
|
|
347
|
+
)
|
|
348
|
+
except (FileNotFoundError, ModuleNotFoundError) as e:
|
|
349
|
+
raise FileNotFoundError(_BUNDLED_CATALOG_FILENAME) from e
|
|
350
|
+
except (OSError, UnicodeDecodeError) as e:
|
|
351
|
+
raise ValueError("bundled model catalog invalid") from e
|
|
352
|
+
|
|
353
|
+
try:
|
|
354
|
+
raw = json.loads(text)
|
|
355
|
+
except json.JSONDecodeError as e:
|
|
356
|
+
raise ValueError("bundled model catalog invalid") from e
|
|
357
|
+
|
|
358
|
+
if not isinstance(raw, dict):
|
|
359
|
+
raise ValueError("bundled model catalog invalid")
|
|
360
|
+
return raw
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@lru_cache(maxsize=1)
|
|
364
|
+
def _load_bundled_model_catalog_meta() -> dict[str, Any]:
|
|
365
|
+
try:
|
|
366
|
+
text = (
|
|
367
|
+
resources.files(_BUNDLED_CATALOG_PACKAGE)
|
|
368
|
+
.joinpath(_BUNDLED_CATALOG_META_FILENAME)
|
|
369
|
+
.read_text(encoding="utf-8")
|
|
370
|
+
)
|
|
371
|
+
except (FileNotFoundError, ModuleNotFoundError) as e:
|
|
372
|
+
raise FileNotFoundError(_BUNDLED_CATALOG_META_FILENAME) from e
|
|
373
|
+
except (OSError, UnicodeDecodeError) as e:
|
|
374
|
+
raise ValueError("bundled model catalog provenance invalid") from e
|
|
375
|
+
|
|
376
|
+
try:
|
|
377
|
+
raw = json.loads(text)
|
|
378
|
+
except json.JSONDecodeError as e:
|
|
379
|
+
raise ValueError("bundled model catalog provenance invalid") from e
|
|
380
|
+
|
|
381
|
+
if not isinstance(raw, dict):
|
|
382
|
+
raise ValueError("bundled model catalog provenance invalid")
|
|
383
|
+
return raw
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def get_bundled_model_catalog_provenance() -> BundledModelCatalogProvenance:
|
|
387
|
+
try:
|
|
388
|
+
raw = _load_bundled_model_catalog_meta()
|
|
389
|
+
except FileNotFoundError:
|
|
390
|
+
return _empty_provenance("bundled model catalog provenance missing")
|
|
391
|
+
except ValueError:
|
|
392
|
+
return _empty_provenance("bundled model catalog provenance invalid")
|
|
393
|
+
|
|
394
|
+
schema_version = parse_positive_int(raw.get("schema_version"))
|
|
395
|
+
source = raw.get("source") if isinstance(raw.get("source"), str) else None
|
|
396
|
+
refresh_policy = (
|
|
397
|
+
raw.get("refresh_policy") if isinstance(raw.get("refresh_policy"), str) else None
|
|
398
|
+
)
|
|
399
|
+
upstream = raw.get("upstream")
|
|
400
|
+
snapshot = raw.get("snapshot")
|
|
401
|
+
if (
|
|
402
|
+
schema_version != 1
|
|
403
|
+
or source != BUNDLED_MODEL_CATALOG_SOURCE
|
|
404
|
+
or refresh_policy != _BUNDLED_MODEL_CATALOG_REFRESH_POLICY
|
|
405
|
+
or not isinstance(upstream, dict)
|
|
406
|
+
or not isinstance(snapshot, dict)
|
|
407
|
+
):
|
|
408
|
+
return _empty_provenance("bundled model catalog provenance invalid")
|
|
409
|
+
|
|
410
|
+
upstream_commit_sha = _parse_full_hex_digest(upstream.get("commit_sha"), digits=40)
|
|
411
|
+
upstream_repo = upstream.get("repo") if isinstance(upstream.get("repo"), str) else None
|
|
412
|
+
upstream_path = upstream.get("path") if isinstance(upstream.get("path"), str) else None
|
|
413
|
+
upstream_blob_url = (
|
|
414
|
+
upstream.get("blob_url") if isinstance(upstream.get("blob_url"), str) else None
|
|
415
|
+
)
|
|
416
|
+
fetched_at_utc = _parse_strict_utc_timestamp(snapshot.get("fetched_at_utc"))
|
|
417
|
+
bundled_json_sha256 = _parse_full_hex_digest(snapshot.get("bundled_json_sha256"), digits=64)
|
|
418
|
+
bundled_json_size_bytes = parse_positive_int(snapshot.get("bundled_json_size_bytes"))
|
|
419
|
+
top_level_entry_count = parse_positive_int(snapshot.get("top_level_entry_count"))
|
|
420
|
+
if (
|
|
421
|
+
upstream_commit_sha is None
|
|
422
|
+
or upstream_repo is None
|
|
423
|
+
or upstream_path is None
|
|
424
|
+
or fetched_at_utc is None
|
|
425
|
+
or bundled_json_sha256 is None
|
|
426
|
+
or bundled_json_size_bytes is None
|
|
427
|
+
or top_level_entry_count is None
|
|
428
|
+
):
|
|
429
|
+
return _empty_provenance("bundled model catalog provenance invalid")
|
|
430
|
+
|
|
431
|
+
return BundledModelCatalogProvenance(
|
|
432
|
+
schema_version=schema_version,
|
|
433
|
+
source=source,
|
|
434
|
+
refresh_policy=refresh_policy,
|
|
435
|
+
fetched_at_utc=fetched_at_utc,
|
|
436
|
+
upstream_commit_sha=upstream_commit_sha,
|
|
437
|
+
upstream_blob_url=upstream_blob_url,
|
|
438
|
+
bundled_json_sha256=bundled_json_sha256,
|
|
439
|
+
bundled_json_size_bytes=bundled_json_size_bytes,
|
|
440
|
+
top_level_entry_count=top_level_entry_count,
|
|
441
|
+
raw_metadata=dict(raw),
|
|
442
|
+
error=None,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def resolve_litellm_static_metadata(
|
|
447
|
+
model_name: str,
|
|
448
|
+
*,
|
|
449
|
+
base_url: str | None = None,
|
|
450
|
+
provider_hint: str | None = None,
|
|
451
|
+
) -> LiteLLMStaticMetadata:
|
|
452
|
+
try:
|
|
453
|
+
model_cost = _load_bundled_model_catalog()
|
|
454
|
+
except FileNotFoundError:
|
|
455
|
+
return _empty_metadata("bundled model catalog missing")
|
|
456
|
+
except ValueError:
|
|
457
|
+
return _empty_metadata("bundled model catalog invalid")
|
|
458
|
+
|
|
459
|
+
match = _lookup_model_info(
|
|
460
|
+
model_cost,
|
|
461
|
+
model_name,
|
|
462
|
+
base_url=base_url,
|
|
463
|
+
provider_hint=provider_hint,
|
|
464
|
+
)
|
|
465
|
+
if match is None:
|
|
466
|
+
return _empty_metadata("model not found in bundled model catalog")
|
|
467
|
+
|
|
468
|
+
model_key, raw_metadata = match
|
|
469
|
+
context_window_tokens, max_output_tokens = _resolve_capacity_metadata(raw_metadata)
|
|
470
|
+
supports_vision = parse_bool(raw_metadata.get("supports_vision"))
|
|
471
|
+
input_cost_per_token = parse_non_negative_float(raw_metadata.get("input_cost_per_token"))
|
|
472
|
+
output_cost_per_token = parse_non_negative_float(raw_metadata.get("output_cost_per_token"))
|
|
473
|
+
cache_read_input_cost_per_token = _first_non_negative_float(
|
|
474
|
+
raw_metadata,
|
|
475
|
+
"cache_read_input_cost_per_token",
|
|
476
|
+
"cache_read_input_token_cost",
|
|
477
|
+
"input_cache_read_cost_per_token",
|
|
478
|
+
"input_cached_read_cost_per_token",
|
|
479
|
+
"cache_read_cost_per_token",
|
|
480
|
+
)
|
|
481
|
+
cache_creation_input_cost_per_token = _first_non_negative_float(
|
|
482
|
+
raw_metadata,
|
|
483
|
+
"cache_creation_input_cost_per_token",
|
|
484
|
+
"cache_creation_input_token_cost",
|
|
485
|
+
"cache_write_input_cost_per_token",
|
|
486
|
+
"cache_write_input_token_cost",
|
|
487
|
+
"input_cache_write_cost_per_token",
|
|
488
|
+
"input_cache_creation_cost_per_token",
|
|
489
|
+
)
|
|
490
|
+
cache_creation_5m_input_cost_per_token = _first_non_negative_float(
|
|
491
|
+
raw_metadata,
|
|
492
|
+
"cache_creation_5m_input_cost_per_token",
|
|
493
|
+
"cache_creation_5m_input_token_cost",
|
|
494
|
+
"cache_creation_input_cost_per_token_5m",
|
|
495
|
+
"cache_creation_input_token_cost_5m",
|
|
496
|
+
"input_cache_write_5m_cost_per_token",
|
|
497
|
+
)
|
|
498
|
+
cache_creation_1h_input_cost_per_token = _first_non_negative_float(
|
|
499
|
+
raw_metadata,
|
|
500
|
+
"cache_creation_input_token_cost_above_1hr",
|
|
501
|
+
"cache_creation_1h_input_cost_per_token",
|
|
502
|
+
"cache_creation_1h_input_token_cost",
|
|
503
|
+
"cache_creation_input_cost_per_token_1h",
|
|
504
|
+
"cache_creation_input_token_cost_1h",
|
|
505
|
+
"input_cache_write_1h_cost_per_token",
|
|
506
|
+
)
|
|
507
|
+
reasoning_output_cost_per_token = _first_non_negative_float(
|
|
508
|
+
raw_metadata,
|
|
509
|
+
"output_cost_per_reasoning_token",
|
|
510
|
+
"reasoning_output_cost_per_token",
|
|
511
|
+
"output_reasoning_cost_per_token",
|
|
512
|
+
"reasoning_token_cost_per_token",
|
|
513
|
+
"reasoning_cost_per_token",
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
metadata_with_provenance = dict(raw_metadata)
|
|
517
|
+
metadata_with_provenance["catalog_model_key"] = model_key
|
|
518
|
+
if str(provider_hint or "").strip():
|
|
519
|
+
metadata_with_provenance["catalog_provider_hint"] = str(provider_hint).strip()
|
|
520
|
+
|
|
521
|
+
return LiteLLMStaticMetadata(
|
|
522
|
+
model_key=model_key,
|
|
523
|
+
context_window_tokens=context_window_tokens,
|
|
524
|
+
max_output_tokens=max_output_tokens,
|
|
525
|
+
supports_vision=supports_vision,
|
|
526
|
+
input_cost_per_token=input_cost_per_token,
|
|
527
|
+
output_cost_per_token=output_cost_per_token,
|
|
528
|
+
cache_read_input_cost_per_token=cache_read_input_cost_per_token,
|
|
529
|
+
cache_creation_input_cost_per_token=cache_creation_input_cost_per_token,
|
|
530
|
+
cache_creation_5m_input_cost_per_token=cache_creation_5m_input_cost_per_token,
|
|
531
|
+
cache_creation_1h_input_cost_per_token=cache_creation_1h_input_cost_per_token,
|
|
532
|
+
reasoning_output_cost_per_token=reasoning_output_cost_per_token,
|
|
533
|
+
raw_metadata=metadata_with_provenance,
|
|
534
|
+
error=None,
|
|
535
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__all__ = []
|