adapter

package
v0.19.2 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

View Source
const GeminiModelsRoutePrefix = "/v1beta/models/"

GeminiModelsRoutePrefix is the fixed Gemini route segment that carries the model in the URL instead of the body.

View Source
const MetadataUsageKey = "usage"

MetadataUsageKey is the RequestContext.Metadata key under which the streaming usage observer records the latest *CanonicalUsage. The metrics pipeline reads it back from the same key when building the exchange.

Variables

View Source
var ErrModelNotAllowed = errors.New("model not allowed")

Functions

func AdaptEmbeddingRequest added in v0.3.4

func AdaptEmbeddingRequest(registry *Registry, body []byte, source, target Format) ([]byte, error)

func AdaptEmbeddingResponse added in v0.3.4

func AdaptEmbeddingResponse(registry *Registry, body []byte, source, target Format) ([]byte, error)

func AdaptRerankRequest added in v0.3.4

func AdaptRerankRequest(registry *Registry, body []byte, source, target Format) ([]byte, error)

func AdaptRerankResponse added in v0.3.4

func AdaptRerankResponse(registry *Registry, body []byte, source, target Format) ([]byte, error)

func BodyCarriesRetryableError

func BodyCarriesRetryableError(body []byte) bool

func EnforceModel

func EnforceModel(body []byte, allowedModels []string, defaultModel string) ([]byte, string, error)

func ExtractAssistantOutputGeneric

func ExtractAssistantOutputGeneric(body []byte) string

ExtractAssistantOutputGeneric attempts to find assistant output from common JSON fields when no provider-specific adapter is available. It probes, in order: choices[0].message.content, content, output.

func ExtractModel

func ExtractModel(body []byte) (string, error)

func ExtractModelField

func ExtractModelField(body []byte) (model string, hasModelID bool, err error)

func ExtractUserInputGeneric

func ExtractUserInputGeneric(body []byte) string

ExtractUserInputGeneric attempts to find user input from common JSON fields when no provider-specific adapter is available. It probes, in order: messages[-1].content (last user), input, prompt.

func GeminiModelFromPath

func GeminiModelFromPath(path string) string

GeminiModelFromPath extracts the model segment of a Gemini generateContent path, e.g. "/v1beta/models/gemini-pro:generateContent" -> "gemini-pro".

func IsRequestDecodeError

func IsRequestDecodeError(err error) bool

IsRequestDecodeError returns true when err (or any error in its chain) is a RequestDecodeError, i.e. the caller sent a body that does not match the expected provider format.

func IsSameWireFormat

func IsSameWireFormat(a, b Format) bool

func NormalizeGroqRequest

func NormalizeGroqRequest(body []byte) []byte

NormalizeGroqRequest applies OpenAI-compatible fixes plus Groq-specific request normalizations before calling the Groq API. It does not alter upstream error responses.

Groq-specific normalizations:

  • Ensures tools[].type is "function" when the tools array is present.
  • Sets parallel_tool_calls to false when tools are used and the field is omitted (reduces tool_use_failed on some Llama models).
  • Drops assistant history messages that only contain Llama-style <function=...> text without structured tool_calls (poisoned turns from clients or prior failed generations).

func NormalizeOpenAIRequest

func NormalizeOpenAIRequest(body []byte) []byte

NormalizeOpenAIRequest performs lightweight, in-place normalization of an OpenAI-compatible request body to fix common issues sent by third-party SDKs (e.g. Mistral, Cohere) that use the OpenAI wire format but omit fields that OpenAI strictly requires.

Current normalizations:

  • Ensures every tool_call object inside messages has "type": "function". The Mistral SDK omits this field, but OpenAI returns 400 without it.
  • Ensures every tools[].function.parameters is a non-empty JSON Schema object. Gemini cross-format requests often omit parameters; strict OpenAI-wire upstreams (e.g. Cerebras gpt-oss) reject tools without it.

The function is a no-op (returns the original body) when no changes are needed, so it is safe to call unconditionally on every OpenAI-bound request.

func NormalizeRequestForProvider

func NormalizeRequestForProvider(providerName string, targetFormat Format, body []byte) []byte

NormalizeRequestForProvider applies provider-specific request fixes before an upstream call. Groq uses NormalizeGroqRequest; other OpenAI-wire targets use NormalizeOpenAIRequest when applicable.

func OverrideModel

func OverrideModel(body []byte, model string) []byte

func RequestWantsStream

func RequestWantsStream(body []byte) (stream bool, explicit bool)

func SSEData

func SSEData(dataJSON []byte) [][]byte

SSEData builds a single "data: …" line followed by an empty separator. This is the format used by providers that do not emit "event:" lines (e.g. OpenAI, Azure).

func SSEEvent

func SSEEvent(eventType string, dataJSON []byte) [][]byte

SSEEvent builds the standard SSE lines for one event:

event: <eventType>
data: <dataJSON>
<empty line>

The caller writes each element followed by "\n".

func ShouldPassthroughSameWireFormat

func ShouldPassthroughSameWireFormat(source, target Format) bool

ShouldPassthroughSameWireFormat reports whether request/response bodies can be forwarded without canonical adaptation. Groq and OpenRouter are OpenAI-compatible but not identical, so openai↔groq/openrouter still goes through the adapter.

func StripModel

func StripModel(body []byte) []byte

func SupportedSourceFormat

func SupportedSourceFormat(f Format) bool

Types

type AnthropicAdapter

type AnthropicAdapter struct{}

AnthropicAdapter converts between Anthropic Messages API format and the canonical internal model.

func (*AnthropicAdapter) DecodeRequest

func (a *AnthropicAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*AnthropicAdapter) DecodeResponse

func (a *AnthropicAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*AnthropicAdapter) DecodeStreamChunk

func (a *AnthropicAdapter) DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)

func (*AnthropicAdapter) EncodeRequest

func (a *AnthropicAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*AnthropicAdapter) EncodeResponse

func (a *AnthropicAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*AnthropicAdapter) EncodeStreamChunk

func (a *AnthropicAdapter) EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)

type BedrockAdapter

type BedrockAdapter struct {
	// contains filtered or unexported fields
}

BedrockAdapter converts between AWS Bedrock model-specific formats and the canonical internal model. Bedrock hosts multiple model families (Claude, Titan, Llama, Mistral, DeepSeek/OpenAI-compat) each with its own wire format. This adapter dispatches to the appropriate sub-adapter based on model family detection.

func (*BedrockAdapter) DecodeRequest

func (a *BedrockAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*BedrockAdapter) DecodeResponse

func (a *BedrockAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*BedrockAdapter) DecodeStreamChunk

func (a *BedrockAdapter) DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)

func (*BedrockAdapter) EncodeRequest

func (a *BedrockAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*BedrockAdapter) EncodeResponse

func (a *BedrockAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*BedrockAdapter) EncodeStreamChunk

func (a *BedrockAdapter) EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)

type CanonicalEmbeddingRequest added in v0.3.4

type CanonicalEmbeddingRequest struct {
	Model     string   `json:"model,omitempty"`
	Inputs    []string `json:"inputs,omitempty"`
	InputType string   `json:"input_type,omitempty"`
}

type CanonicalEmbeddingResponse added in v0.3.4

type CanonicalEmbeddingResponse struct {
	Model      string          `json:"model,omitempty"`
	Embeddings [][]float64     `json:"embeddings,omitempty"`
	Usage      *CanonicalUsage `json:"usage,omitempty"`
}

type CanonicalMessage

type CanonicalMessage struct {
	Role       string              `json:"role"`
	Content    string              `json:"content"`
	ToolCalls  []CanonicalToolCall `json:"tool_calls,omitempty"`
	ToolCallID string              `json:"tool_call_id,omitempty"`
}

CanonicalMessage represents a single turn in the conversation.

type CanonicalReasoning

type CanonicalReasoning struct {
	Effort       []byte  `json:"effort,omitempty"`        // OpenAI: provider-specific (e.g. JSON)
	Summary      *string `json:"summary,omitempty"`       // OpenAI: summary
	ThinkingText string  `json:"thinking_text,omitempty"` // Anthropic/Gemini: raw thinking blocks concatenated
}

CanonicalReasoning holds optional reasoning/thinking metadata from the model. OpenAI uses Effort/Summary; Anthropic/Gemini use ThinkingText (raw thinking content).

type CanonicalRequest

type CanonicalRequest struct {
	Model             string                     `json:"model,omitempty"`
	System            string                     `json:"system,omitempty"`
	Messages          []CanonicalMessage         `json:"messages,omitempty"`
	Tools             []CanonicalTool            `json:"tools,omitempty"`
	ToolChoice        *CanonicalToolChoice       `json:"tool_choice,omitempty"`
	MaxTokens         int                        `json:"max_tokens,omitempty"`
	Temperature       *float64                   `json:"temperature,omitempty"`
	TopP              *float64                   `json:"top_p,omitempty"`
	TopK              *int                       `json:"top_k,omitempty"`
	Stop              []string                   `json:"stop,omitempty"`
	Stream            bool                       `json:"stream,omitempty"`
	ResponseFormat    *CanonicalRespFormat       `json:"response_format,omitempty"`
	Metadata          map[string]interface{}     `json:"metadata,omitempty"`
	RequestExtensions map[string]json.RawMessage `json:"request_extensions,omitempty"`
}

CanonicalRequest is the internal neutral representation of any AI provider

type CanonicalRespFormat

type CanonicalRespFormat struct {
	Type string `json:"type"` // "json_object", "text"
}

CanonicalRespFormat controls the response format.

type CanonicalResponse

type CanonicalResponse struct {
	ID                 string                     `json:"id,omitempty"`
	Model              string                     `json:"model,omitempty"`
	Content            string                     `json:"content,omitempty"`
	Role               string                     `json:"role,omitempty"`
	ToolCalls          []CanonicalToolCall        `json:"tool_calls,omitempty"`
	FinishReason       string                     `json:"finish_reason,omitempty"` // "stop", "length", "tool_calls"
	Usage              *CanonicalUsage            `json:"usage,omitempty"`
	Reasoning          *CanonicalReasoning        `json:"reasoning,omitempty"` // e.g. OpenAI reasoning / thinking
	ProviderExtensions map[string]json.RawMessage `json:"provider_extensions,omitempty"`
}

CanonicalResponse is the internal neutral representation of a provider response.

type CanonicalStreamChunk

type CanonicalStreamChunk struct {
	ID                 string                     `json:"id,omitempty"`
	Model              string                     `json:"model,omitempty"`
	Role               string                     `json:"role,omitempty"`  // only on first chunk
	Delta              string                     `json:"delta,omitempty"` // text content delta
	FinishReason       string                     `json:"finish_reason,omitempty"`
	ToolCallDeltas     []StreamToolCallDelta      `json:"tool_call_deltas,omitempty"`
	Usage              *CanonicalUsage            `json:"usage,omitempty"` // present in the final chunk of some providers
	ProviderExtensions map[string]json.RawMessage `json:"provider_extensions,omitempty"`
}

CanonicalStreamChunk is one piece of a streamed response.

type CanonicalTool

type CanonicalTool struct {
	Name        string                 `json:"name"`
	Description string                 `json:"description,omitempty"`
	Schema      map[string]interface{} `json:"schema,omitempty"`
}

CanonicalTool represents a tool/function the model can call.

type CanonicalToolCall

type CanonicalToolCall struct {
	ID        string `json:"id"`
	Name      string `json:"name"`
	Arguments string `json:"arguments"` // raw JSON string
}

CanonicalToolCall represents a tool invocation by the model.

type CanonicalToolChoice

type CanonicalToolChoice struct {
	// Type: "auto", "none", "any", "tool"
	Type string `json:"type"`
	// Name is only set when Type == "tool"
	Name string `json:"name,omitempty"`
}

CanonicalToolChoice controls how the model selects tools.

type CanonicalUsage

type CanonicalUsage struct {
	InputTokens  int `json:"input_tokens"`
	OutputTokens int `json:"output_tokens"`
	TotalTokens  int `json:"total_tokens"`
	// Provider-specific cache/billing fields (pass-through).
	CacheCreationInputTokens int    `json:"cache_creation_input_tokens,omitempty"`
	CacheReadInputTokens     int    `json:"cache_read_input_tokens,omitempty"`
	ServiceTier              string `json:"service_tier,omitempty"`
	CachedInputTokens        int    `json:"cached_input_tokens,omitempty"`     // sub-count of InputTokens
	ReasoningOutputTokens    int    `json:"reasoning_output_tokens,omitempty"` // sub-count of OutputTokens
	ToolUseInputTokens       int    `json:"tool_use_input_tokens,omitempty"`   // sub-count of InputTokens
}

CanonicalUsage holds token counts in a provider-neutral split: Input / Output / Total. The three buckets are the canonical view; sub-counts are optional refinements of InputTokens / OutputTokens (NOT subtracted from the totals). The nil-on-absence and total-synthesis contracts live in newCanonicalUsage.

type CohereAdapter added in v0.3.4

type CohereAdapter struct{}

func (*CohereAdapter) DecodeRequest added in v0.3.4

func (a *CohereAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*CohereAdapter) DecodeResponse added in v0.3.4

func (a *CohereAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*CohereAdapter) DecodeStreamChunk added in v0.3.4

func (a *CohereAdapter) DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)

func (*CohereAdapter) EncodeRequest added in v0.3.4

func (a *CohereAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*CohereAdapter) EncodeResponse added in v0.3.4

func (a *CohereAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*CohereAdapter) EncodeStreamChunk added in v0.3.4

func (a *CohereAdapter) EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)

type CohereEmbedAdapter added in v0.3.4

type CohereEmbedAdapter struct{}

func (*CohereEmbedAdapter) DecodeRequest added in v0.3.4

func (a *CohereEmbedAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*CohereEmbedAdapter) DecodeResponse added in v0.3.4

func (a *CohereEmbedAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*CohereEmbedAdapter) DecodeStreamChunk added in v0.3.4

func (a *CohereEmbedAdapter) DecodeStreamChunk([]byte) (*CanonicalStreamChunk, error)

func (*CohereEmbedAdapter) EncodeRequest added in v0.3.4

func (a *CohereEmbedAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*CohereEmbedAdapter) EncodeResponse added in v0.3.4

func (a *CohereEmbedAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*CohereEmbedAdapter) EncodeStreamChunk added in v0.3.4

func (a *CohereEmbedAdapter) EncodeStreamChunk(*CanonicalStreamChunk) ([][]byte, error)

type CohereRerankAdapter added in v0.3.4

type CohereRerankAdapter struct{}

CohereRerankAdapter maps gateway /v1/rerank payloads to Cohere v2 rerank wire format. The gateway speaks the same JSON shape as Cohere v2 rerank, so encode/decode are identity.

func (*CohereRerankAdapter) DecodeRequest added in v0.3.4

func (a *CohereRerankAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*CohereRerankAdapter) DecodeResponse added in v0.3.4

func (a *CohereRerankAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*CohereRerankAdapter) DecodeStreamChunk added in v0.3.4

func (a *CohereRerankAdapter) DecodeStreamChunk([]byte) (*CanonicalStreamChunk, error)

func (*CohereRerankAdapter) EncodeRequest added in v0.3.4

func (a *CohereRerankAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*CohereRerankAdapter) EncodeResponse added in v0.3.4

func (a *CohereRerankAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*CohereRerankAdapter) EncodeStreamChunk added in v0.3.4

func (a *CohereRerankAdapter) EncodeStreamChunk(*CanonicalStreamChunk) ([][]byte, error)

type Format

type Format string
const (
	FormatOpenAI           Format = "openai"
	FormatOpenAIResponses  Format = "openai_responses"
	FormatAnthropic        Format = "anthropic"
	FormatGemini           Format = "google"
	FormatBedrock          Format = "bedrock"
	FormatAzure            Format = "azure" // wire-compatible with OpenAI
	FormatGroq             Format = "groq"  // wire-compatible with OpenAI Chat Completions
	FormatVertex           Format = "vertex"
	FormatMistral          Format = "mistral"
	FormatDeepSeek         Format = "deepseek"   // wire-compatible with OpenAI Chat Completions
	FormatXAI              Format = "xai"        // wire-compatible with OpenAI Chat Completions
	FormatOpenRouter       Format = "openrouter" // wire-compatible with OpenAI Chat Completions
	FormatCohere           Format = "cohere"
	FormatOpenAIEmbeddings Format = "openai_embeddings"
	FormatCohereEmbed      Format = "cohere_embed"
	FormatCohereRerank     Format = "cohere_rerank"
)

func DetectFormat

func DetectFormat(body []byte) Format

func ResolveAgentFormat

func ResolveAgentFormat(providerName, sourceFormat string, providerOptions map[string]any) (Format, error)

func ResolveTargetFormat

func ResolveTargetFormat(providerName string, providerOptions map[string]any) Format

func ResolveTargetFormatForCapability added in v0.3.4

func ResolveTargetFormatForCapability(providerName string, capability string, providerOptions map[string]any) Format

ResolveTargetFormatForCapability picks the provider wire format for a proxy capability.

func (Format) IsOpenAIFamily added in v0.3.4

func (f Format) IsOpenAIFamily() bool

IsOpenAIFamily reports whether the format speaks an OpenAI-compatible wire protocol: Chat Completions (openai, azure, groq, deepseek) or the Responses API.

func (Format) SupportsCanonicalToolCalls added in v0.3.4

func (f Format) SupportsCanonicalToolCalls() bool

SupportsCanonicalToolCalls reports whether a response in this wire format can carry tool calls the gateway knows how to translate into the caller's format.

type GeminiAdapter

type GeminiAdapter struct{}

GeminiAdapter converts between Google Gemini generateContent format and the canonical internal model.

func (*GeminiAdapter) DecodeRequest

func (a *GeminiAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*GeminiAdapter) DecodeResponse

func (a *GeminiAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*GeminiAdapter) DecodeStreamChunk

func (a *GeminiAdapter) DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)

func (*GeminiAdapter) EncodeRequest

func (a *GeminiAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*GeminiAdapter) EncodeResponse

func (a *GeminiAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*GeminiAdapter) EncodeStreamChunk

func (a *GeminiAdapter) EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)

type MistralAdapter

type MistralAdapter struct {
	// contains filtered or unexported fields
}

func (*MistralAdapter) DecodeRequest

func (a *MistralAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*MistralAdapter) DecodeResponse

func (a *MistralAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*MistralAdapter) DecodeStreamChunk

func (a *MistralAdapter) DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)

func (*MistralAdapter) EncodeRequest

func (a *MistralAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*MistralAdapter) EncodeResponse

func (a *MistralAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*MistralAdapter) EncodeStreamChunk

func (a *MistralAdapter) EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)

type OpenAIAdapter

type OpenAIAdapter struct{}

OpenAIAdapter converts between OpenAI Chat Completions API format and the canonical internal model. It also acts as a dispatcher that auto-detects Responses API payloads and delegates decoding to the appropriate sub-adapter. Encoding always produces Chat Completions format; use OpenAIResponsesAdapter when Responses API encoding is needed.

func (*OpenAIAdapter) DecodeRequest

func (a *OpenAIAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*OpenAIAdapter) DecodeResponse

func (a *OpenAIAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*OpenAIAdapter) DecodeStreamChunk

func (a *OpenAIAdapter) DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)

func (*OpenAIAdapter) EncodeRequest

func (a *OpenAIAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*OpenAIAdapter) EncodeResponse

func (a *OpenAIAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*OpenAIAdapter) EncodeStreamChunk

func (a *OpenAIAdapter) EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)

type OpenAIEmbeddingsAdapter added in v0.3.4

type OpenAIEmbeddingsAdapter struct{}

func (*OpenAIEmbeddingsAdapter) DecodeRequest added in v0.3.4

func (a *OpenAIEmbeddingsAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*OpenAIEmbeddingsAdapter) DecodeResponse added in v0.3.4

func (a *OpenAIEmbeddingsAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*OpenAIEmbeddingsAdapter) DecodeStreamChunk added in v0.3.4

func (a *OpenAIEmbeddingsAdapter) DecodeStreamChunk([]byte) (*CanonicalStreamChunk, error)

func (*OpenAIEmbeddingsAdapter) EncodeRequest added in v0.3.4

func (a *OpenAIEmbeddingsAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*OpenAIEmbeddingsAdapter) EncodeResponse added in v0.3.4

func (a *OpenAIEmbeddingsAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*OpenAIEmbeddingsAdapter) EncodeStreamChunk added in v0.3.4

func (a *OpenAIEmbeddingsAdapter) EncodeStreamChunk(*CanonicalStreamChunk) ([][]byte, error)

type OpenAIResponsesAdapter

type OpenAIResponsesAdapter struct{}

OpenAIResponsesAdapter converts between OpenAI Responses API format and the canonical internal model. Registered under FormatOpenAIResponses so that the cross-provider pipeline (AdaptRequest/AdaptResponse/AdaptStreamChunk) automatically produces Responses API wire format for the client.

func (*OpenAIResponsesAdapter) DecodeRequest

func (a *OpenAIResponsesAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*OpenAIResponsesAdapter) DecodeResponse

func (a *OpenAIResponsesAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*OpenAIResponsesAdapter) DecodeStreamChunk

func (a *OpenAIResponsesAdapter) DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)

func (*OpenAIResponsesAdapter) EncodeRequest

func (a *OpenAIResponsesAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*OpenAIResponsesAdapter) EncodeResponse

func (a *OpenAIResponsesAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*OpenAIResponsesAdapter) EncodeStreamChunk

func (a *OpenAIResponsesAdapter) EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)

type OpenRouterAdapter added in v0.3.4

type OpenRouterAdapter struct {
	// contains filtered or unexported fields
}

OpenRouterAdapter wraps OpenAIAdapter and preserves OpenRouter routing fields.

func (*OpenRouterAdapter) DecodeRequest added in v0.3.4

func (a *OpenRouterAdapter) DecodeRequest(body []byte) (*CanonicalRequest, error)

func (*OpenRouterAdapter) DecodeResponse added in v0.3.4

func (a *OpenRouterAdapter) DecodeResponse(body []byte) (*CanonicalResponse, error)

func (*OpenRouterAdapter) DecodeStreamChunk added in v0.3.4

func (a *OpenRouterAdapter) DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)

func (*OpenRouterAdapter) EncodeRequest added in v0.3.4

func (a *OpenRouterAdapter) EncodeRequest(req *CanonicalRequest) ([]byte, error)

func (*OpenRouterAdapter) EncodeResponse added in v0.3.4

func (a *OpenRouterAdapter) EncodeResponse(resp *CanonicalResponse) ([]byte, error)

func (*OpenRouterAdapter) EncodeStreamChunk added in v0.3.4

func (a *OpenRouterAdapter) EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)

type ProviderAdapter

type ProviderAdapter interface {
	RequestAdapter
	ResponseAdapter
	StreamAdapter
}

ProviderAdapter combines all three conversion interfaces.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry holds provider adapters and exposes methods for cross-provider format adaptation. Unlike a global map+init(), a Registry is explicitly constructed and injected, making it testable and configurable.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates a Registry pre-populated with all built-in adapters.

func (*Registry) AdaptRequest

func (r *Registry) AdaptRequest(body []byte, source, target Format) ([]byte, error)

func (*Registry) AdaptResponse

func (r *Registry) AdaptResponse(body []byte, source, target Format) ([]byte, error)

AdaptResponse transforms a provider response from targetFormat back to sourceFormat via the canonical model: target.DecodeResponse → canonical → source.EncodeResponse.

If the two formats are wire-compatible the body is returned unmodified, except when provider-specific extensions require canonical filtering.

func (*Registry) AdaptStreamChunk

func (r *Registry) AdaptStreamChunk(chunk []byte, source, target Format) ([][]byte, error)

AdaptStreamChunk transforms a single SSE data payload from the target provider format to the source (caller) format via the canonical model.

If the two formats are wire-compatible the chunk is returned unmodified, except when provider-specific extensions require canonical filtering.

Returns (nil, nil) when the chunk should be skipped (e.g. Anthropic ping).

func (*Registry) DecodeRequestFor

func (r *Registry) DecodeRequestFor(body []byte, providerFormat Format) (*CanonicalRequest, error)

DecodeRequestFor decodes a raw provider request into the canonical model.

func (*Registry) DecodeResponseFor

func (r *Registry) DecodeResponseFor(body []byte, providerFormat Format) (*CanonicalResponse, error)

DecodeResponseFor decodes a raw provider response into the canonical model.

func (*Registry) DecodeStreamChunkFor

func (r *Registry) DecodeStreamChunkFor(chunk []byte, target Format) (*CanonicalStreamChunk, error)

DecodeStreamChunkFor decodes a single SSE data payload from the given provider format into a canonical stream chunk.

func (*Registry) EncodeStreamChunkFor

func (r *Registry) EncodeStreamChunkFor(canonical *CanonicalStreamChunk, source Format) ([][]byte, error)

EncodeStreamChunkFor encodes a canonical stream chunk into the given provider's SSE format.

func (*Registry) GetAdapter

func (r *Registry) GetAdapter(f Format) (ProviderAdapter, error)

GetAdapter returns the adapter for a format, resolving aliases.

func (*Registry) Register

func (r *Registry) Register(f Format, a ProviderAdapter)

Register adds or replaces an adapter for the given format.

type RequestAdapter

type RequestAdapter interface {
	DecodeRequest(body []byte) (*CanonicalRequest, error)
	EncodeRequest(req *CanonicalRequest) ([]byte, error)
}

RequestAdapter converts between a provider's native request format and the canonical internal model.

type RequestDecodeError

type RequestDecodeError struct {
	Format Format
	Cause  error
}

RequestDecodeError signals that the incoming request body could not be parsed into the expected provider format. The handler should surface this as an HTTP 400 instead of a 502.

func (*RequestDecodeError) Error

func (e *RequestDecodeError) Error() string

func (*RequestDecodeError) Unwrap

func (e *RequestDecodeError) Unwrap() error

type ResponseAdapter

type ResponseAdapter interface {
	DecodeResponse(body []byte) (*CanonicalResponse, error)
	EncodeResponse(resp *CanonicalResponse) ([]byte, error)
}

ResponseAdapter converts between a provider's native response format and the canonical internal model.

type StreamAdapter

type StreamAdapter interface {
	DecodeStreamChunk(chunk []byte) (*CanonicalStreamChunk, error)
	EncodeStreamChunk(chunk *CanonicalStreamChunk) ([][]byte, error)
}

StreamAdapter converts between a provider's native SSE chunk format and the canonical internal model.

EncodeStreamChunk returns a slice of raw SSE lines. Each element is written followed by "\n" by the handler. Typical elements include "event: …", "data: {…}" and "" (empty-line event separator). This allows providers that require multi-line SSE events (e.g. Anthropic's event: + data:) to produce a byte-accurate stream.

type StreamToolCallDelta

type StreamToolCallDelta struct {
	Index          int    `json:"index"`
	ID             string `json:"id,omitempty"`
	Name           string `json:"name,omitempty"`
	ArgumentsDelta string `json:"arguments_delta,omitempty"` // incremental piece
}

StreamToolCallDelta is one tool-call delta in a streamed response (OpenAI streams tool_calls with incremental arguments; Anthropic uses input_json_delta).

Jump to

Keyboard shortcuts

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