From 4c0d8ce3fe998c753bca00604cd42e70229cf8df Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 3 Oct 2026 10:34:04 +0200 Subject: [PATCH] =?UTF-8?q?feat(agent):=20Bild=20mit=20Text=20einblenden?= =?UTF-8?q?=20=E2=80=94=20host=5Fnotify=20kann=20jetzt=20image=5Fpath?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Android-Agent konnte schon immer ein Bild MIT Text einblenden (OverlayView.show nimmt ein imageB64), aber ARIA kam nicht dran: in der Parameter-Liste von host_notify fehlte das Feld einfach. Die Faehigkeit war gebaut und unerreichbar. ARIA gibt jetzt image_path an (ein Pfad unter /shared/uploads/, damit arbeitet sie sowieso) und das Brain wandelt die Datei nach base64 — statt ARIA megabyteweise base64 durch den Tool-Call schieben zu lassen. Pfad-Praefix wird geprueft, und ueber 4 MB wird abgelehnt: fuer eine Einblendung auf einem Fernseher ist mehr sinnlos und blaeht die WS-Nachricht auf. Nur Android-Agenten koennen das; die Beschreibung sagt das ausdruecklich. Co-Authored-By: Claude Opus 5 (1M context) --- aria-brain/agent.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/aria-brain/agent.py b/aria-brain/agent.py index b9a858d..9e5e3f9 100644 --- a/aria-brain/agent.py +++ b/aria-brain/agent.py @@ -1599,7 +1599,9 @@ META_TOOLS = [ "das NICHT ueber host_exec/adb (dort gibt es kein passendes Kommando). " "mode: 'overlay' (einblenden), 'speech' (vorlesen) oder 'both'; ohne " "Angabe gilt die Einstellung am Geraet. Braucht dort einmalig die " - "Berechtigung 'Ueber anderen Apps anzeigen'." + "Berechtigung 'Ueber anderen Apps anzeigen'. Mit image_path kann " + "ein BILD mit Text darueber eingeblendet werden (z.B. ein " + "generiertes Bild oder ein Screenshot) — nur bei Android-Agenten." ), "parameters": { "type": "object", @@ -1610,6 +1612,14 @@ META_TOOLS = [ "seconds": {"type": "integer", "description": "Anzeigedauer (Default 12)."}, "mode": {"type": "string", "description": "overlay | speech | both"}, "focus": {"type": "string", "description": "Bei Sprachausgabe: 'duck' (laufende Medien werden leiser, Standard) | 'pause' (Film/Musik anhalten) | 'none'."}, + "image_path": { + "type": "string", + "description": ( + "Optional: Pfad zu einem Bild (PNG/JPEG) unter " + "/shared/uploads/, das MIT dem Text eingeblendet wird. " + "Nur Android-Agenten koennen das." + ), + }, }, "required": ["host", "text"], }, @@ -3246,6 +3256,24 @@ class Agent: if name in _UI_ACTIONS: action, keys = _UI_ACTIONS[name] params = {k: arguments[k] for k in keys if arguments.get(k) is not None} + # Bild-Einblendung: ARIA gibt einen Pfad an (damit arbeitet sie + # sowieso), der Agent will base64. Hier umwandeln, statt ARIA + # megabyteweise base64 durch den Tool-Call schieben zu lassen. + img_path = (arguments.get("image_path") or "").strip() + if action == "notify" and img_path: + if not img_path.startswith("/shared/uploads/"): + return "FEHLER: image_path muss unter /shared/uploads/ liegen." + if not os.path.isfile(img_path): + return f"FEHLER: Bild nicht gefunden: {img_path}" + # Overlay-Bilder ueber ~4 MB sind sinnlos gross fuer einen + # Fernseher und blaehen die WS-Nachricht unnoetig auf. + _img_size = os.path.getsize(img_path) + if _img_size > 4 * 1024 * 1024: + return (f"FEHLER: Bild zu gross fuer eine Einblendung " + f"({_img_size // (1024 * 1024)} MB > 4 MB). " + f"Vorher verkleinern.") + with open(img_path, "rb") as _f: + params["image_base64"] = _b64.b64encode(_f.read()).decode("ascii") # Sprachausgabe braucht laenger: der Agent meldet erst Erfolg, # wenn wirklich Ton laeuft (TTS-Render + Uebertragung). Mit den # 20s der UI-Aktionen lief die ehrliche Antwort in den Timeout.