File size: 6,154 Bytes
7ab5aee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import unittest

from app.agents.browser_decision import _fallback_browser_decision
from app.agents.browser_tools import (
    _normalize_points,
    execute_browser_tool_call,
    parse_browser_json_response,
)
from app.agents.graph.state import AgentState
from app.agents.llm_client import _parse_openrouter_responses_api
from app.agents.tooling import ToolCall, tool


@tool(description="Add two numbers together")
def add_numbers(left: int, right: int, note: str = "") -> dict:
    return {"sum": left + right, "note": note}


class ToolingTests(unittest.TestCase):
    def test_tool_schema_marks_required_and_optional_fields(self):
        schema = add_numbers.schema
        self.assertEqual(schema.name, "add_numbers")
        self.assertEqual(schema.parameters["required"], ["left", "right"])
        self.assertEqual(schema.parameters["properties"]["note"]["type"], "string")
        self.assertEqual(schema.parameters["properties"]["left"]["type"], "integer")

    def test_execute_browser_tool_call_normalizes_search_decision(self):
        result = execute_browser_tool_call(
            ToolCall(
                id="call_search",
                name="search_web",
                arguments={
                    "query": "latest groq models",
                    "reason": "current page lacks the answer",
                    "known_facts": ["Groq exposes an OpenAI-compatible API"],
                },
            )
        )

        self.assertEqual(result["action"], "SEARCH")
        self.assertEqual(result["value"], "latest groq models")
        self.assertEqual(result["reason"], "current page lacks the answer")
        self.assertEqual(result["known_facts"], ["Groq exposes an OpenAI-compatible API"])

    def test_parse_browser_json_response_maps_legacy_fields(self):
        parsed = parse_browser_json_response(
            """
            {
              "action": "navigate",
              "url": "https://example.com/page",
              "reason": "This looks like the source page",
              "missing_points": ["exact launch date"]
            }
            """
        )

        self.assertEqual(parsed["action"], "NAVIGATE")
        self.assertEqual(parsed["value"], "https://example.com/page")
        self.assertEqual(parsed["reason"], "This looks like the source page")
        self.assertEqual(parsed["missing_points"], ["exact launch date"])

    def test_parse_browser_json_response_rejects_scroll_when_mode_disallows_it(self):
        with self.assertRaises(ValueError) as ctx:
            parse_browser_json_response('{"action":"scroll"}', allow_scroll=False)

        self.assertIn("SCROLL", str(ctx.exception))

    def test_normalize_points_treats_plain_string_as_single_item(self):
        self.assertEqual(
            _normalize_points("trump age still missing"),
            ["trump age still missing"],
        )

    def test_agent_state_update_research_progress_does_not_split_string_into_chars(self):
        state = AgentState(task="qual idade do trump?")
        state.update_research_progress(missing_points="trump age still missing")

        self.assertEqual(state.missing_points, ["trump age still missing"])

    def test_fallback_browser_decision_does_not_leak_reasoning_as_done(self):
        decision = _fallback_browser_decision(
            task="qual idade do trump?",
            current_url="https://en.wikipedia.org/wiki/Donald_Trump",
            blocked=False,
            allow_scroll=True,
            links=[],
            raw_text="We are on the Wikipedia page and should think step by step...",
        )

        self.assertNotEqual(decision["action"], "DONE")
        self.assertEqual(decision["action"], "SCROLL")

    def test_fallback_browser_decision_uses_unseen_link_when_available(self):
        decision = _fallback_browser_decision(
            task="qual idade do trump?",
            current_url="https://html.duckduckgo.com/html/?q=qual+idade+do+trump",
            blocked=False,
            allow_scroll=False,
            links=["https://en.wikipedia.org/wiki/Donald_Trump"],
            raw_text="Let us think carefully first...",
        )

        self.assertEqual(decision["action"], "NAVIGATE")
        self.assertEqual(decision["value"], "https://en.wikipedia.org/wiki/Donald_Trump")

    def test_parse_openrouter_responses_api_separates_reasoning_from_content_and_tools(self):
        parsed = _parse_openrouter_responses_api(
            {
                "model": "nvidia/nemotron-3-super-120b-a12b:free",
                "status": "completed",
                "output": [
                    {
                        "type": "reasoning",
                        "summary": [
                            "Need the current age",
                            "Should inspect the canonical page first",
                        ],
                    },
                    {
                        "type": "function_call",
                        "id": "fc_1",
                        "call_id": "call_1",
                        "name": "navigate_to_url",
                        "arguments": "{\"url\":\"https://en.wikipedia.org/wiki/Donald_Trump\"}",
                    },
                    {
                        "type": "message",
                        "role": "assistant",
                        "content": [
                            {
                                "type": "output_text",
                                "text": "Vou abrir a página principal.",
                            }
                        ],
                    },
                ],
            }
        )

        self.assertEqual(parsed.reasoning, [
            "Need the current age",
            "Should inspect the canonical page first",
        ])
        self.assertEqual(parsed.content, "Vou abrir a página principal.")
        self.assertEqual(len(parsed.tool_calls), 1)
        self.assertEqual(parsed.tool_calls[0].name, "navigate_to_url")
        self.assertEqual(
            parsed.tool_calls[0].arguments,
            {"url": "https://en.wikipedia.org/wiki/Donald_Trump"},
        )


if __name__ == "__main__":
    unittest.main()