Skip to content

Commit aa80df7

Browse files
committed
test(agent): cover tool call streak argument changes
1 parent 68a3c7f commit aa80df7

1 file changed

Lines changed: 65 additions & 4 deletions

File tree

tests/test_tool_loop_agent_runner.py

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,10 @@ async def text_chat(self, **kwargs) -> LLMResponse:
261261

262262

263263
class SequentialToolProvider(MockProvider):
264-
def __init__(self, tool_sequence: list[str]):
264+
def __init__(self, tool_sequence: list[str], *, same_args: bool = False):
265265
super().__init__()
266266
self.tool_sequence = tool_sequence
267+
self.same_args = same_args
267268

268269
async def text_chat(self, **kwargs) -> LLMResponse:
269270
self.call_count += 1
@@ -276,11 +277,16 @@ async def text_chat(self, **kwargs) -> LLMResponse:
276277
)
277278

278279
tool_name = self.tool_sequence[self.call_count - 1]
280+
tool_args = (
281+
{"query": "same"}
282+
if self.same_args
283+
else {"query": f"step-{self.call_count}"}
284+
)
279285
return LLMResponse(
280286
role="assistant",
281287
completion_text="",
282288
tools_call_name=[tool_name],
283-
tools_call_args=[{"query": f"step-{self.call_count}"}],
289+
tools_call_args=[tool_args],
284290
tools_call_ids=[f"call_{self.call_count}"],
285291
usage=TokenUsage(input_other=10, output=5),
286292
)
@@ -734,7 +740,7 @@ async def test_same_tool_consecutive_results_include_escalating_guidance(
734740
):
735741
runner_cls = type(runner)
736742
total_calls = runner_cls.REPEATED_TOOL_NOTICE_L3_THRESHOLD
737-
provider = SequentialToolProvider(["test_tool"] * total_calls)
743+
provider = SequentialToolProvider(["test_tool"] * total_calls, same_args=True)
738744
tool = FunctionTool(
739745
name="test_tool",
740746
description="测试工具",
@@ -797,14 +803,69 @@ async def test_same_tool_consecutive_results_include_escalating_guidance(
797803
assert level_3_notice in content
798804

799805

806+
@pytest.mark.asyncio
807+
async def test_same_tool_streak_resets_when_arguments_change(
808+
runner, mock_tool_executor, mock_hooks
809+
):
810+
runner_cls = type(runner)
811+
total_calls = runner_cls.REPEATED_TOOL_NOTICE_L3_THRESHOLD
812+
provider = SequentialToolProvider(["test_tool"] * total_calls)
813+
tool = FunctionTool(
814+
name="test_tool",
815+
description="测试工具",
816+
parameters={"type": "object", "properties": {"query": {"type": "string"}}},
817+
handler=AsyncMock(),
818+
)
819+
request = ProviderRequest(
820+
prompt="请连续执行不同参数的工具",
821+
func_tool=ToolSet(tools=[tool]),
822+
contexts=[],
823+
)
824+
825+
await runner.reset(
826+
provider=provider,
827+
request=request,
828+
run_context=ContextWrapper(context=None),
829+
tool_executor=mock_tool_executor,
830+
agent_hooks=mock_hooks,
831+
streaming=False,
832+
)
833+
834+
async for _ in runner.step_until_done(total_calls + 1):
835+
pass
836+
837+
tool_messages = [
838+
m for m in runner.run_context.messages if getattr(m, "role", None) == "tool"
839+
]
840+
assert len(tool_messages) == total_calls
841+
842+
tool_contents = [str(message.content) for message in tool_messages]
843+
notices = [
844+
runner_cls.REPEATED_TOOL_NOTICE_L1_TEMPLATE.format(
845+
tool_name="test_tool",
846+
streak=runner_cls.REPEATED_TOOL_NOTICE_L1_THRESHOLD,
847+
),
848+
runner_cls.REPEATED_TOOL_NOTICE_L2_TEMPLATE.format(
849+
tool_name="test_tool",
850+
streak=runner_cls.REPEATED_TOOL_NOTICE_L2_THRESHOLD,
851+
),
852+
runner_cls.REPEATED_TOOL_NOTICE_L3_TEMPLATE.format(
853+
tool_name="test_tool",
854+
streak=runner_cls.REPEATED_TOOL_NOTICE_L3_THRESHOLD,
855+
),
856+
]
857+
assert all(notice not in content for content in tool_contents for notice in notices)
858+
859+
800860
@pytest.mark.asyncio
801861
async def test_same_tool_streak_resets_after_switching_tools(
802862
runner, mock_tool_executor, mock_hooks
803863
):
804864
runner_cls = type(runner)
805865
repeated_after_reset = runner_cls.REPEATED_TOOL_NOTICE_L1_THRESHOLD
806866
provider = SequentialToolProvider(
807-
["test_tool", "other_tool", *(["test_tool"] * repeated_after_reset)]
867+
["test_tool", "other_tool", *(["test_tool"] * repeated_after_reset)],
868+
same_args=True,
808869
)
809870
tool_a = FunctionTool(
810871
name="test_tool",

0 commit comments

Comments
 (0)