diff --git a/Claude outputs/main.py b/Claude outputs/main.py index 56aa3e3..0c8eeb3 100644 --- a/Claude outputs/main.py +++ b/Claude outputs/main.py @@ -1086,6 +1086,7 @@ async def update_conversation_summary(conversation_id: int): try: history = await get_messages(conversation_id) claude_messages = [{"role": m["role"], "content": m["content"]} for m in history] + claude_messages.append({"role": "user", "content": "Fasse das bisherige Gespraech zusammen."}) completion = await asyncio.to_thread( claude_client.messages.create, model=CLAUDE_MODEL, diff --git a/Claude outputs/tests/test_memory.py b/Claude outputs/tests/test_memory.py index 073991e..6ed0aad 100644 --- a/Claude outputs/tests/test_memory.py +++ b/Claude outputs/tests/test_memory.py @@ -237,6 +237,34 @@ async def test_update_conversation_summary_upserts_summary_and_embedding(): mock_upsert.assert_called_once_with(3, "Nutzer fragte nach seinem Hund Bruno.", [0.1, 0.2]) +@pytest.mark.asyncio +async def test_update_conversation_summary_ends_messages_with_user_role(): + """Regression: history always ends with the just-saved assistant reply, + but the Anthropic Messages API rejects a request whose last message is + not role=user (no prefill support) - a trailing user instruction must + be appended, or this call 400s on every real conversation.""" + history = [ + {"role": "user", "content": "Wie geht es meinem Hund?", "tokens_used": None, "created_at": None}, + {"role": "assistant", "content": "Bruno geht es gut.", "tokens_used": 5, "created_at": None}, + ] + completion = MagicMock() + text_block = MagicMock() + text_block.type = "text" + text_block.text = "Zusammenfassung." + completion.content = [text_block] + + main.claude_client = MagicMock() + main.claude_client.messages.create.return_value = completion + + with patch.object(main, "get_messages", new=AsyncMock(return_value=history)), patch.object( + main, "get_embedding", new=AsyncMock(return_value=[0.1]) + ), patch.object(main, "upsert_conversation_summary", new=AsyncMock()): + await main.update_conversation_summary(conversation_id=3) + + _, kwargs = main.claude_client.messages.create.call_args + assert kwargs["messages"][-1]["role"] == "user" + + @pytest.mark.asyncio async def test_update_conversation_summary_swallows_exceptions(): with patch.object(main, "get_messages", new=AsyncMock(side_effect=RuntimeError("DB down"))):