Dialect translation
hlid's core principle is passthrough-first — when the agent's dialect matches the backend's, requests flow through unchanged, byte for byte. Translation happens only when dialects differ.
The matrix
| Agent speaks | Backend speaks | What happens |
|---|---|---|
| OpenAI Chat | OpenAI Chat | Passthrough — bytes forwarded as-is |
| Anthropic Messages | Anthropic Messages | Passthrough — bytes forwarded as-is |
| Anthropic Messages | OpenAI Chat | Translate — Messages ⇄ Chat Completions |
| OpenAI Chat | Anthropic Messages | Translate — Chat Completions ⇄ Messages |
Most real traffic is passthrough. llama.cpp speaks every dialect an agent does, and same-vendor agent/backend pairs match by definition. The cross-dialect case collapses to one boundary — OpenAI-family ⇄ Anthropic-family — and hlid implements both directions of it.
What translation covers
- System prompts —
systemfield ⇄ system message - Multi-turn conversations — role mapping across the full history
- Tool use —
tool_use/tool_resultblocks ⇄tool_calls/tool messages - Streaming — incremental SSE translation, event by event: OpenAI chunks ⇄
message_start/content_block_delta/message_delta/message_stop - Token usage — mapped into the response shape the agent expects
- Finish reasons —
stop_reason⇄finish_reasonsemantics
All of it is driven by golden-test fixtures — recorded request/response pairs in tests/fixtures/ that pin the exact expected output. If a translation is wrong, the fix starts with a fixture that proves it.
Degraded inputs
Backends don't always send complete responses. The translator tolerates minimal and empty-content responses (see tests/fixtures/degraded/) rather than failing the request.
Seeing it happen
Every capture in /hlid/requests carries a translated flag plus the inbound and backend dialects, so you can verify which path a request took:
{
"inbound_dialect": "anthropic-messages",
"backend_dialect": "openai-chat",
"translated": true
}