From bfde49db9af228ea33a829a6a17e190fe43cfe9f Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Fri, 23 Oct 2026 23:55:42 -0400 Subject: [PATCH] fix(dashscope): keep steering text sent alongside tool results --- models/dashscope/dashscope_bot.py | 7 ++++ ...st_dashscope_steering_with_tool_results.py | 41 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/test_dashscope_steering_with_tool_results.py diff --git a/models/dashscope/dashscope_bot.py b/models/dashscope/dashscope_bot.py index 19c1c2bf..d0370d7c 100644 --- a/models/dashscope/dashscope_bot.py +++ b/models/dashscope/dashscope_bot.py @@ -661,6 +661,7 @@ class DashscopeBot(Bot): # Check if this is a tool result message (user role with tool_result blocks) if role == "user" and any(block.get("type") == "tool_result" for block in content): # Convert each tool_result block to a separate tool message + text_parts = [] for block in content: if block.get("type") == "tool_result": dashscope_messages.append({ @@ -668,6 +669,12 @@ class DashscopeBot(Bot): "content": block.get("content", ""), "tool_call_id": block.get("tool_use_id") # DashScope uses 'tool_call_id' }) + elif block.get("type") == "text": + text_parts.append(block.get("text", "")) + # Text next to tool results (e.g. a steering message sent + # while tools ran) follows them as a user message. + if text_parts: + dashscope_messages.append({"role": "user", "content": "\n".join(text_parts)}) # Check if this is an assistant message with tool_use blocks elif role == "assistant": diff --git a/tests/test_dashscope_steering_with_tool_results.py b/tests/test_dashscope_steering_with_tool_results.py new file mode 100644 index 00000000..0d34c15c --- /dev/null +++ b/tests/test_dashscope_steering_with_tool_results.py @@ -0,0 +1,41 @@ +"""A steer that lands while tools run shares the user message with the +tool_result blocks (AgentStreamExecutor._append_steering). The DashScope converter +must keep that text instead of forwarding only the tool results.""" +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) + + +def _steered_tool_result_message(): + from agent.protocol.agent_stream import AgentStreamExecutor + + executor = AgentStreamExecutor.__new__(AgentStreamExecutor) + executor._emit_event = lambda *a, **kw: None + blocks = [{"type": "tool_result", "tool_use_id": "call_1", "content": "file listing"}] + executor._append_steering( + ["Stop and summarise what you found so far"], + pending_tool_calls=[{"id": "call_2", "name": "bash", "arguments": {}}], + content_blocks=blocks, + ) + return {"role": "user", "content": blocks} + + +def test_steering_text_next_to_tool_results_reaches_qwen(): + from models.dashscope.dashscope_bot import DashscopeBot + + bot = DashscopeBot.__new__(DashscopeBot) + history = [ + {"role": "user", "content": "look around"}, + {"role": "assistant", "content": [ + {"type": "tool_use", "id": "call_1", "name": "ls", "input": {}}, + {"type": "tool_use", "id": "call_2", "name": "bash", "input": {}}, + ]}, + _steered_tool_result_message(), + ] + + converted = bot._convert_messages_to_dashscope_format(history) + + assert [m["role"] for m in converted] == ["user", "assistant", "tool", "tool", "user"] + assert [m["tool_call_id"] for m in converted[2:4]] == ["call_1", "call_2"] + assert "Stop and summarise what you found so far" in converted[-1]["content"]