from __future__ import annotations import pytest from app.llm.base import ProviderError, parse_openai_choice def test_parse_valid_tool_call(): data = {"choices": [{"message": {"content": None, "tool_calls": [ {"id": "1", "function": {"name": "search_products", "arguments": '{"query": "hose"}'}} ]}, "finish_reason": "tool_calls"}]} res = parse_openai_choice(data) assert res.tool_calls[0].name == "search_products" assert res.tool_calls[0].arguments == {"query": "hose"} def test_empty_string_args_become_empty_dict(): data = {"choices": [{"message": {"tool_calls": [ {"id": "1", "function": {"name": "reorder", "arguments": " "}} ]}}]} assert parse_openai_choice(data).tool_calls[0].arguments == {} def test_malformed_tool_args_raise_to_failover(): # a weak model emitted invalid JSON for a required-arg tool — must NOT be # silently dispatched with {}; raise so the router fails over. data = {"choices": [{"message": {"tool_calls": [ {"id": "1", "function": {"name": "lookup_order", "arguments": "{email: not json"}} ]}}]} with pytest.raises(ProviderError): parse_openai_choice(data) def test_plain_text_answer_parsed(): data = {"choices": [{"message": {"content": "hello"}, "finish_reason": "stop"}], "usage": {"total_tokens": 5}} res = parse_openai_choice(data) assert res.content == "hello" assert res.usage["total_tokens"] == 5