forked from Rockachopa/Timmy-time-dashboard
This commit is contained in:
@@ -885,3 +885,98 @@ async def test_call_agent_does_not_use_session_chat(tmp_path):
|
||||
await engine._call_agent("prompt")
|
||||
|
||||
mock_session_chat.assert_not_awaited()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_call_agent_strips_think_tags(tmp_path):
|
||||
"""_call_agent must strip <think> tags from reasoning models like qwen3."""
|
||||
engine = _make_engine(tmp_path)
|
||||
|
||||
mock_agent = AsyncMock()
|
||||
mock_run = AsyncMock()
|
||||
mock_run.content = (
|
||||
"<think>Let me reason about this carefully...</think>"
|
||||
"The actual thought content."
|
||||
)
|
||||
mock_agent.arun.return_value = mock_run
|
||||
|
||||
with patch("timmy.agent.create_timmy", return_value=mock_agent):
|
||||
result = await engine._call_agent("test prompt")
|
||||
|
||||
assert "<think>" not in result
|
||||
assert result == "The actual thought content."
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_call_agent_strips_multiline_think_tags(tmp_path):
|
||||
"""_call_agent handles multi-line <think> blocks."""
|
||||
engine = _make_engine(tmp_path)
|
||||
|
||||
mock_agent = AsyncMock()
|
||||
mock_run = AsyncMock()
|
||||
mock_run.content = (
|
||||
"<think>\nStep 1: analyze\nStep 2: synthesize\n</think>\n"
|
||||
"Clean output here."
|
||||
)
|
||||
mock_agent.arun.return_value = mock_run
|
||||
|
||||
with patch("timmy.agent.create_timmy", return_value=mock_agent):
|
||||
result = await engine._call_agent("test prompt")
|
||||
|
||||
assert "<think>" not in result
|
||||
assert result == "Clean output here."
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _parse_facts_response resilience (#237)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_parse_facts_clean_json(tmp_path):
|
||||
"""Direct JSON array should parse normally."""
|
||||
engine = _make_engine(tmp_path)
|
||||
result = engine._parse_facts_response('["fact one", "fact two"]')
|
||||
assert result == ["fact one", "fact two"]
|
||||
|
||||
|
||||
def test_parse_facts_empty_array(tmp_path):
|
||||
"""Empty JSON array should return empty list."""
|
||||
engine = _make_engine(tmp_path)
|
||||
assert engine._parse_facts_response("[]") == []
|
||||
|
||||
|
||||
def test_parse_facts_with_prose_prefix(tmp_path):
|
||||
"""JSON array preceded by prose should still parse (#237)."""
|
||||
engine = _make_engine(tmp_path)
|
||||
raw = 'Here are the facts:\n["Alexander prefers YAML", "Timmy runs locally"]'
|
||||
result = engine._parse_facts_response(raw)
|
||||
assert result == ["Alexander prefers YAML", "Timmy runs locally"]
|
||||
|
||||
|
||||
def test_parse_facts_with_markdown_fences(tmp_path):
|
||||
"""JSON wrapped in markdown code fences should parse."""
|
||||
engine = _make_engine(tmp_path)
|
||||
raw = '```json\n["fact in fences"]\n```'
|
||||
result = engine._parse_facts_response(raw)
|
||||
assert result == ["fact in fences"]
|
||||
|
||||
|
||||
def test_parse_facts_filters_non_strings(tmp_path):
|
||||
"""Non-string entries in the array should be filtered out."""
|
||||
engine = _make_engine(tmp_path)
|
||||
result = engine._parse_facts_response('[42, "valid fact", null, true]')
|
||||
assert result == ["valid fact"]
|
||||
|
||||
|
||||
def test_parse_facts_none_and_empty(tmp_path):
|
||||
"""None and empty input should return empty list."""
|
||||
engine = _make_engine(tmp_path)
|
||||
assert engine._parse_facts_response(None) == []
|
||||
assert engine._parse_facts_response("") == []
|
||||
assert engine._parse_facts_response(" ") == []
|
||||
|
||||
|
||||
def test_parse_facts_invalid_json(tmp_path):
|
||||
"""Totally invalid text with no JSON array should return empty list."""
|
||||
engine = _make_engine(tmp_path)
|
||||
assert engine._parse_facts_response("no json here at all") == []
|
||||
|
||||
Reference in New Issue
Block a user