Faden 11: Gateway-Bild-Weiche - Requests mit Bild automatisch an VL-30B
Entscheid Weg A (vision-harness-verdikt): das MTP-Hirn (fast/hermes) bleibt
schnell und bildunfaehig; Bild-Requests routet das MC2-Gateway automatisch ans
Vision-Modell - kein manueller Modellwechsel, Lucys Flow bleibt.
router_logic.py: has_image(body) erkennt OpenAI-multimodalen content
(image_url/input_image/image); _text_of zieht jetzt nur Text-Parts fuer das
Komplexitaets-Routing (str() einer content-Liste haette die Zeichen-Schwelle
verfaelscht). VISION_CAPABLE = {vision, scout}.
routing_policy.py: neues UI-editierbares vision-Alias (Default env MC_ROUTE_VISION
= "vision"; leer = Weiche aus), darf wie coder_lite leer sein.
gateway_proxy.py _proxy: nach der Alias-Wahl - wenn ein Bild dabei ist und das
Ziel nicht bildfaehig - Override auf das vision-Alias (auch bei explizitem
model=hermes; genau Lucys Fall). Header x-mc-route-reason.
Verifiziert (Unit): Bild+hermes->vision, Bild+auto->vision, Text->fast,
Bild+scout->scout (schon bildfaehig), has_image korrekt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -50,9 +50,41 @@ _CODE_HINT = re.compile(
|
||||
)
|
||||
|
||||
|
||||
# Bild-Weiche (Faden 11): Aliase, die selbst Bilder koennen — die werden NIE umgeroutet.
|
||||
VISION_CAPABLE = {"vision", "scout"}
|
||||
_IMAGE_PART_TYPES = {"image_url", "input_image", "image"}
|
||||
|
||||
|
||||
def has_image(body: dict) -> bool:
|
||||
"""True, wenn irgendeine Nachricht einen Bild-Part enthaelt (OpenAI-multimodaler
|
||||
content: eine Liste mit einem {"type": "image_url"|"input_image"|"image", ...}-Teil)."""
|
||||
for m in body.get("messages") or []:
|
||||
if not isinstance(m, dict):
|
||||
continue
|
||||
content = m.get("content")
|
||||
if isinstance(content, list):
|
||||
for part in content:
|
||||
if isinstance(part, dict) and part.get("type") in _IMAGE_PART_TYPES:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _text_of(body: dict) -> str:
|
||||
msgs = body.get("messages") or []
|
||||
return "\n".join(str(m.get("content") or "") for m in msgs)
|
||||
# Multimodaler content ist eine Liste — nur die Text-Parts fuers Komplexitaets-Routing
|
||||
# zusammenziehen (ein dict/Liste als str() wuerde die Zeichen-Schwelle verfaelschen).
|
||||
out = []
|
||||
for m in msgs:
|
||||
if not isinstance(m, dict):
|
||||
continue
|
||||
c = m.get("content")
|
||||
if isinstance(c, str):
|
||||
out.append(c)
|
||||
elif isinstance(c, list):
|
||||
for part in c:
|
||||
if isinstance(part, dict) and part.get("type") == "text":
|
||||
out.append(str(part.get("text") or ""))
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def _route_chat(text: str, n: int) -> tuple[str, str]:
|
||||
|
||||
Reference in New Issue
Block a user