Three independent failure modes observed in HTTP 400 logs:
1. reasoningEffortMap only mapped xhigh→max for the deepseek provider,
not for DeepSeek-family models on NVIDIA/OpenCode-Go/etc. Sending
reasoning_effort: "xhigh" to these endpoints caused 400 errors.
2. convertMessages filtered thinking blocks by nonEmptyThinkingBlocks,
excluding blocks with valid thinkingSignature but empty text. These
signatures identify the correct field name for reasoning_content
replay but were lost in the filter.
3. When a proxy (OpenCode-Go, NVIDIA) returns a tool-call response
without any reasoning_content at all, no thinking blocks exist to
recover from. Added empty-string fallback so the required field is
present even when no reasoning was captured.
Adds allowsSyntheticReasoningContentForToolCalls compat flag to
distinguish DeepSeek (rejects synthetic "." placeholder) from Kimi
and OpenRouter (accept it).
Credit: builds on the approach from PR #902 by @edmand46.