mindXtrain / tests /test_agent_loop.py
Gregory-L's picture
fork mindXtrain from GitHub (Professor-Codephreak/mindXtrain@661bd41) as the mindX-specific line
dfb775d verified
Raw
History Blame Contribute Delete
2.13 kB
"""Bounded ReAct loop + doom-loop detector."""
from __future__ import annotations
import pytest
from mindxtrain.operator.agent_loop import (
AgentLoopConfig,
DoomLoopDetected,
run_agent_loop,
trajectory_summary,
)
@pytest.mark.asyncio
async def test_loop_terminates_on_no_tool_calls():
async def chat(messages):
return {"role": "assistant", "content": "done"}
out = await run_agent_loop(chat, [{"role": "user", "content": "hi"}])
assert out[-1]["content"] == "done"
@pytest.mark.asyncio
async def test_loop_doom_detected_on_repeat():
call_count = {"n": 0}
async def chat(messages):
call_count["n"] += 1
return {
"role": "assistant",
"content": "",
"tool_calls": [{"function": {"name": "noop", "arguments": "{}"}}],
}
with pytest.raises(DoomLoopDetected):
await run_agent_loop(
chat,
[{"role": "user", "content": "x"}],
AgentLoopConfig(max_steps=10, repeat_threshold=3),
)
assert call_count["n"] == 3
@pytest.mark.asyncio
async def test_loop_max_steps_exhausted():
async def chat(messages):
# Different tool every step → no doom detection, but eventually max_steps.
n = len([m for m in messages if m.get("role") == "assistant"])
return {
"role": "assistant",
"content": "",
"tool_calls": [{"function": {"name": f"t{n}", "arguments": "{}"}}],
}
with pytest.raises(RuntimeError, match="max_steps"):
await run_agent_loop(chat, [{"role": "user", "content": "x"}], AgentLoopConfig(max_steps=4))
def test_trajectory_summary_counts_roles():
msgs = [
{"role": "system", "content": "s"},
{"role": "user", "content": "u"},
{"role": "assistant", "content": "", "tool_calls": [{"function": {"name": "t", "arguments": "{}"}}]},
{"role": "tool", "content": "r"},
{"role": "assistant", "content": "ok"},
]
s = trajectory_summary(msgs)
assert s["assistant"] == 2
assert s["tool"] == 1
assert s["tool_calls"] == 1