Gateway: Deutsch-Direktive fuer IDE-Traffic + web_search-Tool im Web-MCP
1) /v1-Gateway haengt an jede Chat-Anfrage (ausser hermes/Lucy — SOUL.md regelt das selbst) eine System-Direktive an: Antworten auf Deutsch, Code/Bezeichner unveraendert. Abschaltbar via MC_GATEWAY_LANG_DIRECTIVE="". 2) mcp_web.py: neues Tool web_search (ddgs/DuckDuckGo, kein Key), Ergebnis injection-geschuetzt via wrap_untrusted. Damit koennen IDE-Agents (Zed via context_servers) und Hermes im Web suchen; Debug-Log geht auf stderr, stdout bleibt MCP-sauber (verifiziert). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, Request
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
@@ -9,6 +11,32 @@ from services.routing_policy import load_policy
|
||||
|
||||
router = APIRouter(prefix="/v1")
|
||||
|
||||
# Antwortsprache für IDE-/Lane-Traffic: die Coding-Modelle antworten sonst englisch
|
||||
# (User-Anforderung 03.07.2026). Leerer String (MC_GATEWAY_LANG_DIRECTIVE="") schaltet ab.
|
||||
_LANG_DIRECTIVE = os.environ.get(
|
||||
"MC_GATEWAY_LANG_DIRECTIVE",
|
||||
"Antworte dem Nutzer grundsätzlich auf Deutsch (Erklärungen, Pläne, Rückfragen, "
|
||||
"Zusammenfassungen) — auch wenn die Frage oder Tool-Anweisungen englisch sind. "
|
||||
"Quellcode, Bezeichner und Shell-Befehle bleiben unverändert.")
|
||||
|
||||
|
||||
def _inject_language(body: dict, alias: str) -> None:
|
||||
"""Deutsch-Direktive anhängen. An die ERSTE System-Message (viele Chat-Templates
|
||||
erwarten nur eine), sonst als neue System-Message. `hermes` ausgenommen — Lucys
|
||||
Persona (SOUL.md) regelt die Sprache selbst."""
|
||||
if not _LANG_DIRECTIVE or alias == "hermes":
|
||||
return
|
||||
msgs = body.get("messages")
|
||||
if not isinstance(msgs, list):
|
||||
return
|
||||
first_sys = next((m for m in msgs if isinstance(m, dict) and m.get("role") == "system"), None)
|
||||
if first_sys is None:
|
||||
msgs.insert(0, {"role": "system", "content": _LANG_DIRECTIVE})
|
||||
elif isinstance(first_sys.get("content"), str):
|
||||
first_sys["content"] = first_sys["content"].rstrip() + "\n\n" + _LANG_DIRECTIVE
|
||||
elif isinstance(first_sys.get("content"), list):
|
||||
first_sys["content"].append({"type": "text", "text": _LANG_DIRECTIVE})
|
||||
|
||||
# Virtuelle Lanes, die der Gateway zusätzlich zu den echten Modellen als „Modell" anbietet.
|
||||
_LANE_LABELS = {"coding": "Coding (Router → coder/heavy/fast)", "chat": "Chat (Router → fast/heavy)"}
|
||||
|
||||
@@ -66,6 +94,7 @@ async def _proxy(path: str, request: Request):
|
||||
pol = load_policy()
|
||||
if pol["fast_no_think"] and alias == pol["fast"] and "chat_template_kwargs" not in body:
|
||||
body["chat_template_kwargs"] = {"enable_thinking": False}
|
||||
_inject_language(body, alias)
|
||||
url = f"{LLAMA_SWAP_URL}{path}"
|
||||
|
||||
if body.get("stream"):
|
||||
|
||||
@@ -60,6 +60,24 @@ def fetch_url(url: str, max_chars: int = 8000) -> str:
|
||||
return f"FEHLER: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def web_search(query: str, max_results: int = 6) -> str:
|
||||
"""Websuche (DuckDuckGo, kein API-Key). Liefert Titel, URL und Kurzbeschreibung je
|
||||
Treffer. Nutze dies für aktuelle Informationen, Dokumentation oder Fehlermeldungen —
|
||||
und lies vielversprechende Treffer danach mit fetch_url im Volltext."""
|
||||
try:
|
||||
from ddgs import DDGS
|
||||
|
||||
rows = list(DDGS().text(query, max_results=max_results) or [])
|
||||
if not rows:
|
||||
return "Keine Treffer."
|
||||
lines = [f"- {r.get('title', '(ohne Titel)')}\n {r.get('href', '')}\n {r.get('body', '')}"
|
||||
for r in rows]
|
||||
return wrap_untrusted("\n".join(lines), label=f"WEBSUCHE {query}")
|
||||
except Exception as e:
|
||||
return f"FEHLER: {e}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def fetch_urls(urls: list[str], max_chars_each: int = 4000) -> str:
|
||||
"""Lädt mehrere URLs gleichzeitig und gibt die Texte zurück.
|
||||
|
||||
Reference in New Issue
Block a user