utim-cli 2.5.0__tar.gz → 2.5.1__tar.gz
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.
- {utim_cli-2.5.0 → utim_cli-2.5.1}/CHANGELOG.md +7 -0
- {utim_cli-2.5.0/utim_cli.egg-info → utim_cli-2.5.1}/PKG-INFO +1 -1
- {utim_cli-2.5.0 → utim_cli-2.5.1}/pyproject.toml +1 -1
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim/__init__.py +1 -1
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/__init__.py +1 -1
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/_version.py +1 -1
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/context_pruner.py +47 -18
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/cli_auth.py +19 -2
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/firewall.py +4 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/router.py +16 -4
- {utim_cli-2.5.0 → utim_cli-2.5.1/utim_cli.egg-info}/PKG-INFO +1 -1
- {utim_cli-2.5.0 → utim_cli-2.5.1}/LICENSE +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/MANIFEST.in +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/README.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/setup.cfg +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/setup.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/_chip_test.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/_verify_repro.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/_verify_syntax.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/_wizard_smoke_test.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/agent.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/architecture_indexer.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/ask_helper.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/auth.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/backup.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/billing.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/blender_agent.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/bootstrap.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/brain.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/builtin/skills/utim-guide/SKILL.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/client_utils.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/config.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/constants.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/context_inspector.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/crawler/__init__.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/crawler/engine.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/crawler/markdown_distiller.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/dependency_manager.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/doctor.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/evidence_registry.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/harbor.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/knowledge_graph.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/local_db.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/logger.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/mcp_clean_wrapper.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/mcp_client.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/mcp_registry.json +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/models.txt +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/orchestrator.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/orchestrator_helpers.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/orchestrator_llm_transport.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/orchestrator_tool_exec.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/orchestrator_turn_history.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/personalities.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/platform_installer.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/plugins/__init__.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/plugins/hooks.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/plugins/loader.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/plugins/manager.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/plugins/registry.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/plugins/runtime.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/plugins/schema.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/plugins/tool_loader.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/reflection.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/report.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/scrapy_search.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/sdk/__init__.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/sdk/config.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/sdk/context.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/sdk/events.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/sdk/handlers.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/sdk/session.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/sdk/sidecar.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/__init__.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/admin_auth.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/api_batcher.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/api_models_db.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/attribution.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/audit_log.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/auth.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/batch_processor.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/captcha.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/concurrency.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/db.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/SECRET_PROVISIONING.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/about.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/changelog.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/docs.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/features.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/license.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/pricing.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/privacy.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/refund.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/support.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/docs_md/terms.md +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/email_utils.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/exchange_rate.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/firebase.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/fix_duplicate_users.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/history.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/hobby_throttler.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/key_rotator.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/local_llm.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/logging_config.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/maintenance.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/micro_batcher.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/model_agent.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/models.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/plan_integrity.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/platform_billing.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/pricing_updater.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/provider_balance.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/provider_discovery.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/provider_router.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/provision_build.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/rate_limit.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/request_batcher.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/request_queue.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/rewards_engine.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/__init__.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/admin_bonus_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/admin_db_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/admin_providers_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/admin_separated_models_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/api_gateway_extensions_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/api_key_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/api_models_admin_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/api_models_public_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/auth_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/billing_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/completion_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/credit_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/feedback_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/marketplace_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/provider_compat_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/quota_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/quota_share_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/referral_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/rewards_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/security_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/session_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/share_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/wallet_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/routes/webhook_routes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/security_alerts.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/server.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/signup_guard.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/storage_nodes.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/server/utils.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/share.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/share_tui.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/situational_scoring.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/state.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/subagent_manager.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/syntax_fix.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/task_dispatcher.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/task_logger.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tools.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tools_grep.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/__init__.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/compression_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/feedback_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/history_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/marketplace_app_state.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/marketplace_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/marketplace_layout_engine.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/mcp_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/miniagents_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/model_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/personality_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/plugins_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/publish_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/quota_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/quota_redeem_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/quota_share_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/resume_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/rewards_tui.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/skills_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/subagents_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/tasks_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/thinking_display.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/tools_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/tui/update_dialog.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/update_checker.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/utilities.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/utim.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/utimmodel.txt +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/vector_memory.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice_coding.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice_events.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice_handler.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice_instant.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice_orchestrator.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice_session.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice_stt.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/voice_tts.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/wheel.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli/workspace.py +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli.egg-info/SOURCES.txt +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli.egg-info/dependency_links.txt +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli.egg-info/entry_points.txt +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli.egg-info/requires.txt +0 -0
- {utim_cli-2.5.0 → utim_cli-2.5.1}/utim_cli.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.5.1] - 2026-10-18
|
|
4
|
+
|
|
5
|
+
### 🐛 Fixes
|
|
6
|
+
- **Compression Empty-Response Spam**: `_call_compression_model_with_fallback` now always sets `last_error` on empty/stripped content and logs `model=… routing=… empty_hits=…` diagnostics — eliminates the endless `[COMPRESSION FALLBACK FAILURE] Last error: None` loop and surfaces the real reason (429 / empty content / bad shape).
|
|
7
|
+
- **Admin Portal CORS**: `router.py` now always allows `Origin: null` (downloaded `file://` HTML) and `allow_headers=["*"]` + `max_age=600` so `X-UTIM-Master-Key` / `Authorization` preflights for `/api/admin/*` and `/models` no longer fail with `No 'Access-Control-Allow-Origin'`.
|
|
8
|
+
- **Admin Firewall Bypass**: `firewall.py: _FIREWALL_SKIP_PREFIXES` and `cli_auth.py: PUBLIC_PREFIXES` now include `/admin`, `/admin.html`, `/admin_models.html`, `/static` so the browser-served admin panel bypasses proxy-abuse / burst throttling and CLI HMAC `401` (API auth via master-key session is still enforced).
|
|
9
|
+
|
|
3
10
|
## [2.5.0] - 2026-10-18
|
|
4
11
|
|
|
5
12
|
### ✨ Credit System → Unlimited UX + Internal Throttling
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: utim-cli
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.1
|
|
4
4
|
Summary: UTIM – Universal Terminal Intelligence Manager. A powerful agentic AI coding assistant for your terminal.
|
|
5
5
|
License: Emend AI Proprietary EULA
|
|
6
6
|
Project-URL: Homepage, https://utim.dev
|
|
@@ -14,7 +14,7 @@ Quickstart:
|
|
|
14
14
|
try:
|
|
15
15
|
from utim_cli._version import VERSION as __version__
|
|
16
16
|
except ImportError:
|
|
17
|
-
__version__ = "2.5.
|
|
17
|
+
__version__ = "2.5.1"
|
|
18
18
|
|
|
19
19
|
# Developer-friendly core classes (similar to `import genai` / `import openai`)
|
|
20
20
|
from utim_cli.sdk.session import UtimSession as Session
|
|
@@ -2229,6 +2229,7 @@ def _call_compression_model_with_fallback(messages: List[Dict], llm_key: str, ma
|
|
|
2229
2229
|
_routing = _resolve_compression_routing(primary_model)
|
|
2230
2230
|
|
|
2231
2231
|
last_error = None
|
|
2232
|
+
empty_hits = 0
|
|
2232
2233
|
for i, model in enumerate(models_to_try):
|
|
2233
2234
|
model_retries = 1 if model == primary_model else 2
|
|
2234
2235
|
for attempt in range(model_retries + 1):
|
|
@@ -2251,56 +2252,84 @@ def _call_compression_model_with_fallback(messages: List[Dict], llm_key: str, ma
|
|
|
2251
2252
|
is_reflection=False
|
|
2252
2253
|
)
|
|
2253
2254
|
if resp.status_code == 429:
|
|
2254
|
-
|
|
2255
|
+
last_error = f"Model {model} rate limited (429)"
|
|
2255
2256
|
break
|
|
2256
2257
|
resp.raise_for_status()
|
|
2257
|
-
|
|
2258
|
+
|
|
2258
2259
|
if resp.status_code == 200:
|
|
2259
|
-
|
|
2260
|
-
|
|
2260
|
+
try:
|
|
2261
|
+
body = resp.json()
|
|
2262
|
+
except Exception as je:
|
|
2263
|
+
last_error = f"Model {model} returned non-JSON 200: {je}"
|
|
2264
|
+
break
|
|
2265
|
+
try:
|
|
2266
|
+
result = body["choices"][0]["message"]["content"]
|
|
2267
|
+
except Exception as ke:
|
|
2268
|
+
last_error = f"Model {model} bad 200 shape {list(body.keys()) if isinstance(body, dict) else type(body).__name__}: {ke} body={str(body)[:600]}"
|
|
2269
|
+
break
|
|
2270
|
+
if not result or not str(result).strip():
|
|
2271
|
+
empty_hits += 1
|
|
2272
|
+
last_error = f"Model {model} returned empty content (hit {empty_hits}/2)"
|
|
2273
|
+
if empty_hits >= 2:
|
|
2274
|
+
break
|
|
2261
2275
|
continue
|
|
2262
2276
|
# Strip thinking tags
|
|
2263
|
-
result = re.sub(r"<think(?:ing)?>.*?</think(?:ing)?>", "", result, flags=re.DOTALL)
|
|
2277
|
+
result = re.sub(r"<think(?:ing)?>.*?</think(?:ing)?>", "", str(result), flags=re.DOTALL)
|
|
2264
2278
|
result = result.strip()
|
|
2265
2279
|
if not result:
|
|
2280
|
+
empty_hits += 1
|
|
2281
|
+
last_error = f"Model {model} content empty after stripping thinking tags (hit {empty_hits}/2)"
|
|
2282
|
+
if empty_hits >= 2:
|
|
2283
|
+
break
|
|
2266
2284
|
continue
|
|
2267
|
-
|
|
2285
|
+
|
|
2268
2286
|
# FIX #1: Hallucination detection - reject summaries with suspicious patterns
|
|
2287
|
+
hallucinated = False
|
|
2269
2288
|
hallucination_patterns = [
|
|
2270
2289
|
r"\[.*added.*\]", # Made-up additions like "[feature added]"
|
|
2271
2290
|
r"\[.*created.*\]", # Made-up creations
|
|
2272
2291
|
r"I have (?:created|modified|deleted|implemented)", # False claims of action
|
|
2273
2292
|
r"Successfully (?:added|removed|integrated)", # False success claims
|
|
2274
2293
|
]
|
|
2275
|
-
|
|
2276
|
-
# Check if summary makes claims not in source
|
|
2277
2294
|
for pattern in hallucination_patterns:
|
|
2278
2295
|
if re.search(pattern, result, re.I) and content_hint:
|
|
2279
|
-
# Check if the claim is actually in the original content
|
|
2280
2296
|
if not re.search(pattern.replace(r"\[", r"[^[]*").replace(r"\]", r"[^]]*"), content_hint, re.I):
|
|
2281
2297
|
print(f"[HALLUCINATION PREVENTED] Pattern '{pattern}' detected in summary but not in source", file=__import__('sys'))
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2298
|
+
last_error = f"Model {model} hallucination rejected pattern={pattern}"
|
|
2299
|
+
hallucinated = True
|
|
2300
|
+
break
|
|
2301
|
+
if hallucinated:
|
|
2302
|
+
continue
|
|
2303
|
+
|
|
2285
2304
|
return result
|
|
2286
|
-
|
|
2287
|
-
last_error = f"Model {model} returned status {resp.status_code}"
|
|
2305
|
+
|
|
2306
|
+
last_error = f"Model {model} returned status {resp.status_code}: {str(getattr(resp, 'content_str', '') or '')[:600]}"
|
|
2288
2307
|
break # Not 200 and not 429, break attempt loop and try next model
|
|
2289
2308
|
|
|
2290
2309
|
except requests.exceptions.HTTPError as e:
|
|
2291
2310
|
code = e.response.status_code if e.response is not None else 0
|
|
2311
|
+
body_snip = ""
|
|
2312
|
+
try:
|
|
2313
|
+
body_snip = (e.response.text[:600] if getattr(e, "response", None) is not None and hasattr(e.response, "text") else str(e)[:600])
|
|
2314
|
+
except Exception:
|
|
2315
|
+
body_snip = str(e)[:600]
|
|
2316
|
+
last_error = f"HTTPError {code} model={model}: {body_snip}"
|
|
2292
2317
|
if code == 429 and attempt < model_retries:
|
|
2293
2318
|
import time
|
|
2294
2319
|
time.sleep(5 * (attempt + 1))
|
|
2295
2320
|
continue
|
|
2296
|
-
last_error = e
|
|
2297
2321
|
break
|
|
2298
2322
|
except Exception as e:
|
|
2299
|
-
last_error = e
|
|
2323
|
+
last_error = f"{type(e).__name__} model={model}: {e}"
|
|
2300
2324
|
break
|
|
2301
|
-
|
|
2302
|
-
# Log the failure for debugging
|
|
2325
|
+
|
|
2326
|
+
# Log the failure for debugging — include model/routing so "Last error: None" never happens
|
|
2303
2327
|
import sys
|
|
2328
|
+
diag = f"model={primary_model} routing={_routing} empty_hits={empty_hits}"
|
|
2329
|
+
if last_error is None:
|
|
2330
|
+
last_error = f"No attempt produced a result ({diag})"
|
|
2331
|
+
else:
|
|
2332
|
+
last_error = f"{last_error} ({diag})"
|
|
2304
2333
|
print(f"[COMPRESSION FALLBACK FAILURE] All models failed. Last error: {last_error}", file=sys.stderr)
|
|
2305
2334
|
return None
|
|
2306
2335
|
|
|
@@ -91,6 +91,13 @@ PUBLIC_PREFIXES = (
|
|
|
91
91
|
"/auth/firebase-login",
|
|
92
92
|
"/auth/register",
|
|
93
93
|
"/auth/reset",
|
|
94
|
+
# Admin HTML portal — browser-served, authenticated via admin_auth (master key
|
|
95
|
+
# / session cookie), never via CLI HMAC. Must stay public for signature
|
|
96
|
+
# purposes or browsers get 401 when UTIM_REQUIRE_CLI_SIGNATURE=1.
|
|
97
|
+
"/admin",
|
|
98
|
+
"/admin.html",
|
|
99
|
+
"/admin_models.html",
|
|
100
|
+
"/static",
|
|
94
101
|
)
|
|
95
102
|
|
|
96
103
|
|
|
@@ -363,8 +370,18 @@ async def cli_signature_middleware(request, call_next):
|
|
|
363
370
|
if is_public_path(path) or request.method == "OPTIONS":
|
|
364
371
|
return await call_next(request)
|
|
365
372
|
|
|
366
|
-
# Bypass CLI signature requirement for Admin Agent endpoints
|
|
367
|
-
|
|
373
|
+
# Bypass CLI signature requirement for Admin Agent endpoints, Master Key
|
|
374
|
+
# authenticated calls, and any /admin / static HTML (admin portal in browser).
|
|
375
|
+
if (
|
|
376
|
+
request.headers.get("x-utim-master-key")
|
|
377
|
+
or request.headers.get("X-UTIM-Master-Key")
|
|
378
|
+
or path.startswith("/api/admin/")
|
|
379
|
+
or path == "/admin"
|
|
380
|
+
or path == "/admin.html"
|
|
381
|
+
or path == "/admin_models.html"
|
|
382
|
+
or path.startswith("/admin/")
|
|
383
|
+
or path.startswith("/static/")
|
|
384
|
+
):
|
|
368
385
|
return await call_next(request)
|
|
369
386
|
|
|
370
387
|
sig = request.headers.get("x-utim-cli-signature")
|
|
@@ -408,18 +408,30 @@ else:
|
|
|
408
408
|
"http://127.0.0.1:8080",
|
|
409
409
|
]
|
|
410
410
|
|
|
411
|
-
# Deduplicate while preserving order
|
|
411
|
+
# Deduplicate while preserving order, then always allow `null` (file://) so
|
|
412
|
+
# downloading admin_models.html and double-clicking it doesn't brick CORS.
|
|
413
|
+
# ALLOWED_ORIGINS env override must not accidentally drop it.
|
|
412
414
|
_seen = set()
|
|
413
415
|
allowed_origins = [o for o in allowed_origins if not (o in _seen or _seen.add(o))]
|
|
414
|
-
|
|
416
|
+
if "null" not in allowed_origins:
|
|
417
|
+
allowed_origins.append("null")
|
|
418
|
+
|
|
419
|
+
# Admin portal (admin_models.html) sends X-UTIM-Master-Key / X-Admin-Key /
|
|
420
|
+
# Authorization which MUST be in allow_headers or every preflight fails with
|
|
421
|
+
# "No 'Access-Control-Allow-Origin'" — that's what your screenshot shows.
|
|
422
|
+
# Starlette's CORSMiddleware with allow_headers=["*"] + allow_credentials=True
|
|
423
|
+
# echoes Access-Control-Request-Headers correctly on modern browsers, but we
|
|
424
|
+
# also keep an explicit fallback list for older engines. Using ["*"] covers
|
|
425
|
+
# any future X-UTIM-* headers without another CORS breakage.
|
|
415
426
|
app.add_middleware(
|
|
416
427
|
CORSMiddleware,
|
|
417
428
|
allow_origins=allowed_origins,
|
|
418
429
|
allow_origin_regex=r"^https://([a-zA-Z0-9_\-]+\.)*(utim\.dev)(:\d+)?$",
|
|
419
430
|
allow_credentials=True,
|
|
420
431
|
allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
421
|
-
allow_headers=["
|
|
422
|
-
expose_headers=["Content-Length", "Content-Type"],
|
|
432
|
+
allow_headers=["*"],
|
|
433
|
+
expose_headers=["Content-Length", "Content-Type", "X-Total-Count"],
|
|
434
|
+
max_age=600,
|
|
423
435
|
)
|
|
424
436
|
|
|
425
437
|
app.include_router(auth_router)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: utim-cli
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.1
|
|
4
4
|
Summary: UTIM – Universal Terminal Intelligence Manager. A powerful agentic AI coding assistant for your terminal.
|
|
5
5
|
License: Emend AI Proprietary EULA
|
|
6
6
|
Project-URL: Homepage, https://utim.dev
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|