ChatClientKit Message Normalization (Compatibility)
This page explains how ChatClientKit “cleans” messages before sending requests to stay compatible with OpenAI-style, Anthropic, Mistral, and other interfaces. The sanitizer runs in RemoteCompletionsChatClient, RemoteResponsesChatClient, and the MLX client.
Why the sanitizer is needed
- Role alternation: Some APIs strictly require user/assistant turns and reject empty content.
- Tool responses: Tool calls must be followed by matching tool responses, or APIs refuse to continue.
- Strict mode: Mixing tools with and without
strictcan trigger errors on some gateways. - Stability: A unified message format makes retries and streaming recovery more predictable.
Rule pipeline (execution order)
- Merge system messages: Combine all
.systemmessages into one, keep the firstname, and drop empty content to avoid repeated system prompts. - User context before assistant: If an assistant message lacks a preceding user message, insert
.user "."to satisfy alternation requirements. - Fill missing tool responses: For each
tool_callinside an assistant message, if the matching.toolreply is missing, insert.tool "."with the sametoolCallID, keeping the assistant→tool→assistant chain intact. - Trailing user text: If the final message is not user text, append
.user "."so the model can continue after tool calls. - Align strict tools: If any tool declares
strict: true, rewrite all tools tostrict: trueto avoid mixed-strictness errors.
Note: Placeholder content uses a single dot "." to satisfy minimum-content checks while minimizing semantic impact.