Files
ai-router/internal/protocol/README.md
T
2026-10-23 18:35:44 +08:00

4.5 KiB

Protocol conversion

Public entry points are ConvertRequest, ConvertResponse, Stream, and ExtractUsage. No external dependencies are needed. The service should bypass conversion for same-protocol non-streaming traffic. Stream preserves original SSE bytes for same-protocol traffic, including comments and CRLF, and returns upstream errors instead of silently swallowing them.

Cross-protocol support includes text, user URL/base64 images, system messages, function schemas and selection, multiple function calls, tool results, multi-turn history, and incremental tool argument JSON. Responses output item/content part/ argument start, delta, done and terminal events are emitted. Anthropic content block and message lifecycles are emitted. Each write flushes when supported.

Deliberate limits

  • Anthropic output thinking/redacted_thinking blocks and their thinking/signature stream deltas are omitted when converting to Chat/Responses, never appended to visible text. Block indices and lifecycle are checked. Native Anthropic output bytes remain unchanged; request-side thinking is not translated.

  • Chat output message/delta reasoning_content (string or null) is omitted only during cross-protocol conversion; it is never appended to visible text or fabricated as Anthropic thinking. Native Chat responses/SSE remain unchanged. Optional indices on complete Chat tool calls must match their array positions.

  • Responses output message phase is accepted as metadata. Cross-protocol conversion deliberately omits Responses output reasoning, summaries and encrypted content, including their recognized stream events. They are never appended to visible text or converted to Anthropic thinking/signatures. Same-protocol responses and SSE retain these bytes unchanged. Reasoning item/part indices, identities and lifecycles are checked; unrelated unknown content and event types remain errors. Empty output-text logprobs arrays are accepted, but actual logprobs remain unsupported.

  • Only one choice and function tools are supported. Other reasoning/thinking blocks, audio/video/documents, hosted tools, citations, refusal content, logprobs, structured-output modes, prompt-cache controls and Responses server-side conversation state are rejected rather than approximated. Unknown request fields and unknown stream event types are rejected.

  • Anthropic targets require an explicit token limit. Developer roles, mid-conversation system messages, strict tool schemas and explicit image detail levels cannot be translated to Anthropic. The implementation currently conservatively rejects explicit image detail for all cross-protocol pairs.

  • Tool results must be text and cannot carry Anthropic's is_error=true. Stop sequences cannot target Responses; stop-sequence termination cannot be represented losslessly across protocols.

  • Responses streaming supports one output-text content part per message. Final content must agree with deltas; nonincremental/final-only variants are rejected. Tool identity must be complete before argument streaming; later ID/name fragments are rejected. Parallel tool argument fragments are tracked independently.

  • Usage.Input includes cache-read and cache-write tokens. Anthropic input counters exclude these, so they are added on extraction and subtracted on encoding. Usage.Raw holds upstream usage JSON; Anthropic stream snapshots are merged so final output-only usage does not erase initial input counts. Unknown usage remains Known=false; Anthropic wire messages still carry required zero counters until actual usage is available. OpenAI wire schemas have no separate Anthropic cache-write counter; it remains in returned Usage.

  • SSE events are limited to 16 MiB; generated content is retained for final Responses snapshots and argument validation. LF and CRLF framing is supported (not standalone CR). Same-protocol streams allow EOF without a terminal marker; cross-protocol streams report truncation. Terminal markers finish immediately.

  • Context is checked between reads and writes. A generic io.Reader cannot be interrupted safely: the service must bind upstream HTTP requests to the same context or close their body on cancellation. Writers/readers remain caller-owned.

  • Response transport metadata and echoed Responses request settings are not round-tripped. Generated IDs use cryptographic randomness if upstream omits an ID. No external provider or SDK integration tests have been performed.

Run go test ./internal/protocol, go test -race -cover ./internal/protocol, and go vet ./internal/protocol.