utim-cli 1.47.4__tar.gz → 1.47.6__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-1.47.4 → utim_cli-1.47.6}/CHANGELOG.md +10 -0
- {utim_cli-1.47.4/utim_cli.egg-info → utim_cli-1.47.6}/PKG-INFO +1 -1
- {utim_cli-1.47.4 → utim_cli-1.47.6}/pyproject.toml +1 -1
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/__init__.py +1 -1
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/_version.py +1 -1
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/orchestrator.py +71 -47
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/utim.py +2 -2
- {utim_cli-1.47.4 → utim_cli-1.47.6/utim_cli.egg-info}/PKG-INFO +1 -1
- {utim_cli-1.47.4 → utim_cli-1.47.6}/LICENSE +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/MANIFEST.in +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/README.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/setup.cfg +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/setup.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/agent.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/auth.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/backup.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/blender_agent.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/bootstrap.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/client_utils.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/config.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/constants.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/context_pruner.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/doctor.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/knowledge_graph.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/local_db.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/logger.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/mcp_clean_wrapper.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/mcp_client.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/mcp_registry.json +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/reflection.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/report.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/scrapy_search.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/__init__.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/auth.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/db.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/about.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/changelog.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/docs.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/features.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/license.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/pricing.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/privacy.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/refund.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/support.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/docs_md/terms.md +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/email_utils.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/exchange_rate.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/firebase.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/history.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/logging_config.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/models.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/pricing_updater.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/rate_limit.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/router.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/__init__.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/auth_routes.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/completion_routes.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/credit_routes.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/feedback_routes.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/quota_routes.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/referral_routes.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/session_routes.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/routes/share_routes.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/server/server.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/share.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/share_tui.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/situational_scoring.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/state.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tools.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/__init__.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/feedback_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/history_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/mcp_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/model_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/quota_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/resume_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/skills_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/tools_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/tui/update_dialog.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/utilities.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/vector_memory.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli/workspace.py +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli.egg-info/SOURCES.txt +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli.egg-info/dependency_links.txt +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli.egg-info/entry_points.txt +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli.egg-info/requires.txt +0 -0
- {utim_cli-1.47.4 → utim_cli-1.47.6}/utim_cli.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.47.6] - 2026-07-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Asynchronous Local LLM Setup**: Moved the local Qwen model downloading and setup pipeline into a background daemon thread, allowing UTIM to run completions instantly via Cloud API during initial setup/installation without blocking user queries.
|
|
7
|
+
|
|
8
|
+
## [1.47.5] - 2026-07-19
|
|
9
|
+
|
|
10
|
+
### Optimized
|
|
11
|
+
- **Instant startup / rules summarization**: Prioritized Cloud API completion calls (via UTIM completions server or direct OpenRouter) over local Qwen LLM execution in `summarize_experiences_with_model`. This completely eliminates the 1m 49s latency caused by importing PyTorch/Transformers and loading the 0.5B model from scratch, falling back to local execution only in offline mode.
|
|
12
|
+
|
|
3
13
|
## [1.47.4] - 2026-07-19
|
|
4
14
|
|
|
5
15
|
### Fixed
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "utim-cli"
|
|
7
|
-
version = "1.47.
|
|
7
|
+
version = "1.47.6"
|
|
8
8
|
description = "UTIM – Universal Terminal Intelligence Manager. A powerful agentic AI coding assistant for your terminal."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -350,6 +350,42 @@ def compress_experience(text: str) -> str:
|
|
|
350
350
|
|
|
351
351
|
_qwen_model = None
|
|
352
352
|
_qwen_tokenizer = None
|
|
353
|
+
_qwen_downloading = False
|
|
354
|
+
|
|
355
|
+
def _trigger_qwen_download_bg():
|
|
356
|
+
"""Trigger background download and caching of Qwen local model if not already loaded or downloading."""
|
|
357
|
+
global _qwen_model, _qwen_tokenizer, _qwen_downloading
|
|
358
|
+
if _qwen_model is None and not _qwen_downloading:
|
|
359
|
+
import sys
|
|
360
|
+
if "pytest" in sys.modules:
|
|
361
|
+
return
|
|
362
|
+
|
|
363
|
+
_qwen_downloading = True
|
|
364
|
+
import threading
|
|
365
|
+
|
|
366
|
+
def download_model_bg():
|
|
367
|
+
global _qwen_model, _qwen_tokenizer, _qwen_downloading
|
|
368
|
+
try:
|
|
369
|
+
import torch
|
|
370
|
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
371
|
+
model_id = "Qwen/Qwen2.5-0.5B-Instruct"
|
|
372
|
+
tok = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True, local_files_only=False)
|
|
373
|
+
mod = AutoModelForCausalLM.from_pretrained(
|
|
374
|
+
model_id,
|
|
375
|
+
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
|
|
376
|
+
device_map="auto",
|
|
377
|
+
trust_remote_code=True,
|
|
378
|
+
local_files_only=False
|
|
379
|
+
)
|
|
380
|
+
_qwen_tokenizer = tok
|
|
381
|
+
_qwen_model = mod
|
|
382
|
+
except Exception:
|
|
383
|
+
pass
|
|
384
|
+
finally:
|
|
385
|
+
_qwen_downloading = False
|
|
386
|
+
|
|
387
|
+
t = threading.Thread(target=download_model_bg, daemon=True)
|
|
388
|
+
t.start()
|
|
353
389
|
|
|
354
390
|
def summarize_experiences_with_model(experiences: list[dict], existing_cache: str = "") -> str:
|
|
355
391
|
"""Summarize list of experiences into a clean list of rules under 2000 tokens using local Qwen model first, falling back to LLM API."""
|
|
@@ -409,25 +445,40 @@ def summarize_experiences_with_model(experiences: list[dict], existing_cache: st
|
|
|
409
445
|
"Output ONLY the clean markdown list of rules (do not include introductory or concluding text):"
|
|
410
446
|
)
|
|
411
447
|
|
|
412
|
-
#
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
448
|
+
# Proactively trigger Qwen local model download in a background thread if needed
|
|
449
|
+
_trigger_qwen_download_bg()
|
|
450
|
+
|
|
451
|
+
# 1. Attempt Cloud API completions (via UTIM completions server or direct OpenRouter)
|
|
452
|
+
import os
|
|
453
|
+
api_key = config.get("api_key")
|
|
454
|
+
llm_key = os.environ.get("OPENROUTER_API_KEY") or os.environ.get("UTIM_API_KEY")
|
|
455
|
+
|
|
456
|
+
if api_key or llm_key:
|
|
457
|
+
from utim_cli.reflection import REFLECTION_MODELS
|
|
458
|
+
from utim_cli.client_utils import proxy_openrouter_request
|
|
459
|
+
|
|
460
|
+
for model in REFLECTION_MODELS:
|
|
461
|
+
try:
|
|
462
|
+
resp = proxy_openrouter_request({
|
|
463
|
+
"model": model,
|
|
464
|
+
"messages": [
|
|
465
|
+
{"role": "system", "content": "You are a context compressor. Output rules list directly."},
|
|
466
|
+
{"role": "user", "content": prompt}
|
|
467
|
+
],
|
|
468
|
+
"max_tokens": 1000
|
|
469
|
+
})
|
|
470
|
+
if resp.status_code == 200:
|
|
471
|
+
content = resp.json()["choices"][0]["message"]["content"].strip()
|
|
472
|
+
if content:
|
|
473
|
+
return content
|
|
474
|
+
except Exception:
|
|
475
|
+
continue
|
|
476
|
+
|
|
477
|
+
# 2. Fallback to local execution using Qwen2.5-0.5B-Instruct if background loader has completed
|
|
478
|
+
global _qwen_model, _qwen_tokenizer
|
|
479
|
+
if _qwen_model is not None:
|
|
480
|
+
try:
|
|
417
481
|
import torch
|
|
418
|
-
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
419
|
-
|
|
420
|
-
model_id = "Qwen/Qwen2.5-0.5B-Instruct"
|
|
421
|
-
|
|
422
|
-
if _qwen_model is None:
|
|
423
|
-
_qwen_tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
|
|
424
|
-
_qwen_model = AutoModelForCausalLM.from_pretrained(
|
|
425
|
-
model_id,
|
|
426
|
-
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
|
|
427
|
-
device_map="auto",
|
|
428
|
-
trust_remote_code=True
|
|
429
|
-
)
|
|
430
|
-
|
|
431
482
|
messages = [
|
|
432
483
|
{"role": "system", "content": "You are a context compressor. Output rules list directly."},
|
|
433
484
|
{"role": "user", "content": prompt}
|
|
@@ -454,36 +505,9 @@ def summarize_experiences_with_model(experiences: list[dict], existing_cache: st
|
|
|
454
505
|
response = _qwen_tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0].strip()
|
|
455
506
|
if response:
|
|
456
507
|
return response
|
|
457
|
-
|
|
458
|
-
except Exception:
|
|
459
|
-
pass
|
|
460
|
-
|
|
461
|
-
# 2. Fallback to OpenRouter Cloud API
|
|
462
|
-
import os
|
|
463
|
-
llm_key = os.environ.get("OPENROUTER_API_KEY") or os.environ.get("UTIM_API_KEY")
|
|
464
|
-
if not llm_key:
|
|
465
|
-
return existing_cache or "\n".join(raw_texts[:15])
|
|
466
|
-
|
|
467
|
-
from utim_cli.reflection import REFLECTION_MODELS
|
|
468
|
-
from utim_cli.client_utils import proxy_openrouter_request
|
|
469
|
-
|
|
470
|
-
for model in REFLECTION_MODELS:
|
|
471
|
-
try:
|
|
472
|
-
resp = proxy_openrouter_request({
|
|
473
|
-
"model": model,
|
|
474
|
-
"messages": [
|
|
475
|
-
{"role": "system", "content": "You are a context compressor. Output rules list directly."},
|
|
476
|
-
{"role": "user", "content": prompt}
|
|
477
|
-
],
|
|
478
|
-
"max_tokens": 1000
|
|
479
|
-
})
|
|
480
|
-
if resp.status_code == 200:
|
|
481
|
-
content = resp.json()["choices"][0]["message"]["content"].strip()
|
|
482
|
-
if content:
|
|
483
|
-
return content
|
|
484
508
|
except Exception:
|
|
485
|
-
|
|
486
|
-
|
|
509
|
+
pass
|
|
510
|
+
|
|
487
511
|
return existing_cache or "\n".join(raw_texts[:15])
|
|
488
512
|
|
|
489
513
|
def update_experience_summary_cache(user_prompt: str) -> str:
|
|
@@ -952,7 +952,7 @@ def _print_animated_banner(animated: bool = True):
|
|
|
952
952
|
else:
|
|
953
953
|
console.print(f"[bold {color}]{BANNER_BIG}[/bold {color}]")
|
|
954
954
|
|
|
955
|
-
console.print(f" [bold white]U Think I Make[/bold white] [dim]v1.47.
|
|
955
|
+
console.print(f" [bold white]U Think I Make[/bold white] [dim]v1.47.6[/dim]")
|
|
956
956
|
user_email = config.email
|
|
957
957
|
user_type = "UTIM Community"
|
|
958
958
|
api_key = config.get("api_key")
|
|
@@ -3586,7 +3586,7 @@ def check_and_update_background():
|
|
|
3586
3586
|
return
|
|
3587
3587
|
|
|
3588
3588
|
latest_ver = resp.json().get("version", "")
|
|
3589
|
-
current_ver = "1.47.
|
|
3589
|
+
current_ver = "1.47.6"
|
|
3590
3590
|
|
|
3591
3591
|
def parse_ver(v):
|
|
3592
3592
|
return [int(x) for x in v.split(".") if x.isdigit()]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|