feat: OpenAI-compatible orchestrator + backend auto-routing
- openai_orchestrator.py — new ReAct tool loop engine for any OpenAI-compatible endpoint (OpenRouter, Open WebUI, Ollama, LiteLLM); model handles both tool loop and final response, no Claude handoff needed - tools/__init__.py — auto-derive OpenAI JSON Schema from existing Gemini FunctionDeclarations so tool definitions have a single source of truth - routers/orchestrator.py — route to openai_orchestrator when model registry "orchestrator" role resolves to a local_openai type host - routers/chat.py — pass role to _backend_label(); fix fallback_used logic (only meaningful for explicit backend overrides, not auto-routing) - static/app.js — add null/"auto" to backend cycle; fetch local model hint without overriding the auto default on page load - model_registry.py — _normalize() back-fills host_type on old registry files - requirements.txt — add openai>=1.0.0 - ARCH__BACKENDS.md — document OpenAI-compat backend and routing logic Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -122,13 +122,20 @@ def _empty() -> dict:
|
||||
return {"version": 1, "hosts": [], "models": [], "roles": {}}
|
||||
|
||||
|
||||
def _normalize(data: dict) -> dict:
|
||||
"""Back-fill any missing fields introduced by schema additions."""
|
||||
for h in data.get("hosts", []):
|
||||
h.setdefault("host_type", "openwebui")
|
||||
return data
|
||||
|
||||
|
||||
def _load(username: str) -> dict:
|
||||
path = _registry_path(username)
|
||||
if path.exists():
|
||||
try:
|
||||
data = json.loads(path.read_text())
|
||||
if isinstance(data, dict) and "version" in data:
|
||||
return data
|
||||
return _normalize(data)
|
||||
except (json.JSONDecodeError, OSError):
|
||||
logger.warning("model_registry.json for %s is unreadable — starting fresh", username)
|
||||
return _empty()
|
||||
|
||||
Reference in New Issue
Block a user