mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-16 09:45:24 -04:00
Chat: merge consecutive user messages for strict providers
After a non-native tool round, the agent appends tool results as a {role:
'user'} message next to the user's original 'user' prompt, producing two
consecutive 'user' messages. Strict provider APIs (Anthropic/Claude) reject
consecutive same-role messages, so the follow-up generation request fails
silently — search returns sources, then nothing is generated.
_sanitize_llm_messages now merges consecutive 'user' messages (joining their
content). Only user/user is merged; normal chat and agent/tool turns already
alternate and are untouched.
Scoped down per maintainer review: the agent_loop 'output' source-extraction
change is already on main (#898/#901) and the broad-mocking web-sources test
was dropped. Added a focused test that runs consecutive-user messages through
the real _build_anthropic_payload and asserts the payload alternates correctly.
This commit is contained in:
+38
-1
@@ -586,7 +586,44 @@ def _sanitize_llm_messages(messages: List[Dict]) -> List[Dict]:
|
||||
cleaned.append(item)
|
||||
elif "content" in item:
|
||||
cleaned.append(item)
|
||||
return cleaned
|
||||
|
||||
# Merge consecutive user messages to satisfy strict role alternation requirements.
|
||||
merged = []
|
||||
for item in cleaned:
|
||||
if not merged:
|
||||
merged.append(item)
|
||||
continue
|
||||
|
||||
last = merged[-1]
|
||||
if last["role"] == "user" and item["role"] == "user":
|
||||
last_copy = dict(last)
|
||||
|
||||
# Content:
|
||||
last_content = last_copy.get("content")
|
||||
item_content = item.get("content")
|
||||
|
||||
# Convert contents to string if they exist, or keep None/empty
|
||||
last_str = str(last_content) if last_content is not None else ""
|
||||
item_str = str(item_content) if item_content is not None else ""
|
||||
|
||||
if last_str and item_str:
|
||||
new_content = f"{last_str}\n\n{item_str}"
|
||||
elif last_str:
|
||||
new_content = last_str
|
||||
else:
|
||||
new_content = item_str if item_str else None
|
||||
|
||||
if new_content is not None:
|
||||
last_copy["content"] = new_content
|
||||
elif "content" in last_copy:
|
||||
del last_copy["content"]
|
||||
|
||||
merged[-1] = last_copy
|
||||
else:
|
||||
merged.append(item)
|
||||
|
||||
return merged
|
||||
|
||||
|
||||
def _normalize_anthropic_url(url: str) -> str:
|
||||
"""Ensure Anthropic URL points to /v1/messages."""
|
||||
|
||||
Reference in New Issue
Block a user