mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-18 18:10:37 +08:00
fix: handle webchat image outputs without streaming
This commit is contained in:
@@ -11,6 +11,9 @@ from astrbot.core.agent.hooks import BaseAgentRunHooks
|
||||
from astrbot.core.agent.run_context import ContextWrapper
|
||||
from astrbot.core.agent.runners.tool_loop_agent_runner import ToolLoopAgentRunner
|
||||
from astrbot.core.agent.tool import FunctionTool, ToolSet
|
||||
from astrbot.core.astr_agent_run_util import run_agent
|
||||
from astrbot.core.message.components import Image
|
||||
from astrbot.core.message.message_event_result import MessageChain
|
||||
from astrbot.core.provider.entities import LLMResponse, ProviderRequest, TokenUsage
|
||||
from astrbot.core.provider.provider import Provider
|
||||
|
||||
@@ -127,6 +130,26 @@ class MockAbortableStreamProvider(MockProvider):
|
||||
)
|
||||
|
||||
|
||||
class MockFinalMediaStreamProvider(MockProvider):
|
||||
async def text_chat_stream(self, **kwargs):
|
||||
yield LLMResponse(
|
||||
role="assistant",
|
||||
is_chunk=True,
|
||||
result_chain=MessageChain().message("draft "),
|
||||
)
|
||||
yield LLMResponse(
|
||||
role="assistant",
|
||||
is_chunk=False,
|
||||
result_chain=MessageChain(
|
||||
chain=[
|
||||
Image.fromBase64(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+a7d4AAAAASUVORK5CYII="
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class MockHooks(BaseAgentRunHooks):
|
||||
"""模拟钩子函数"""
|
||||
|
||||
@@ -466,6 +489,41 @@ async def test_stop_signal_returns_aborted_and_persists_partial_message(
|
||||
assert runner.run_context.messages[-1].role == "assistant"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_agent_emits_final_media_chain_in_streaming_mode(
|
||||
runner, provider_request, mock_tool_executor, mock_hooks
|
||||
):
|
||||
provider = MockFinalMediaStreamProvider()
|
||||
mock_event = MockEvent("test:FriendMessage:stream_media", "u1")
|
||||
mock_event.is_stopped = lambda: False
|
||||
mock_event.get_extra = lambda *args, **kwargs: None
|
||||
mock_event.set_extra = lambda *args, **kwargs: None
|
||||
mock_event.get_platform_id = lambda: "webchat"
|
||||
mock_event.get_platform_name = lambda: "webchat"
|
||||
mock_event.send = AsyncMock()
|
||||
mock_event.trace = AsyncMock()
|
||||
mock_event.trace.record = lambda *args, **kwargs: None
|
||||
run_context = ContextWrapper(context=MockAgentContext(mock_event))
|
||||
|
||||
await runner.reset(
|
||||
provider=provider,
|
||||
request=provider_request,
|
||||
run_context=run_context,
|
||||
tool_executor=mock_tool_executor,
|
||||
agent_hooks=mock_hooks,
|
||||
streaming=True,
|
||||
)
|
||||
|
||||
emitted = []
|
||||
async for chain in run_agent(runner, max_step=5):
|
||||
if chain is not None:
|
||||
emitted.append(chain)
|
||||
|
||||
assert any(
|
||||
any(isinstance(comp, Image) for comp in chain.chain) for chain in emitted
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tool_result_injects_follow_up_notice(
|
||||
runner, mock_provider, provider_request, mock_tool_executor, mock_hooks
|
||||
|
||||
Reference in New Issue
Block a user