utim-cli 2.3.21__tar.gz → 2.3.22__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.3.21 → utim_cli-2.3.22}/CHANGELOG.md +15 -8
- {utim_cli-2.3.21/utim_cli.egg-info → utim_cli-2.3.22}/PKG-INFO +1 -1
- {utim_cli-2.3.21 → utim_cli-2.3.22}/pyproject.toml +1 -1
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim/__init__.py +1 -1
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/__init__.py +1 -1
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/_version.py +1 -1
- utim_cli-2.3.22/utim_cli/constants.py +99 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/orchestrator_llm_transport.py +29 -1
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/models.py +12 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/completion_routes.py +4 -52
- {utim_cli-2.3.21 → utim_cli-2.3.22/utim_cli.egg-info}/PKG-INFO +1 -1
- utim_cli-2.3.21/utim_cli/constants.py +0 -43
- {utim_cli-2.3.21 → utim_cli-2.3.22}/LICENSE +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/MANIFEST.in +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/README.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/setup.cfg +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/setup.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/_verify_repro.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/_verify_syntax.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/_wizard_smoke_test.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/agent.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/ask_helper.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/auth.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/backup.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/billing.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/blender_agent.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/bootstrap.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/brain.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/builtin/skills/utim-guide/SKILL.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/client_utils.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/config.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/context_pruner.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/crawler/__init__.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/crawler/engine.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/crawler/markdown_distiller.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/dependency_manager.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/doctor.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/evidence_registry.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/harbor.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/knowledge_graph.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/local_db.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/logger.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/mcp_clean_wrapper.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/mcp_client.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/mcp_registry.json +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/models.txt +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/orchestrator.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/orchestrator_helpers.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/orchestrator_tool_exec.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/orchestrator_turn_history.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/personalities.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/platform_installer.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/plugins/__init__.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/plugins/hooks.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/plugins/loader.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/plugins/manager.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/plugins/registry.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/plugins/runtime.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/plugins/schema.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/plugins/tool_loader.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/reflection.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/report.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/scrapy_search.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/sdk/__init__.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/sdk/config.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/sdk/context.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/sdk/events.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/sdk/handlers.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/sdk/session.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/sdk/sidecar.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/__init__.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/admin_auth.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/attribution.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/audit_log.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/auth.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/batch_processor.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/captcha.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/cli_auth.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/concurrency.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/db.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/SECRET_PROVISIONING.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/about.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/changelog.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/docs.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/features.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/license.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/pricing.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/privacy.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/refund.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/support.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/docs_md/terms.md +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/email_utils.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/exchange_rate.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/firebase.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/fix_duplicate_users.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/history.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/key_rotator.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/local_llm.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/logging_config.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/micro_batcher.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/model_agent.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/plan_integrity.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/pricing_updater.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/provision_build.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/rate_limit.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/rewards_engine.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/router.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/__init__.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/admin_bonus_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/admin_db_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/auth_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/billing_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/credit_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/feedback_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/marketplace_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/quota_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/quota_share_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/referral_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/rewards_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/security_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/session_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/share_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/routes/webhook_routes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/security_alerts.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/server.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/storage_nodes.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/server/utils.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/share.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/share_tui.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/situational_scoring.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/state.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/subagent_manager.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/task_dispatcher.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/task_logger.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tools.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tools_grep.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/__init__.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/feedback_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/history_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/marketplace_app_state.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/marketplace_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/marketplace_layout_engine.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/mcp_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/miniagents_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/model_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/personality_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/plugins_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/publish_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/quota_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/quota_redeem_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/quota_share_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/resume_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/rewards_tui.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/skills_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/subagents_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/tasks_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/thinking_display.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/tools_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/tui/update_dialog.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/update_checker.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/utilities.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/utim.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/utimmodel.txt +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/vector_memory.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/wheel.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli/workspace.py +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli.egg-info/SOURCES.txt +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli.egg-info/dependency_links.txt +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli.egg-info/entry_points.txt +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli.egg-info/requires.txt +0 -0
- {utim_cli-2.3.21 → utim_cli-2.3.22}/utim_cli.egg-info/top_level.txt +0 -0
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.3.22] - 2026-09-06
|
|
4
|
+
|
|
5
|
+
### 🛡️ Seamless Rate-Limit Failover to Paid Slugs
|
|
6
|
+
- **Client-Side Auto-Shift**: In `orchestrator_llm_transport.py`, when a free model (e.g. `poolside/laguna-s-2.1:free`) encounters an HTTP 429 or streaming rate-limit event, the client immediately switches to its paid slug (`poolside/laguna-s-2.1`) without terminating the conversation turn or showing an interrupting rate-limit error.
|
|
7
|
+
- **Single Source of Truth**: Centralized `get_paid_slug()` in `utim_cli/constants.py` for uniform mapping across client transport and server completion routing.
|
|
8
|
+
- **Laguna Paid Slug Registration**: Added `poolside/laguna-s-2.1` to the server model registry with complete tool, chat, and reasoning capabilities.
|
|
9
|
+
- **Cost-Protected MiniMax Failover**: Ensured rate-limited MiniMax free models shift to the Laguna S 2.1 paid slug rather than expensive MiniMax paid tiers.
|
|
10
|
+
- **Credit Rate Preservation**: Retained fixed free model pricing ($0.30 input / $0.50 output per 1M tokens) on server fallback turns.
|
|
11
|
+
|
|
3
12
|
## [2.3.21] - 2026-09-06
|
|
4
13
|
|
|
5
14
|
### 💰 Pricing Modifications
|
|
6
|
-
-
|
|
7
|
-
- **Free Model Fallback Credit Rate Preservation**: Preserved fixed consumption rates ($0.30 input / $0.50 output per 1M tokens) when transitioning from exhausted APINEX keys to fallback paid slugs, ensuring consistent credit accounting.
|
|
15
|
+
- OpenRouter tier markup standardization and free model fallback credit preservation
|
|
8
16
|
|
|
9
|
-
### 📦 Models Payload Fixes
|
|
10
|
-
-
|
|
11
|
-
- **Image Generation Model Filtering**: Excluded image-generation models from the interactive chat model catalog to avoid completion payload incompatibilities.
|
|
12
|
-
- **APINEX Model Mapping Support**: Added model registry definitions and key rotation support for `qwen/3.8-max` and `free/qwen-3.8-max`.
|
|
17
|
+
### 📦 Models Payload Fixes
|
|
18
|
+
- Upstream provider normalization and APINEX model mapping support
|
|
13
19
|
|
|
14
20
|
### 🛡️ Rate Limit & Vision Tooling Fixes
|
|
15
|
-
-
|
|
16
|
-
|
|
21
|
+
- MiniMax rate-limit fallback to Laguna and APINEX transparent image analysis
|
|
22
|
+
|
|
23
|
+
*See [docs](docs.md) for detailed APINEX migration information and implementation notes.*
|
|
17
24
|
|
|
18
25
|
## [2.3.20] - 2026-09-04
|
|
19
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: utim-cli
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.22
|
|
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.3.
|
|
17
|
+
__version__ = "2.3.22"
|
|
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
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
DEFAULT_MODEL = "poolside/laguna-s-2.1:free"
|
|
4
|
+
SERVER_URL = os.getenv("UTIM_SERVER_URL", "https://api.utim.dev")
|
|
5
|
+
OPENROUTER_BASE_URL = os.getenv("OPENROUTER_BASE_URL", "https://openrouter.ai/api/v1")
|
|
6
|
+
|
|
7
|
+
SUBAGENT_DEFAULTS = {
|
|
8
|
+
"web_search": DEFAULT_MODEL,
|
|
9
|
+
"plan_project": DEFAULT_MODEL,
|
|
10
|
+
"generate_image": "qwen/qwen-image-3",
|
|
11
|
+
"analyze_image": "google/gemma-4-31b-it:free",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
APINEX_MODEL_IDS = {
|
|
15
|
+
"claude/opus-5",
|
|
16
|
+
"claude/sonnet-5",
|
|
17
|
+
"deepseek/v4-flash-0731",
|
|
18
|
+
"deepseek/v4-pro-0813",
|
|
19
|
+
"free/deepseek-v4-flash-0731",
|
|
20
|
+
"free/deepseek-v4-pro-0813",
|
|
21
|
+
"free/glm-5.3-flash",
|
|
22
|
+
"free/gemini-3.1-pro",
|
|
23
|
+
"free/gemini-3.7-flash",
|
|
24
|
+
"gemini/3.1-pro",
|
|
25
|
+
"gemini/3.7-flash",
|
|
26
|
+
"kimi/k3",
|
|
27
|
+
"gpt/5.6-luna",
|
|
28
|
+
"gpt/5.6-sol",
|
|
29
|
+
"gpt/5.6-terra",
|
|
30
|
+
"glm/5.3",
|
|
31
|
+
"glm/5.3-flash",
|
|
32
|
+
"grok/4.6",
|
|
33
|
+
"qwen/3.8-max",
|
|
34
|
+
"free/qwen-3.8-max",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
APINEX_TO_OPENROUTER_PAID: dict[str, str] = {
|
|
38
|
+
"gemini/3.7-flash": "google/gemini-2.5-flash",
|
|
39
|
+
"free/gemini-3.7-flash": "google/gemini-2.5-flash",
|
|
40
|
+
"gemini/3.1-pro": "google/gemini-2.5-pro",
|
|
41
|
+
"free/gemini-3.1-pro": "google/gemini-2.5-pro",
|
|
42
|
+
"deepseek/v4-flash-0731": "deepseek/deepseek-chat",
|
|
43
|
+
"free/deepseek-v4-flash-0731": "deepseek/deepseek-chat",
|
|
44
|
+
"deepseek/v4-pro-0813": "deepseek/deepseek-r1",
|
|
45
|
+
"free/deepseek-v4-pro-0813": "deepseek/deepseek-r1",
|
|
46
|
+
"claude/sonnet-5": "anthropic/claude-3.5-sonnet",
|
|
47
|
+
"claude/opus-5": "anthropic/claude-3-opus",
|
|
48
|
+
"gpt/5.6-luna": "openai/gpt-4o-mini",
|
|
49
|
+
"gpt/5.6-sol": "openai/gpt-4o",
|
|
50
|
+
"gpt/5.6-terra": "openai/gpt-4o",
|
|
51
|
+
"glm/5.3": "z-ai/glm-4",
|
|
52
|
+
"glm/5.3-flash": "z-ai/glm-4",
|
|
53
|
+
"free/glm-5.3-flash": "z-ai/glm-4",
|
|
54
|
+
"kimi/k3": "moonshotai/kimi-k2",
|
|
55
|
+
"grok/4.6": "x-ai/grok-2-1212",
|
|
56
|
+
"qwen/3.8-max": "qwen/qwen-2.5-72b-instruct",
|
|
57
|
+
"free/qwen-3.8-max": "qwen/qwen-2.5-72b-instruct",
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_paid_slug(model_id: str) -> str:
|
|
62
|
+
"""Return the paid equivalent slug for a free or gateway model.
|
|
63
|
+
- MiniMax models (e.g. minimax/minimax-m2.7:free, minimax/minimax-m3:free) are pricy,
|
|
64
|
+
so when hitting rate limits, the server falls back to Laguna S 2.1 paid slug
|
|
65
|
+
('poolside/laguna-s-2.1') instead of expensive MiniMax paid slugs.
|
|
66
|
+
- If model ends with ':free', strip ':free' (provider/model:free -> provider/model).
|
|
67
|
+
- If APINEX model, map to corresponding OpenRouter paid model.
|
|
68
|
+
- If model starts with 'free/', check APINEX mapping or strip 'free/'.
|
|
69
|
+
- If 'openrouter/free', return standard high-capacity default ('google/gemini-2.5-flash').
|
|
70
|
+
"""
|
|
71
|
+
clean_id = (model_id or "").strip()
|
|
72
|
+
clean_lower = clean_id.lower()
|
|
73
|
+
|
|
74
|
+
# MiniMax free models are pricy on their paid tier; route fallback to Laguna S 2.1 paid slug
|
|
75
|
+
if "minimax" in clean_lower:
|
|
76
|
+
return "poolside/laguna-s-2.1"
|
|
77
|
+
|
|
78
|
+
if clean_id.endswith(":free"):
|
|
79
|
+
return clean_id[:-5]
|
|
80
|
+
if clean_id in APINEX_TO_OPENROUTER_PAID:
|
|
81
|
+
return APINEX_TO_OPENROUTER_PAID[clean_id]
|
|
82
|
+
if clean_id.startswith("free/"):
|
|
83
|
+
unprefixed = clean_id[5:]
|
|
84
|
+
if unprefixed in APINEX_TO_OPENROUTER_PAID:
|
|
85
|
+
return APINEX_TO_OPENROUTER_PAID[unprefixed]
|
|
86
|
+
if unprefixed.endswith(":free"):
|
|
87
|
+
return unprefixed[:-5]
|
|
88
|
+
return unprefixed
|
|
89
|
+
if clean_id == "openrouter/free":
|
|
90
|
+
return "google/gemini-2.5-flash"
|
|
91
|
+
return clean_id
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
import sys
|
|
95
|
+
_IS_LEGACY_WIN = (sys.platform == "win32" and "WT_SESSION" not in os.environ)
|
|
96
|
+
PROMPT_SYMBOL = ">" if _IS_LEGACY_WIN else "❯"
|
|
97
|
+
ARROW_SYMBOL = "->" if _IS_LEGACY_WIN else "➔"
|
|
98
|
+
|
|
99
|
+
|
|
@@ -30,7 +30,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
|
30
30
|
from typing import Any, Dict, List, Optional, Tuple
|
|
31
31
|
|
|
32
32
|
import requests
|
|
33
|
-
from utim_cli.constants import DEFAULT_MODEL
|
|
33
|
+
from utim_cli.constants import DEFAULT_MODEL, get_paid_slug
|
|
34
34
|
|
|
35
35
|
# openai SDK removed — we call OpenRouter directly via requests (no Rust/jiter needed)
|
|
36
36
|
from rich.console import Console
|
|
@@ -1558,6 +1558,20 @@ class LLMTransportMixin:
|
|
|
1558
1558
|
"tool_calls": None,
|
|
1559
1559
|
}, False
|
|
1560
1560
|
elif _is_rate_limit:
|
|
1561
|
+
_paid_slug = get_paid_slug(current_model)
|
|
1562
|
+
if _paid_slug != current_model:
|
|
1563
|
+
if not silent:
|
|
1564
|
+
self.console.print(
|
|
1565
|
+
f"\n[bold yellow]⏳ Model '{current_model}' is temporarily rate-limited. Shifting seamlessly to paid slug [bold]{_paid_slug}[/bold]...[/bold yellow]\n"
|
|
1566
|
+
)
|
|
1567
|
+
if _paid_slug not in models_to_try:
|
|
1568
|
+
models_to_try.insert(model_idx + 1, _paid_slug)
|
|
1569
|
+
if not override_model and model_idx == 0:
|
|
1570
|
+
self.model_id = _paid_slug
|
|
1571
|
+
self.model_source = "utim"
|
|
1572
|
+
config.set("main_model_source", "utim")
|
|
1573
|
+
raise RuntimeError(f"__RATE_LIMIT_SHIFT__:{current_model}:{_paid_slug}")
|
|
1574
|
+
|
|
1561
1575
|
rate_limit_display = (
|
|
1562
1576
|
f"⏳ **Model Rate Limited**: `{current_model}` is currently experiencing high demand and is temporarily rate-limited by the provider.\n\n"
|
|
1563
1577
|
f"- **What to do:** Please wait a moment before retrying, or switch to a different model with `/model` or `Ctrl+M`.\n"
|
|
@@ -2115,6 +2129,20 @@ class LLMTransportMixin:
|
|
|
2115
2129
|
"tool_calls": None,
|
|
2116
2130
|
}, False
|
|
2117
2131
|
|
|
2132
|
+
_paid_slug = get_paid_slug(current_model)
|
|
2133
|
+
if _paid_slug != current_model:
|
|
2134
|
+
if not silent:
|
|
2135
|
+
self.console.print(
|
|
2136
|
+
f"\n[bold yellow]⏳ Model '{current_model}' is temporarily rate-limited. Shifting seamlessly to paid slug [bold]{_paid_slug}[/bold]...[/bold yellow]\n"
|
|
2137
|
+
)
|
|
2138
|
+
if _paid_slug not in models_to_try:
|
|
2139
|
+
models_to_try.insert(model_idx + 1, _paid_slug)
|
|
2140
|
+
if not override_model and model_idx == 0:
|
|
2141
|
+
self.model_id = _paid_slug
|
|
2142
|
+
self.model_source = "utim"
|
|
2143
|
+
config.set("main_model_source", "utim")
|
|
2144
|
+
break # attempt loop → outer loop immediately tries _paid_slug next!
|
|
2145
|
+
|
|
2118
2146
|
rate_limit_display = (
|
|
2119
2147
|
f"⏳ **Model Rate Limited**: `{current_model}` is currently experiencing high demand and is temporarily rate-limited by the provider.\n\n"
|
|
2120
2148
|
f"- **What to do:** Please wait a moment before retrying, or switch to a different model with `/model` or `Ctrl+M`.\n"
|
|
@@ -1082,6 +1082,18 @@ MODEL_REGISTRY: dict[MODEL_ID, ModelEntry] = {
|
|
|
1082
1082
|
capabilities=["code", "chat", "tool_use"],
|
|
1083
1083
|
tags=["free"],
|
|
1084
1084
|
),
|
|
1085
|
+
"poolside/laguna-s-2.1": ModelEntry(
|
|
1086
|
+
model_id="poolside/laguna-s-2.1",
|
|
1087
|
+
provider="openrouter",
|
|
1088
|
+
cost_input_per_1k=0.000117,
|
|
1089
|
+
cost_output_per_1k=0.000234,
|
|
1090
|
+
cost_input_per_1m=0.117,
|
|
1091
|
+
cost_output_per_1m=0.234,
|
|
1092
|
+
context_window=1_048_576,
|
|
1093
|
+
capabilities=["code", "chat", "tool_use"],
|
|
1094
|
+
tags=["premium", "code"],
|
|
1095
|
+
max_output_tokens=131_072,
|
|
1096
|
+
),
|
|
1085
1097
|
"krea/krea-2-medium-turbo": ModelEntry(
|
|
1086
1098
|
model_id="krea/krea-2-medium-turbo",
|
|
1087
1099
|
provider="openrouter",
|
|
@@ -556,59 +556,11 @@ def get_openrouter_free_model(model_id: str, db: Optional[Session] = None) -> st
|
|
|
556
556
|
return free_candidates[0]["model_id"]
|
|
557
557
|
|
|
558
558
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
"free/gemini-3.1-pro": "google/gemini-2.5-pro",
|
|
564
|
-
"deepseek/v4-flash-0731": "deepseek/deepseek-chat",
|
|
565
|
-
"free/deepseek-v4-flash-0731": "deepseek/deepseek-chat",
|
|
566
|
-
"deepseek/v4-pro-0813": "deepseek/deepseek-r1",
|
|
567
|
-
"free/deepseek-v4-pro-0813": "deepseek/deepseek-r1",
|
|
568
|
-
"claude/sonnet-5": "anthropic/claude-3.5-sonnet",
|
|
569
|
-
"claude/opus-5": "anthropic/claude-3-opus",
|
|
570
|
-
"gpt/5.6-luna": "openai/gpt-4o-mini",
|
|
571
|
-
"gpt/5.6-sol": "openai/gpt-4o",
|
|
572
|
-
"gpt/5.6-terra": "openai/gpt-4o",
|
|
573
|
-
"glm/5.3": "z-ai/glm-4",
|
|
574
|
-
"glm/5.3-flash": "z-ai/glm-4",
|
|
575
|
-
"free/glm-5.3-flash": "z-ai/glm-4",
|
|
576
|
-
"kimi/k3": "moonshotai/kimi-k2",
|
|
577
|
-
"grok/4.6": "x-ai/grok-2-1212",
|
|
578
|
-
}
|
|
579
|
-
|
|
559
|
+
from utim_cli.constants import (
|
|
560
|
+
APINEX_TO_OPENROUTER_PAID,
|
|
561
|
+
get_paid_slug,
|
|
562
|
+
)
|
|
580
563
|
|
|
581
|
-
def get_paid_slug(model_id: str) -> str:
|
|
582
|
-
"""Return the paid equivalent slug for a free or gateway model.
|
|
583
|
-
- MiniMax models (e.g. minimax/minimax-m2.7:free, minimax/minimax-m3:free) are pricy,
|
|
584
|
-
so when hitting rate limits, the server falls back to Laguna S 2.1 paid slug
|
|
585
|
-
('poolside/laguna-s-2.1') instead of expensive MiniMax paid slugs.
|
|
586
|
-
- If model ends with ':free', strip ':free' (provider/model:free -> provider/model).
|
|
587
|
-
- If APINEX model, map to corresponding OpenRouter paid model.
|
|
588
|
-
- If model starts with 'free/', check APINEX mapping or strip 'free/'.
|
|
589
|
-
- If 'openrouter/free', return standard high-capacity default ('google/gemini-2.5-flash').
|
|
590
|
-
"""
|
|
591
|
-
clean_id = model_id.strip()
|
|
592
|
-
clean_lower = clean_id.lower()
|
|
593
|
-
|
|
594
|
-
# MiniMax free models are pricy on their paid tier; route fallback to Laguna S 2.1 paid slug
|
|
595
|
-
if "minimax" in clean_lower:
|
|
596
|
-
return "poolside/laguna-s-2.1"
|
|
597
|
-
|
|
598
|
-
if clean_id.endswith(":free"):
|
|
599
|
-
return clean_id[:-5]
|
|
600
|
-
if clean_id in APINEX_TO_OPENROUTER_PAID:
|
|
601
|
-
return APINEX_TO_OPENROUTER_PAID[clean_id]
|
|
602
|
-
if clean_id.startswith("free/"):
|
|
603
|
-
unprefixed = clean_id[5:]
|
|
604
|
-
if unprefixed in APINEX_TO_OPENROUTER_PAID:
|
|
605
|
-
return APINEX_TO_OPENROUTER_PAID[unprefixed]
|
|
606
|
-
if unprefixed.endswith(":free"):
|
|
607
|
-
return unprefixed[:-5]
|
|
608
|
-
return unprefixed
|
|
609
|
-
if clean_id == "openrouter/free":
|
|
610
|
-
return "google/gemini-2.5-flash"
|
|
611
|
-
return clean_id
|
|
612
564
|
|
|
613
565
|
|
|
614
566
|
def is_free_or_gateway_model(model_id: str) -> bool:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: utim-cli
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.22
|
|
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
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
DEFAULT_MODEL = "poolside/laguna-s-2.1:free"
|
|
4
|
-
SERVER_URL = os.getenv("UTIM_SERVER_URL", "https://api.utim.dev")
|
|
5
|
-
OPENROUTER_BASE_URL = os.getenv("OPENROUTER_BASE_URL", "https://openrouter.ai/api/v1")
|
|
6
|
-
|
|
7
|
-
SUBAGENT_DEFAULTS = {
|
|
8
|
-
"web_search": DEFAULT_MODEL,
|
|
9
|
-
"plan_project": DEFAULT_MODEL,
|
|
10
|
-
"generate_image": "qwen/qwen-image-3",
|
|
11
|
-
"analyze_image": "google/gemma-4-31b-it:free",
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
APINEX_MODEL_IDS = {
|
|
15
|
-
"claude/opus-5",
|
|
16
|
-
"claude/sonnet-5",
|
|
17
|
-
"deepseek/v4-flash-0731",
|
|
18
|
-
"deepseek/v4-pro-0813",
|
|
19
|
-
"free/deepseek-v4-flash-0731",
|
|
20
|
-
"free/deepseek-v4-pro-0813",
|
|
21
|
-
"free/glm-5.3-flash",
|
|
22
|
-
"free/gemini-3.1-pro",
|
|
23
|
-
"free/gemini-3.7-flash",
|
|
24
|
-
"gemini/3.1-pro",
|
|
25
|
-
"gemini/3.7-flash",
|
|
26
|
-
"kimi/k3",
|
|
27
|
-
"gpt/5.6-luna",
|
|
28
|
-
"gpt/5.6-sol",
|
|
29
|
-
"gpt/5.6-terra",
|
|
30
|
-
"glm/5.3",
|
|
31
|
-
"glm/5.3-flash",
|
|
32
|
-
"grok/4.6",
|
|
33
|
-
"qwen/3.8-max",
|
|
34
|
-
"free/qwen-3.8-max",
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
import sys
|
|
39
|
-
_IS_LEGACY_WIN = (sys.platform == "win32" and "WT_SESSION" not in os.environ)
|
|
40
|
-
PROMPT_SYMBOL = ">" if _IS_LEGACY_WIN else "❯"
|
|
41
|
-
ARROW_SYMBOL = "->" if _IS_LEGACY_WIN else "➔"
|
|
42
|
-
|
|
43
|
-
|
|
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
|