/ tests / test_agent2_react_prompt.py
test_agent2_react_prompt.py
  1  """Tests for restai.agent2.react_prompt — ReAct parser and prompt builder."""
  2  from restai.agent2.react_prompt import (
  3      build_react_system_prompt,
  4      format_tool_for_react,
  5      parse_react_response,
  6  )
  7  from restai.agent2.tool_adapter import AdaptedTool
  8  
  9  
 10  def _make_tool(name: str, description: str = "", schema: dict | None = None) -> AdaptedTool:
 11      return AdaptedTool(
 12          name=name,
 13          description=description or f"Tool {name}",
 14          input_schema=schema or {"type": "object", "properties": {"q": {"type": "string"}}, "required": ["q"]},
 15          fn=lambda **kw: "ok",
 16      )
 17  
 18  
 19  # ---------- parse_react_response ----------
 20  
 21  
 22  def test_parse_action_basic():
 23      text = 'Thought: think\nAction: search\nAction Input: {"q": "hello"}'
 24      result = parse_react_response(text)
 25      assert result.kind == "action"
 26      assert result.thought == "think"
 27      assert result.action_name == "search"
 28      assert result.action_input == {"q": "hello"}
 29  
 30  
 31  def test_parse_action_fenced_json():
 32      text = (
 33          "Thought: ok\n"
 34          "Action: foo\n"
 35          "Action Input:\n"
 36          "```json\n"
 37          '{"x": 1}\n'
 38          "```"
 39      )
 40      result = parse_react_response(text)
 41      assert result.kind == "action"
 42      assert result.action_name == "foo"
 43      assert result.action_input == {"x": 1}
 44  
 45  
 46  def test_parse_final_answer():
 47      text = "Thought: done\nFinal Answer: 42"
 48      result = parse_react_response(text)
 49      assert result.kind == "final"
 50      assert result.thought == "done"
 51      assert result.final_text == "42"
 52  
 53  
 54  def test_parse_plain_text():
 55      text = "Just some text without structure"
 56      result = parse_react_response(text)
 57      assert result.kind == "text"
 58      assert result.final_text == text.strip()
 59  
 60  
 61  def test_parse_action_wins_over_final():
 62      text = "Thought: x\nAction: tool\nAction Input: {}\nFinal Answer: done"
 63      result = parse_react_response(text)
 64      assert result.kind == "action"
 65      assert result.action_name == "tool"
 66  
 67  
 68  def test_parse_action_no_action_input():
 69      text = "Action: bar"
 70      result = parse_react_response(text)
 71      assert result.kind == "action"
 72      assert result.action_name == "bar"
 73      assert result.action_input == {}
 74  
 75  
 76  # ---------- build_react_system_prompt ----------
 77  
 78  
 79  def test_build_react_system_prompt_with_tools():
 80      tools = [_make_tool("search", "Search the web"), _make_tool("calc", "Calculate")]
 81      prompt = build_react_system_prompt("You are helpful.", tools)
 82      assert "search" in prompt
 83      assert "calc" in prompt
 84      assert "You are helpful." in prompt
 85      assert "Action:" in prompt
 86      assert "Final Answer:" in prompt
 87  
 88  
 89  def test_build_react_system_prompt_empty_tools():
 90      prompt = build_react_system_prompt("You are helpful.", [])
 91      assert "You have no tools available" in prompt
 92      assert "Final Answer:" in prompt
 93  
 94  
 95  def test_build_react_system_prompt_default_base():
 96      prompt = build_react_system_prompt("", [_make_tool("x")])
 97      assert "You are a helpful assistant." in prompt
 98  
 99  
100  # ---------- format_tool_for_react ----------
101  
102  
103  def test_format_tool_for_react_output():
104      tool = _make_tool(
105          "search",
106          "Search the web",
107          {
108              "type": "object",
109              "properties": {"q": {"type": "string"}, "limit": {"type": "integer"}},
110              "required": ["q"],
111          },
112      )
113      output = format_tool_for_react(tool)
114      assert "search" in output
115      assert "Search the web" in output
116      assert "q:" in output
117      assert "limit?" in output  # optional param has ?
118  
119  
120  def test_format_tool_for_react_no_params():
121      tool = AdaptedTool(
122          name="noop",
123          description="Does nothing",
124          input_schema={"type": "object", "properties": {}, "required": []},
125          fn=lambda: "ok",
126      )
127      output = format_tool_for_react(tool)
128      assert "no arguments" in output