8e0a3c6083
Mistral Magistral reasoning models (and mistral-large-2512+) return
message content as a list of typed blocks instead of a plain string:
[{"type": "thinking", "thinking": [{"type": "text", "text": "..."}]},
{"type": "text", "text": "final answer"}]
This happens in both streaming deltas and non-streaming responses,
causing TypeError: sequence item 0: expected str instance, list found
when the code tries to join content parts.
Changes:
- Add _normalize_structured_content() helper that extracts text and
thinking parts from Mistral structured blocks
- Fix streaming path: normalize delta.content before appending to
content_parts, route thinking to reasoning_parts
- Fix non-streaming normalization: use the helper to also extract
thinking blocks as reasoning_content (was silently dropping them)
- Fix _build_assistant_message: normalize list content before
string operations
- Fix length truncation/continuation paths: normalize content
before string concatenation
- Add 25 tests covering the helper, streaming, non-streaming,
and _build_assistant_message paths
Fixes the reported CLI/Discord bot crash when using magistral-latest
or magistral-medium-latest via api.mistral.ai.