Files
AstrBot/tests/test_deerflow_agent_runner.py
Weilong Liao 7c366a708b fix: unify media reference handling (#8764)
* fix: unify media reference handling

* fix: accept bare base64 record media refs

* chore: update agents.md

* fix: unify file URI handling across media components and utilities

* fix: unify media reference type handling with MediaRefStr alias

* Potential fix for pull request finding 'CodeQL / Incomplete URL substring sanitization'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Update astrbot/core/platform/sources/discord/discord_platform_adapter.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* fix: unify media handling and improve base64 decoding across components

* fix: simplify client_kwargs type definition and enhance media message handling in platform adapter

* fix: unify media utility documentation and enhance function descriptions

* perf: drop "pilk" requirement, improve audio outbound for tencent-related IM apps which using silk

* fix: unify Tencent Silk audio handling and enhance media resolver functionality

---

- Centralize media reference materialization and base64 resolution for local paths, http(s), base64://, data URIs, and legacy bare base64 payloads.
- Normalize incoming Record audio to wav and Image media to temporary jpg during preprocess, with event-scoped cleanup.
- Reuse the shared media resolver across OpenAI, Gemini, Anthropic, MiMo, DeerFlow, STT, and platform media paths while sanitizing logs and cleaning temporary conversion outputs.
- Ensure generated TTS audio is tracked for cleanup after the event finishes.

fix #8676
fix #8543
fix #7588
fix #7580
fix #8030
fix #8034
fix #7461
fix #7565
fix #6509
fix #7144
fix #7795



---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-06-14 10:37:16 +08:00

109 lines
3.2 KiB
Python

import base64
from io import BytesIO
import pytest
from PIL import Image as PILImage
from astrbot.core.agent.runners.deerflow.deerflow_agent_runner import (
DeerFlowAgentRunner,
)
from astrbot.core.agent.runners.deerflow.deerflow_content_mapper import (
build_user_content_resolved,
)
def _png_base64() -> str:
image_buffer = BytesIO()
PILImage.new("RGBA", (1, 1), (255, 0, 0, 255)).save(image_buffer, format="PNG")
return base64.b64encode(image_buffer.getvalue()).decode("ascii")
def test_build_payload_includes_configurable_runtime_overrides_and_legacy_context():
runner = DeerFlowAgentRunner()
runner.assistant_id = "lead_agent"
runner.thinking_enabled = True
runner.plan_mode = True
runner.subagent_enabled = True
runner.max_concurrent_subagents = 5
runner.model_name = "gpt-4.1"
runner.recursion_limit = 321
payload = runner._build_payload(
thread_id="thread-123",
prompt="hello deerflow",
image_urls=[],
system_prompt=None,
)
expected_runtime = {
"thread_id": "thread-123",
"thinking_enabled": True,
"is_plan_mode": True,
"subagent_enabled": True,
"max_concurrent_subagents": 5,
"model_name": "gpt-4.1",
}
assert payload["assistant_id"] == "lead_agent"
assert payload["stream_mode"] == ["values", "messages-tuple", "custom"]
assert payload["config"]["recursion_limit"] == 321
assert payload["config"]["configurable"] == expected_runtime
assert payload["context"] == expected_runtime
@pytest.mark.asyncio
async def test_build_user_content_resolved_supports_base64_scheme(
tmp_path, monkeypatch
):
monkeypatch.setattr(
"astrbot.core.utils.media_utils.get_astrbot_temp_path",
lambda: str(tmp_path),
)
image_base64 = _png_base64()
content = await build_user_content_resolved(
"look",
[f"base64://{image_base64}"],
)
assert content == [
{"type": "text", "text": "look"},
{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{image_base64}"},
},
]
assert not list(tmp_path.iterdir())
@pytest.mark.asyncio
async def test_build_payload_resolved_supports_local_image_path(tmp_path, monkeypatch):
monkeypatch.setattr(
"astrbot.core.utils.media_utils.get_astrbot_temp_path",
lambda: str(tmp_path),
)
image_path = tmp_path / "image.png"
image_base64 = _png_base64()
image_path.write_bytes(base64.b64decode(image_base64))
runner = DeerFlowAgentRunner()
runner.assistant_id = "lead_agent"
runner.thinking_enabled = False
runner.plan_mode = False
runner.subagent_enabled = False
runner.max_concurrent_subagents = 3
runner.model_name = ""
runner.recursion_limit = 1000
payload = await runner._build_payload_resolved(
thread_id="thread-123",
prompt="look",
image_urls=[str(image_path)],
system_prompt=None,
)
content = payload["input"]["messages"][-1]["content"]
assert content[0] == {"type": "text", "text": "look"}
assert content[1]["type"] == "image_url"
assert content[1]["image_url"]["url"] == f"data:image/png;base64,{image_base64}"