wire

package
v0.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Google Gemini generateContent API translation. The Gemini wire (gemini-cli speaks it) carries the model in the URL rather than the body, groups content into role-tagged parts, and names its token counts differently; this file maps that to and from chat completions.

Anthropic Messages API translation. The Messages wire (Claude Code speaks it) structures content as typed blocks and streams a block-indexed event sequence; this file maps that to and from chat completions.

OpenAI Responses API translation. The Responses wire (codex speaks it) nests its output in typed items and streams a rich event sequence; this file maps that to and from chat completions.

Package wire translates between the three foreign chat wires a coding agent might speak (OpenAI Responses, Anthropic Messages, Google Gemini) and the OpenAI Chat Completions wire that most hosted models actually serve.

The problem it solves: a single shared model may only expose /v1/chat/completions, yet the tools you want to run against it each speak a different wire. codex posts to /v1/responses, Claude Code posts to /v1/messages, gemini-cli posts to /v1beta/models/{model}:generateContent. A proxy sitting in front of the model can accept any of those, translate the request down to chat completions, forward it, and translate the reply back, so every tool runs against the one model on equal footing.

This package is the pure translation half of that proxy. It has no knowledge of HTTP, trace recording, or the upstream connection: request bytes in, chat bytes out; chat bytes in, foreign bytes (or a foreign event stream) out. The caller owns reading the request, forwarding to the upstream, recording usage, and writing the response. That keeps the translators reusable and unit-testable without a live model.

Every translator targets the shapes a coding agent actually sends: messages, tool calls, and tool results. Multimodal parts beyond text are flattened to text rather than dropped, so nothing goes silently missing.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ChatPathOf

func ChatPathOf(p string) string

ChatPathOf maps a foreign wire's path onto its /chat/completions sibling, keeping any version prefix intact, so /v1/responses and /v1/messages both become /v1/chat/completions. A path it does not recognize passes through.

func ChatToGemini

func ChatToGemini(chat []byte) map[string]any

ChatToGemini assembles a Gemini generateContent response from one non-streamed chat completion: text becomes a text part, each tool_call a functionCall part.

func ChatToMessages

func ChatToMessages(chat []byte, seq int) map[string]any

ChatToMessages assembles a completed Messages object from one non-streamed chat completion: text becomes a text block, each tool_call a tool_use block.

func ChatToResponses

func ChatToResponses(chat []byte, seq int) map[string]any

ChatToResponses assembles a completed Responses object from one non-streamed chat completion: text becomes a message item, each tool_call a function_call item. seq disambiguates the synthetic ids across calls.

func GeminiToChat

func GeminiToChat(body []byte, model string, stream bool) (chat []byte, err error)

GeminiToChat converts a Gemini generateContent request body into a Chat Completions body. The model comes from the URL (Gemini does not carry it in the body) and stream comes from the method name, so both are passed in. systemInstruction becomes a system message, each content's parts fan out (text into content, functionCall into assistant tool_calls, functionResponse into tool messages), and functionDeclarations nest into chat tools.

func IsGeminiPath

func IsGeminiPath(p string) (model string, stream bool, ok bool)

IsGeminiPath reports whether a path is a Gemini generateContent call, and if so returns the model (parsed from /v1beta/models/{model}:method) and whether the method streams. Gemini puts the model in the URL and picks streaming by method name, so both must come from the path, not the body.

func IsMessagesPath

func IsMessagesPath(p string) bool

IsMessagesPath reports whether a path is an Anthropic Messages call the proxy should translate rather than forward verbatim.

func IsResponsesPath

func IsResponsesPath(p string) bool

IsResponsesPath reports whether a path is a Responses-API call the proxy should translate rather than forward verbatim. codex posts to /v1/responses.

func MessagesToChat

func MessagesToChat(body []byte) (chat []byte, stream bool, err error)

MessagesToChat converts a Messages-API request body into a Chat Completions body and reports whether the caller asked to stream. system becomes a system message, each turn's blocks fan out into chat messages (text into content, tool_use into assistant tool_calls, tool_result into tool messages), and the flat tool shape nests.

func ResponsesToChat

func ResponsesToChat(body []byte) (chat []byte, stream bool, err error)

ResponsesToChat converts a Responses-API request body into a Chat Completions body and reports whether the caller asked to stream. The mapping is: the top-level instructions become a system message, the input array becomes the message list, and the flat tool shape becomes the nested chat tool shape.

func StreamGemini

func StreamGemini(w io.Writer, flush func(), r io.Reader, onFirst func()) json.RawMessage

StreamGemini reads an upstream chat SSE stream from r and re-emits it as the Gemini streamGenerateContent SSE stream (data: lines carrying GenerateContentResponse chunks), writing to w and flushing after each chunk via flush (nil is allowed). onFirst, if non-nil, fires on the first stream byte. It returns the final chat usage block (raw JSON, possibly nil).

func StreamMessages

func StreamMessages(w io.Writer, flush func(), r io.Reader, seq int, onFirst func()) json.RawMessage

StreamMessages reads an upstream chat SSE stream from r and re-emits it as the Anthropic Messages event stream, writing to w and flushing after each event via flush (nil is allowed). onFirst, if non-nil, fires when the first stream byte arrives. It returns the final chat usage block (raw JSON, possibly nil).

func StreamResponses

func StreamResponses(w io.Writer, flush func(), r io.Reader, seq int, onFirst func()) json.RawMessage

StreamResponses reads an upstream chat SSE stream from r and re-emits it as the Responses-API event stream codex consumes, writing to w and flushing after each event via flush (nil is allowed). onFirst, if non-nil, fires when the first stream byte arrives, so the caller can stamp time-to-first-token. It returns the final chat usage block (raw JSON, possibly nil) for the caller to record.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL