astra-vision/tests/test_tools.py
Jeuner 76a5d4e499 feat: show the ComfyUI job itself in the transcript, not just a status line
Ein Statustext über dem Orb war zu unauffällig. Ein Tool-Aufruf legt
jetzt eine eigene Karte im Gesprächsverlauf an, mit Spinner und dem
tatsächlichen Prompt, den das LLM an ComfyUI schickt ("Anfrage an
ComfyUI: ..."). Sobald das Bild fertig ist, wird dieselbe Karte
in-place durch das Ergebnis ersetzt statt eine zweite anzuhängen;
schlägt ComfyUI fehl, zeigt sie stattdessen die Fehlermeldung.

Der Prompt-Text landet über sichere DOM-Erstellung (createTextNode),
nicht per innerHTML, weil er vom LLM erzeugt und damit indirekt
nutzerbeeinflusst ist.

Per Browser-Test mit echter synthetisierter Sprache verifiziert: Karte
mit Spinner + Prompt erscheint sofort, wird sauber (kein Leerlauf-id im
DOM) durch das Bild ersetzt, gefolgt von Astras Textantwort.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVgSHNHdRx3UNTBodFmhRA
2026-09-07 16:48:17 +02:00

69 lines
2.3 KiB
Python

import pytest
import astra.tools as tools_module
from astra.comfyui import ComfyUIError
from astra.core import Settings
class FakeFunctionCallParams:
"""Stand-in for pipecat's FunctionCallParams: only what the handler touches."""
def __init__(self, arguments):
self.arguments = arguments
self.results = []
async def result_callback(self, result, *, properties=None):
self.results.append(result)
@pytest.mark.asyncio
async def test_generate_image_tool_stores_media_and_notifies(monkeypatch):
async def fake_generate_image(endpoint, prompt, **kwargs):
assert endpoint == "http://fake-comfyui"
assert prompt == "a cat"
return b"png-bytes"
monkeypatch.setattr(tools_module, "generate_image", fake_generate_image)
notifications = []
media_store: dict[str, bytes] = {}
schema = tools_module.build_tools(
Settings(comfyui_url="http://fake-comfyui"), notifications.append, media_store
).standard_tools[0]
params = FakeFunctionCallParams({"prompt": "a cat"})
await schema.handler(params)
assert len(media_store) == 1
image_id, image_bytes = next(iter(media_store.items()))
assert image_bytes == b"png-bytes"
assert [n["type"] for n in notifications] == ["activity", "tool_start", "image"]
assert "a cat" in notifications[1]["text"]
assert notifications[2] == {"type": "image", "url": f"/api/media/{image_id}"}
assert params.results[0]["status"] == "ok"
@pytest.mark.asyncio
async def test_generate_image_tool_reports_comfyui_errors_without_storing_media(monkeypatch):
async def failing_generate_image(endpoint, prompt, **kwargs):
raise ComfyUIError("ComfyUI ist nicht erreichbar.")
monkeypatch.setattr(tools_module, "generate_image", failing_generate_image)
notifications = []
media_store: dict[str, bytes] = {}
schema = tools_module.build_tools(
Settings(comfyui_url="http://fake-comfyui"), notifications.append, media_store
).standard_tools[0]
params = FakeFunctionCallParams({"prompt": "a cat"})
await schema.handler(params)
assert media_store == {}
assert "error" in params.results[0]
assert [n["type"] for n in notifications] == [
"activity",
"tool_start",
"activity",
"tool_error",
]