chore: track pre-existing test_chat_tools.py baseline
Was never committed before. Tracking it now (unmodified) so Task 6 of the cross-chat-memory plan, which edits this file, produces a clean incremental diff instead of showing the whole file as new. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iZMEPk2Kt1UC96Lo9bC5w
This commit is contained in:
parent
99dd1a1f8f
commit
09fc20c9df
|
|
@ -0,0 +1,138 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import main
|
||||||
|
|
||||||
|
|
||||||
|
def _text_block(text):
|
||||||
|
block = MagicMock()
|
||||||
|
block.type = "text"
|
||||||
|
block.text = text
|
||||||
|
return block
|
||||||
|
|
||||||
|
|
||||||
|
def _tool_use_block(name, tool_input, tool_id="tool_1"):
|
||||||
|
block = MagicMock()
|
||||||
|
block.type = "tool_use"
|
||||||
|
block.name = name
|
||||||
|
block.input = tool_input
|
||||||
|
block.id = tool_id
|
||||||
|
return block
|
||||||
|
|
||||||
|
|
||||||
|
def _usage(input_tokens, output_tokens):
|
||||||
|
usage = MagicMock()
|
||||||
|
usage.input_tokens = input_tokens
|
||||||
|
usage.output_tokens = output_tokens
|
||||||
|
return usage
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_run_chat_completion_without_tool_use():
|
||||||
|
completion = MagicMock()
|
||||||
|
completion.stop_reason = "end_turn"
|
||||||
|
completion.content = [_text_block("Hallo!")]
|
||||||
|
completion.usage = _usage(10, 5)
|
||||||
|
|
||||||
|
main.claude_client = MagicMock()
|
||||||
|
main.claude_client.messages.create.return_value = completion
|
||||||
|
|
||||||
|
text, output_tokens, total_tokens = await main.run_chat_completion([{"role": "user", "content": "Hi"}])
|
||||||
|
|
||||||
|
assert text == "Hallo!"
|
||||||
|
assert output_tokens == 5
|
||||||
|
assert total_tokens == 15
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_run_chat_completion_executes_tool_and_returns_followup():
|
||||||
|
first = MagicMock()
|
||||||
|
first.stop_reason = "tool_use"
|
||||||
|
first.content = [_tool_use_block("list_calendar_events", {"days_ahead": 7})]
|
||||||
|
first.usage = _usage(20, 8)
|
||||||
|
|
||||||
|
second = MagicMock()
|
||||||
|
second.stop_reason = "end_turn"
|
||||||
|
second.content = [_text_block("Naechste Woche steht nichts an.")]
|
||||||
|
second.usage = _usage(30, 12)
|
||||||
|
|
||||||
|
main.claude_client = MagicMock()
|
||||||
|
main.claude_client.messages.create.side_effect = [first, second]
|
||||||
|
|
||||||
|
with patch.object(main, "list_upcoming_events", new=AsyncMock(return_value=[])):
|
||||||
|
text, output_tokens, total_tokens = await main.run_chat_completion(
|
||||||
|
[{"role": "user", "content": "Was steht diese Woche an?"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert text == "Naechste Woche steht nichts an."
|
||||||
|
assert output_tokens == 8 + 12
|
||||||
|
assert total_tokens == 20 + 8 + 30 + 12
|
||||||
|
assert main.claude_client.messages.create.call_count == 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_run_chat_completion_handles_two_sequential_tool_calls():
|
||||||
|
"""Regression test: 'verschiebe den Termin X' needs list_calendar_events
|
||||||
|
to find the uid, THEN update_calendar_event - a single tool round used
|
||||||
|
to silently drop the second call and return an empty response."""
|
||||||
|
first = MagicMock()
|
||||||
|
first.stop_reason = "tool_use"
|
||||||
|
first.content = [_tool_use_block("list_calendar_events", {"days_ahead": 30}, "tool_1")]
|
||||||
|
first.usage = _usage(20, 8)
|
||||||
|
|
||||||
|
second = MagicMock()
|
||||||
|
second.stop_reason = "tool_use"
|
||||||
|
second.content = [
|
||||||
|
_tool_use_block("update_calendar_event", {"uid": "abc", "start": "2026-09-30T11:00:00"}, "tool_2")
|
||||||
|
]
|
||||||
|
second.usage = _usage(40, 10)
|
||||||
|
|
||||||
|
third = MagicMock()
|
||||||
|
third.stop_reason = "end_turn"
|
||||||
|
third.content = [_text_block("Termin verschoben.")]
|
||||||
|
third.usage = _usage(50, 6)
|
||||||
|
|
||||||
|
main.claude_client = MagicMock()
|
||||||
|
main.claude_client.messages.create.side_effect = [first, second, third]
|
||||||
|
|
||||||
|
with patch.object(main, "list_upcoming_events", new=AsyncMock(return_value=[{"uid": "abc"}])), patch.object(
|
||||||
|
main, "update_event", new=AsyncMock(return_value={"uid": "abc"})
|
||||||
|
):
|
||||||
|
text, output_tokens, total_tokens = await main.run_chat_completion(
|
||||||
|
[{"role": "user", "content": "Verschiebe den Termin X"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert text == "Termin verschoben."
|
||||||
|
assert output_tokens == 8 + 10 + 6
|
||||||
|
assert total_tokens == 20 + 8 + 40 + 10 + 50 + 6
|
||||||
|
assert main.claude_client.messages.create.call_count == 3
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_run_chat_completion_lists_recent_emails():
|
||||||
|
first = MagicMock()
|
||||||
|
first.stop_reason = "tool_use"
|
||||||
|
first.content = [_tool_use_block("list_recent_emails", {"limit": 5}, "tool_1")]
|
||||||
|
first.usage = _usage(15, 6)
|
||||||
|
|
||||||
|
second = MagicMock()
|
||||||
|
second.stop_reason = "end_turn"
|
||||||
|
second.content = [_text_block("Du hast 5 neue Mails.")]
|
||||||
|
second.usage = _usage(20, 8)
|
||||||
|
|
||||||
|
main.claude_client = MagicMock()
|
||||||
|
main.claude_client.messages.create.side_effect = [first, second]
|
||||||
|
|
||||||
|
with patch.object(main, "list_recent_emails", new=AsyncMock(return_value=[])):
|
||||||
|
text, output_tokens, total_tokens = await main.run_chat_completion(
|
||||||
|
[{"role": "user", "content": "Was ist neu im Postfach?"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert text == "Du hast 5 neue Mails."
|
||||||
|
assert output_tokens == 6 + 8
|
||||||
|
assert total_tokens == 15 + 6 + 20 + 8
|
||||||
Loading…
Reference in New Issue