DanglingToolCallMiddleware._message_tool_calls collected the raw
additional_kwargs tool_calls payload whenever structured tool_calls was
empty, even when invalid_tool_calls was non-empty. The raw payload is a
fallback serialization of the SAME calls — the OpenAI serializer reaches
for it only once both structured views are empty, which is exactly the
gating _normalize_tool_call_ids documents and implements. Collecting it
alongside a same-id invalid entry counted the call twice and emitted two
placeholder ToolMessages for one id — the duplicate-id shape strict
OpenAI-compatible providers reject with HTTP 400, the failure this
middleware exists to prevent.
Gate the raw collection on both structured views being empty, aligning
_message_tool_calls with _normalize_tool_call_ids.