llm_ollama broken after llm base refactors: role helpers used as bool (all messages become "user"), format_messages signature, arguments type
- Langage dominant
- Python
- Étoiles
- 219
- Forks
- 159
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Description
**Environment:** branch `18.0` @ `609ec6dda3645165f6a4a843d7af5d286081a29d`, Odoo 18 (official docker image), python `ollama` client 0.6.2, models tested: qwen3:8b, qwen2.5:7b.
With this combination, any `llm.thread` chat using tools via the Ollama provider never converges: the model keeps re-issuing the same tool call (threads grow by hundreds of messages) or asks the user for parameters it already used. We tracked it down to three independent regressions plus one unenforced field. Details below — happy to send a PR with the fixes if useful.
### 1. `llm_ollama` formats EVERY message as role "user" → tool results never reach the model
`llm/models/mail_message.py` refactored the role helpers to a batch API returning a dict:
```python
def is_llm_user_message(self):
return {message: message.llm_role == "user" for message in self}
```
`llm_openai`, `llm_anthropic` and `llm_letta` were updated to the new call form (`self.is_llm_user_message()[self]`), but `llm_ollama/models/mail_message.py::ollama_format_message` still uses the old boolean form:
```python
if self.is_llm_user_message(): # non-empty dict -> always truthy
```
A non-empty dict is always truthy, so EVERY message in the history is formatted as `{"role": "user", "content": }`. Assistant `tool_calls` and tool results are silently dropped from the payload — the model literally sees a conversation made only of "user" messages like `Executing consultar_estoque_produto`.
Fix (mirrors `llm_openai`):
```python
if self.is_llm_user_message()[self]:
...
elif self.is_llm_assistant_message()[self]:
```
### 2. `format_messages` dispatch signature mismatch
`llm/models/llm_provider.py::format_messages` dispatches with `model=model`, but `ollama_format_messages(self, messages, system_prompt=None)` does not accept it → `TypeError` on every thread+ollama chat. Fix: add `model=None` to the signature.
### 3. History resend rejected: `arguments` serialized as JSON string, ollama client >=0.4 requires dict
`ollama_process_(non_)streaming_response` stores `function.arguments` as a JSON **string** (`json.dumps(arguments)`), and `ollama_format_message` sends it back verbatim when re-sending the history. The python `ollama` client validates `Message.tool_calls[].function.arguments` as a **dict** (pydantic), so the second chat call of every tool conversation fails client-side:
```
1 validation error for Message tool_calls.0.function.arguments
Input should be a valid dictionary [type=dict_type, input_value='{"etapa": ""}', input_type=str]
```
Fix in `ollama_format_message` (assistant branch): `json.loads(...)` when the stored value is a string.
### 4. `llm_assistant.tool_calls_max` is never read
The field exists on `llm.assistant` (and is copied to threads via onchange), but no code enforces it, so nothing bounds the tool loop — which turns bug 1 into an unbounded loop (we observed 300+ messages from a single question). Suggest enforcing it in `llm_thread.generate_messages`/`_should_continue`.
---
After patching 1–3 locally (and enforcing 4 in a custom module), tool calling with Ollama works end to end: correct roles in the payload, tool results fed back to the model, and grounded answers.
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Évaluation
Cette issue n'a pas encore été évaluée.