Files
odysseus/tests/test_promote_image_fields.py
T

79 lines
2.9 KiB
Python

"""Unit tests for `_promote_image_fields` (PR #2809).
`generate_image` is a text-only MCP tool, so the saved image URL never reaches
the agent loop's structured forwarding (which renders the image via
`buildImageBubble` on `result["image_url"]`). `_promote_image_fields` lifts the
URL — plus prompt/model/size — out of the tool's stdout into structured fields so
the image renders deterministically, without relying on the model echoing the URL
into prose. These cases cover the absolute-URL, relative-URL, no-URL, and
non-success-exit paths.
"""
import asyncio
import src.tool_execution as tool_execution
from src.tool_execution import _promote_image_fields
def _result(stdout, exit_code=0):
return {"exit_code": exit_code, "stdout": stdout}
def test_absolute_url_promoted_with_fields():
"""An absolute https URL in stdout is lifted into image_url, along with the
prompt/model/size lines."""
r = _result(
"Generated image for: a red fox in snow\n"
"Direct link: https://odysseus.example.com/api/generated-image/abc123.png\n"
"model: qwen-image\n"
"size: 1024x1024"
)
_promote_image_fields(r)
assert r["image_url"] == "https://odysseus.example.com/api/generated-image/abc123.png"
assert r["image_prompt"] == "a red fox in snow"
assert r["image_model"] == "qwen-image"
assert r["image_size"] == "1024x1024"
def test_relative_url_promoted():
"""A relative /api/generated-image/... path (no host) is still matched."""
r = _result(
"Generated image for: a cat\n"
"Direct link: /api/generated-image/def456.png"
)
_promote_image_fields(r)
assert r["image_url"] == "/api/generated-image/def456.png"
assert r["image_prompt"] == "a cat"
def test_no_url_leaves_result_unchanged():
"""No generated-image URL anywhere -> no image_url key is added."""
r = _result("Generated image for: a dog\n(no link produced)")
_promote_image_fields(r)
assert "image_url" not in r
assert "image_prompt" not in r
def test_nonzero_exit_not_promoted():
"""A non-success result is never promoted, even if stdout contains a URL."""
r = _result("https://host/api/generated-image/zzz.png", exit_code=1)
_promote_image_fields(r)
assert "image_url" not in r
def test_mcp_text_error_is_normalized_as_failed_result(monkeypatch):
class FakeMcp:
async def call_tool(self, qualified, args):
return {
"stdout": "Error: No image model found. Configure one in Admin.",
"stderr": "",
"exit_code": 0,
}
monkeypatch.setattr(tool_execution, "get_mcp_manager", lambda: FakeMcp())
result = asyncio.run(tool_execution._call_mcp_tool("generate_image", "red mug"))
assert result["exit_code"] == 1
assert result["error"] == "No image model found. Configure one in Admin."
assert "image_url" not in result