Bug Description
The llm_anthropic module is missing the format_messages / format_message infrastructure that other providers (e.g., llm_openai) implement. This causes a KeyError: 'role' when anthropic_chat() receives mail.message records instead of pre-formatted dicts.
Steps to Reproduce
- Install
llm, llm_anthropic, llm_thread, llm_assistant, llm_tool
- Configure an Anthropic provider with a valid API key
- Create a model, assistant, prompt, and thread
- Send a message via the chat UI or SSE endpoint
GET /llm/thread/generate?thread_id=X&message=Y
Expected Behavior
Assistant responds with LLM-generated content.
Actual Behavior
SSE returns:
data: {"type": "error", "error": "'role'"}
data: {"type": "done"}
Root Cause
The flow is:
llm_assistant/models/llm_thread.py → _generate_assistant_response() calls self.get_llm_messages() which returns a mail.message recordset
- This recordset is passed through
model.chat() → provider.chat() → anthropic_chat()
anthropic_chat() iterates messages doing msg["role"] — but mail.message records have the field llm_role, not role
The llm_openai module handles this correctly by implementing:
openai_format_messages() on llm.provider (converts recordset to list of dicts)
openai_format_message() on mail.message (converts a single record)
openai_chat() uses _prepare_chat_params() which calls format_messages()
The llm_anthropic module has none of this — anthropic_chat() directly iterates the raw recordset assuming dict-like role/content keys.
Proposed Fix
Add anthropic_format_message() to mail.message and anthropic_format_messages() to llm.provider, following the same pattern as llm_openai. Then update anthropic_chat() to use _prepare_chat_params_base() or call format_messages() before processing.
Environment
- Odoo 16 Enterprise (Clodofy hosting)
llm v16.0.1.4.2
llm_anthropic v16.0.1.1.0
llm_thread v16.0.1.3.2
llm_assistant v16.0.1.5.3
llm_tool v16.0.3.0.0
Bug Description
The
llm_anthropicmodule is missing theformat_messages/format_messageinfrastructure that other providers (e.g.,llm_openai) implement. This causes aKeyError: 'role'whenanthropic_chat()receivesmail.messagerecords instead of pre-formatted dicts.Steps to Reproduce
llm,llm_anthropic,llm_thread,llm_assistant,llm_toolGET /llm/thread/generate?thread_id=X&message=YExpected Behavior
Assistant responds with LLM-generated content.
Actual Behavior
SSE returns:
Root Cause
The flow is:
llm_assistant/models/llm_thread.py→_generate_assistant_response()callsself.get_llm_messages()which returns amail.messagerecordsetmodel.chat()→provider.chat()→anthropic_chat()anthropic_chat()iterates messages doingmsg["role"]— butmail.messagerecords have the fieldllm_role, notroleThe
llm_openaimodule handles this correctly by implementing:openai_format_messages()onllm.provider(converts recordset to list of dicts)openai_format_message()onmail.message(converts a single record)openai_chat()uses_prepare_chat_params()which callsformat_messages()The
llm_anthropicmodule has none of this —anthropic_chat()directly iterates the raw recordset assuming dict-likerole/contentkeys.Proposed Fix
Add
anthropic_format_message()tomail.messageandanthropic_format_messages()tollm.provider, following the same pattern asllm_openai. Then updateanthropic_chat()to use_prepare_chat_params_base()or callformat_messages()before processing.Environment
llmv16.0.1.4.2llm_anthropicv16.0.1.1.0llm_threadv16.0.1.3.2llm_assistantv16.0.1.5.3llm_toolv16.0.3.0.0