feat(agent): hierarchical executor with path resolve, runtime probe, quiet UI
Make Zed Agent closer to Cursor: deterministic DevOps path index, live Traefik port probe before blind edits, stop-after-edit, and quieter Russian progress.
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate litellm_config.yaml from PRIMARY_PROVIDER + config/*.yaml."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
PROFILE = os.environ.get("PRIMARY_PROVIDER", "hybrid").strip().lower()
|
||||
|
||||
|
||||
def load(path: Path) -> dict:
|
||||
with path.open(encoding="utf-8") as f:
|
||||
return yaml.safe_load(f) or {}
|
||||
|
||||
|
||||
def api_key_ref(name: str) -> str:
|
||||
return f"os.environ/{name}"
|
||||
|
||||
|
||||
def _apply_thinking(params: dict, spec: dict) -> None:
|
||||
"""Qwen3 defaults to thinking; empty content + hang unless disabled."""
|
||||
model = str(params.get("model") or spec.get("model") or "").lower()
|
||||
force = bool(spec.get("disable_thinking"))
|
||||
auto = ("qwen3" in model) and not spec.get("enable_thinking")
|
||||
if force or auto:
|
||||
params["extra_body"] = {
|
||||
"chat_template_kwargs": {"enable_thinking": False},
|
||||
"enable_thinking": False,
|
||||
}
|
||||
|
||||
|
||||
def lane_entry(name: str, spec: dict, rpm: int | None) -> dict:
|
||||
params: dict = {
|
||||
"model": spec["model"],
|
||||
"api_key": api_key_ref(spec["api_key"]),
|
||||
# Per-deployment timeout: litellm_settings.request_timeout often shows as
|
||||
# Deployment Info timeout: None on stream/tool hangs.
|
||||
"timeout": int(os.environ.get("LITELLM_MODEL_TIMEOUT", "180")),
|
||||
}
|
||||
if rpm:
|
||||
params["rpm"] = rpm
|
||||
_apply_thinking(params, spec)
|
||||
return {"model_name": name, "litellm_params": params}
|
||||
|
||||
|
||||
def fixed_entry(name: str, spec: dict) -> dict:
|
||||
params: dict = {
|
||||
"model": spec["model"],
|
||||
"api_key": api_key_ref(spec["api_key"]),
|
||||
"timeout": int(os.environ.get("LITELLM_MODEL_TIMEOUT", "180")),
|
||||
}
|
||||
for key in ("ssl_verify", "max_tokens", "temperature"):
|
||||
if key in spec:
|
||||
params[key] = spec[key]
|
||||
_apply_thinking(params, spec)
|
||||
return {"model_name": name, "litellm_params": params}
|
||||
|
||||
|
||||
def smart_router_internal(rules: dict) -> dict:
|
||||
litellm_rules = rules.get("litellm", {})
|
||||
return {
|
||||
"model_name": "smart-router-internal",
|
||||
"litellm_params": {
|
||||
"model": "auto_router/complexity_router",
|
||||
"drop_params": True,
|
||||
"complexity_router_default_model": "a-medium-ops",
|
||||
"complexity_router_config": {
|
||||
"tiers": {
|
||||
"SIMPLE": "a-simple",
|
||||
"MEDIUM": "a-medium-ops",
|
||||
"MEDIUM_CODE": "a-medium-code",
|
||||
"COMPLEX": "a-complex",
|
||||
"REASONING": "a-reasoning",
|
||||
},
|
||||
"classifier_fallback": "heuristic",
|
||||
"keyword_tier_rules": litellm_rules.get("keyword_tier_rules", []),
|
||||
"custom_technical_keywords": litellm_rules.get(
|
||||
"custom_technical_keywords", []
|
||||
),
|
||||
"token_thresholds": {"simple": 20, "complex": 500},
|
||||
"tier_boundaries": {
|
||||
"simple_medium": 0.18,
|
||||
"medium_complex": 0.38,
|
||||
"complex_reasoning": 0.62,
|
||||
},
|
||||
"session_affinity": True,
|
||||
"session_affinity_ttl_seconds": 1800,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
providers = load(ROOT / "config/providers.yaml")
|
||||
profiles = providers.get("profiles", {})
|
||||
if PROFILE not in profiles:
|
||||
print(f"ERROR: unknown PRIMARY_PROVIDER={PROFILE!r}", file=sys.stderr)
|
||||
print(f"Available: {', '.join(sorted(profiles))}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
profile = profiles[PROFILE]
|
||||
base = load(ROOT / "config/litellm.base.yaml")
|
||||
matrix = load(ROOT / "config/model_matrix.yaml")
|
||||
rules = load(ROOT / "config/routing_rules.yaml")
|
||||
meta = matrix.get("models", {})
|
||||
|
||||
model_list: list[dict] = []
|
||||
|
||||
# Classifier first
|
||||
fixed = providers.get("fixed_models", {})
|
||||
if "gigachat-classifier" in fixed:
|
||||
model_list.append(fixed_entry("gigachat-classifier", fixed["gigachat-classifier"]))
|
||||
|
||||
# Lane models from active profile
|
||||
lanes = profile.get("lanes", {})
|
||||
for name, spec in lanes.items():
|
||||
rpm = meta.get(name, {}).get("rpm")
|
||||
model_list.append(lane_entry(name, spec, rpm))
|
||||
|
||||
# Fixed models (Claude / OR fallbacks / GigaChat / optional free tiers)
|
||||
for name in (
|
||||
"novita-planner",
|
||||
"novita-verifier",
|
||||
"claude-haiku-planner",
|
||||
"claude-sonnet-verifier",
|
||||
"groq-llama-8b",
|
||||
"groq-qwen-coder",
|
||||
"gemini-flash",
|
||||
"grok-3",
|
||||
"gigachat-pro",
|
||||
):
|
||||
if name in fixed:
|
||||
model_list.append(fixed_entry(name, fixed[name]))
|
||||
|
||||
model_list.append(smart_router_internal(rules))
|
||||
|
||||
# smart-router alias (Zed default)
|
||||
sr = profile.get("smart_router", {})
|
||||
if sr:
|
||||
sr_params: dict = {
|
||||
"model": sr["model"],
|
||||
"api_key": api_key_ref(sr["api_key"]),
|
||||
}
|
||||
_apply_thinking(sr_params, sr)
|
||||
model_list.append({"model_name": "smart-router", "litellm_params": sr_params})
|
||||
|
||||
router = base.setdefault("router_settings", {})
|
||||
router["fallbacks"] = [
|
||||
{k: v for k, v in row.items()}
|
||||
for row in _fallback_list(profile.get("fallbacks", {}))
|
||||
]
|
||||
router["default_fallbacks"] = profile.get(
|
||||
"default_fallbacks", ["a-medium-code", "groq-qwen-coder"]
|
||||
)
|
||||
|
||||
out_cfg = {**base, "model_list": model_list}
|
||||
out_path = ROOT / "litellm_config.yaml"
|
||||
header = (
|
||||
f"# LiteLLM — generated for PRIMARY_PROVIDER={PROFILE}\n"
|
||||
f"# Profile: {profile.get('label', PROFILE)}\n"
|
||||
f"# Regenerate: PRIMARY_PROVIDER={PROFILE} bash scripts/gen-litellm-config.py\n\n"
|
||||
)
|
||||
body = yaml.dump(out_cfg, allow_unicode=True, sort_keys=False)
|
||||
out_path.write_text(header + body, encoding="utf-8")
|
||||
print(f"Wrote {out_path} (profile={PROFILE}, {len(model_list)} models)")
|
||||
return 0
|
||||
|
||||
|
||||
def _fallback_list(fallbacks: dict) -> list[dict]:
|
||||
return [{model: targets} for model, targets in fallbacks.items()]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user