v1

package
v0.7.0 Latest Latest
Warning

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

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

Documentation

Overview

Package v1 defines the relay's canonical protocol — the wire-neutral internal representation that all vendor adapters translate to and from.

What this package is

This is the lowest layer in the relay's type hierarchy. It declares:

  • Canonical request and response types (Request, Response).
  • Discriminated union types for items (Item), parts (Part), tools (Tool), and stream events (Event).
  • The Translator interface that every vendor adapter must implement.
  • Name and Registry for adapter registration.
  • SSE framing helpers shared by all stream paths.

What this package is NOT

This package knows nothing about specific vendors. It imports no app/, internal/, or pkg/adapters/* code. It is vendorable: external consumers can use the canonical types and Translator interface without pulling in any relay application code.

Design principles

Symmetric input/output: items you receive in output[] can be spliced into the next request's input[] without transformation. No tool_call_id gymnastics.

Typed discriminated unions: every polymorphic field uses a sealed interface. External packages cannot implement Item, Part, Tool, or Event, so type switches in adapters are exhaustive.

No request-echo in responses: the Response carries only what was produced. Vendor adapters that require echo (e.g. OpenAI Responses) receive *Request explicitly through SerializeResponse.

String-or-array input normalizes to array: wire allows "content": "hi" for terse single-text messages. Internal types always use []Part.

Extensions envelope: anything vendor-specific that doesn't map cleanly across all vendors lives in extensions: map[string]json.RawMessage on Request and Response. No new top-level canonical field for vendor-specific features.

Provider data: signed/encrypted vendor payloads (Anthropic thinking signatures, OpenAI encrypted_content) are carried on the relevant item as provider_data json.RawMessage. Round-tripped verbatim to the same vendor; dropped cross-vendor. Customers never construct it.

Index

Constants

View Source
const (
	EventGenerationCreated   = "generation.created"
	EventItemStarted         = "item.started"
	EventItemDelta           = "item.delta"
	EventItemCompleted       = "item.completed"
	EventGenerationCompleted = "generation.completed"
	EventError               = "error"
)

Canonical stream event name constants. These six events collapse OpenAI Responses' ~50 event types.

View Source
const (
	OutputModeSync   = "sync"
	OutputModeStream = "stream"
)

Variables

View Source
var ErrMultiplexNotImplemented = errors.New("multiplex_not_implemented")

ErrMultiplexNotImplemented is returned when the request specifies more than one model. The wire shape accepts []string; v1 runtime rejects multiplex so future support is additive.

Functions

func ExtractUsage

func ExtractUsage(tr Translator, body []byte) (usage.Tokens, error)

ExtractUsage decodes a vendor wire response body — sync JSON or SSE stream, optionally gzipped — into a canonical usage.Tokens map keyed by orthogonal meter dimensions (input, output, cache_read, …). Returns nil when the body carries no usage block (failed request, non-completion response, etc.); returns (nil, err) only for decompression failures we want to surface.

Three layers of normalization:

  • gzip: sniff magic bytes (0x1f 0x8b), decompress with stdlib.
  • SSE: sniff `event:`/`data:` framing. Walk frames, convert each vendor SSE frame to canonical via Translator.NewToCanonicalStream (the closure handles per-stream state), capture Usage from the terminal GenerationCompletedEvent.
  • sync JSON: hand the body to Translator.ParseResponse, read Response.Usage.

The helper lets observers speak canonical without per-vendor knowledge. Vendor adapters keep their narrow Translator interface; gzip + SSE handling lives in the canonical layer where it can be shared across every observer that needs Usage.

func IsReasoningEvent

func IsReasoningEvent(event string, data []byte) bool

IsReasoningEvent is IsReasoningFrame for an already-parsed frame: event name plus payload. Callers that have decoded the SSE frame (the client's Recv loop) avoid re-parsing.

func IsReasoningFrame

func IsReasoningFrame(frame []byte) bool

IsReasoningFrame reports whether a canonical SSE frame carries reasoning content — a reasoning item.started, a reasoning item.delta, or a reasoning item.completed. It lets a consumer time the reasoning span over a canonical stream without accumulating the content itself.

Cheap by design: non-item frames return on the event-name switch without parsing, and item frames decode only the single discriminator field (item_type / kind / item.type), not the full payload.

func Marshal

func Marshal(resp *Response) ([]byte, error)

Marshal encodes a Response to wire JSON. Output items are marshaled via their individual MarshalJSON implementations.

func ParseSSEChunk

func ParseSSEChunk(chunk []byte) (event string, data []byte, ok bool)

ParseSSEChunk extracts event and data from a raw SSE chunk (one frame, the bytes between two blank-line separators).

Types

type Annotation

type Annotation interface {
	AnnotationType() string
	// contains filtered or unexported methods
}

Annotation is a sealed interface for citation annotations on output text. Concrete types: *URLCitationAnnotation, *FileCitationAnnotation, *RawAnnotation.

type CacheConfig

type CacheConfig struct {
	// Instructions requests caching of the system/instructions prefix.
	Instructions bool `json:"instructions,omitempty"`
	// Tools requests caching of the tools block.
	Tools bool `json:"tools,omitempty"`
	// Key is an optional stable cache identity for the request's prefix
	// lineage — typically a conversation or session id, identical across
	// turns. It declares "requests sharing this key share a cacheable
	// prefix; keep them cache-local." Vendors that route to cache shards
	// per request (OpenAI: prompt_cache_key) combine it with the prefix
	// hash so same-key requests land on the same shard — without it,
	// routing is best-effort and long conversations take random total
	// cache misses. Vendors whose caching is deterministic (Anthropic
	// breakpoints) or keyless (Gemini implicit) ignore it. Keep the key
	// coarse enough that one key stays under the vendor's per-shard rate
	// (OpenAI: ~15 req/min per prefix+key).
	Key string `json:"key,omitempty"`
	// TTL is how long the cached prefix should stay reusable between
	// requests, as a Go duration string ("5m", "1h", "24h"). It is a hint:
	// each vendor clamps to its nearest supported retention tier —
	// Anthropic breakpoints upgrade to their 1-hour tier when TTL exceeds
	// the default 5 minutes (note: 1h writes cost 2× vs 1.25×); OpenAI maps
	// TTL over ~10 minutes to prompt_cache_retention "24h", at or under to
	// "in_memory". Unset means the vendor default. Unparseable values are
	// treated as unset.
	TTL string `json:"ttl,omitempty"`
}

CacheConfig is the vendor-neutral prompt-cache configuration for a request.

It declares *intent* only: which stable prefixes of the request the caller considers worth caching (Instructions/Tools), which requests share a prefix lineage (Key), and how long the prefix should stay reusable (TTL). There is deliberately no per-vendor cache vocabulary here — no "cache_control", no ephemeral/persistent distinction. A client sets identical values regardless of which vendor the request is routed to.

Adapter contract:

  • Vendors with explicit cache control (Anthropic) translate each enabled flag into the corresponding wire breakpoint and clamp TTL to their retention tiers; Key is ignored (their caching needs no routing hint).
  • Vendors that cache automatically with shard routing (OpenAI) ignore the flags and emit Key as the wire cache key (prompt_cache_key) and TTL as the retention tier (prompt_cache_retention).
  • Vendors with neither (Gemini implicit cache) ignore CacheConfig entirely — it is a no-op, never an error.

Semantics are cumulative in the vendor's own prefix order: an enabled flag means "everything up to and including this section is stable." Whether reads hit is observable via Response.Usage["cache_read"] / ["cache_creation"], which adapters already normalize across vendors.

Breakpoint budget: vendors cap explicit breakpoints (Anthropic allows 4). The flags here stay well within that bound; future per-Item history anchors (the "system_and_N" pattern) will share the same budget and are an additive extension, not a breaking change.

func (*CacheConfig) TTLDuration added in v0.5.0

func (c *CacheConfig) TTLDuration() (time.Duration, bool)

TTLDuration parses TTL. ok is false when TTL is unset or unparseable — adapters treat both as "vendor default", never an error.

type DeltaKind

type DeltaKind string

DeltaKind discriminates the delta payload within an item.delta event.

const (
	DeltaKindText      DeltaKind = "text"
	DeltaKindArguments DeltaKind = "arguments"
	DeltaKindReasoning DeltaKind = "reasoning"
)

type Error

type Error struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

Error is an API-level error embedded in a response object.

type ErrorEvent

type ErrorEvent struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

ErrorEvent carries a stream-level failure. After this event no further events are emitted.

type FilePart

type FilePart struct {
	FileURL   string `json:"file_url,omitempty"`
	FileID    string `json:"file_id,omitempty"`
	FileData  string `json:"file_data,omitempty"` // base64-encoded
	Filename  string `json:"filename,omitempty"`
	MediaType string `json:"media_type,omitempty"`
}

FilePart is an input_file content part. Exactly one of FileURL, FileID, or FileData is set on a valid part.

func (*FilePart) MarshalJSON

func (p *FilePart) MarshalJSON() ([]byte, error)

func (*FilePart) PartType

func (*FilePart) PartType() PartType

type FinishReason

type FinishReason string

FinishReason explains why generation stopped.

const (
	FinishReasonStop          FinishReason = "stop"
	FinishReasonLength        FinishReason = "length"
	FinishReasonContentFilter FinishReason = "content_filter"
	FinishReasonToolCalls     FinishReason = "tool_calls"
	// FinishReasonRefusal: refusal is a stop reason, not a part type.
	// The refusal text appears in a normal message item's text content.
	FinishReasonRefusal FinishReason = "refusal"
)

type Format

type Format struct {
	Type        string          `json:"type"`
	Name        string          `json:"name,omitempty"`        // json_schema only
	Description string          `json:"description,omitempty"` // json_schema only
	Schema      json.RawMessage `json:"schema,omitempty"`      // json_schema only
	Strict      *bool           `json:"strict,omitempty"`      // json_schema only
}

Format specifies the response format type. Type is one of: "text", "json_object", "json_schema".

type FunctionCall

type FunctionCall struct {
	ID           string          `json:"id,omitempty"`
	CallID       string          `json:"call_id"`
	Name         string          `json:"name"`
	Arguments    string          `json:"arguments"` // JSON string
	Status       Status          `json:"status,omitempty"`
	ProviderData json.RawMessage `json:"provider_data,omitempty"`
}

FunctionCall is an output item representing a tool invocation by the model. ProviderData carries vendor-specific opaque payloads for same-vendor round-trip fidelity. Customers never construct it.

func (*FunctionCall) ItemType

func (*FunctionCall) ItemType() ItemType

func (*FunctionCall) MarshalJSON

func (f *FunctionCall) MarshalJSON() ([]byte, error)

type FunctionCallOutput

type FunctionCallOutput struct {
	CallID  string `json:"call_id"`
	Output  string `json:"-"` // string form
	Content []Part `json:"-"` // array form; mutually exclusive with Output
}

FunctionCallOutput is an input item that delivers the result of a tool call. Exactly one of Output (string) or Content ([]Part) is set on a valid item.

func (*FunctionCallOutput) ItemType

func (*FunctionCallOutput) ItemType() ItemType

func (*FunctionCallOutput) MarshalJSON

func (f *FunctionCallOutput) MarshalJSON() ([]byte, error)

func (*FunctionCallOutput) UnmarshalJSON

func (f *FunctionCallOutput) UnmarshalJSON(data []byte) error

type FunctionTool

type FunctionTool struct {
	Name        string          `json:"name"`
	Description string          `json:"description,omitempty"`
	Parameters  json.RawMessage `json:"parameters"` // JSON schema; kept raw to avoid re-encoding user schemas
	Strict      *bool           `json:"strict,omitempty"`
}

FunctionTool is a caller-executed tool. The caller's code receives the tool_call item and submits a tool_result in the next request.

func (*FunctionTool) MarshalJSON

func (f *FunctionTool) MarshalJSON() ([]byte, error)

func (*FunctionTool) ToolType

func (*FunctionTool) ToolType() ToolType

type GenerationCompletedEvent

type GenerationCompletedEvent struct {
	ID           string       `json:"id"`
	Status       Status       `json:"status"`
	FinishReason FinishReason `json:"finish_reason,omitempty"`
	Usage        usage.Tokens `json:"usage,omitempty"`

	// RelayUsage rides the terminal event when the caller opted into echo
	// (X-WR-Usage: full) on a canonical stream. Relay-produced, nil
	// otherwise — the streaming counterpart of Response.RelayUsage. Only
	// the canonical stream carries it; vendor-shaped streams never do.
	RelayUsage *RelayUsage `json:"relay_usage,omitempty"`
}

GenerationCompletedEvent is the final event in a stream. Carries the terminal response status, finish reason, and aggregated token usage.

type GenerationCreatedEvent

type GenerationCreatedEvent struct {
	ID    string `json:"id"`
	Model string `json:"model"`
}

GenerationCreatedEvent is the first event in a stream. Carries the response id and model so clients can correlate the stream before any output arrives.

type IdentityTranslator

type IdentityTranslator struct{}

IdentityTranslator implements Translator for the canonical shape itself — the case the Translator doc anticipates with "when the wire IS canonical." Because the wire and canonical are the same, every method is a plain (de)serialization with no shape conversion, and the stream factories are no-ops (nil).

It serves two symmetric roles:

  • Server inbound: the relay's /v1/generate spec uses it so the generic cross-shape dispatch (inbound → canonical → upstream) serves canonical with no special-casing.
  • Client target: a canonical client (pkg/relay/client) uses it to talk to a relay server — serialize the canonical request, parse the canonical response — exactly as a vendor translator is used to talk to a vendor.

func (IdentityTranslator) NewFromCanonicalStream

func (IdentityTranslator) NewFromCanonicalStream() func(chunk []byte) ([]byte, error)

NewFromCanonicalStream is identity: canonical frames are already in the target shape, so they pass straight through. nil = no-op.

func (IdentityTranslator) NewToCanonicalStream

func (IdentityTranslator) NewToCanonicalStream() func(chunk []byte) ([]byte, error)

NewToCanonicalStream is identity: a canonical stream needs no conversion. nil = no-op.

func (IdentityTranslator) ParseRequest

func (IdentityTranslator) ParseRequest(body []byte) (*Request, error)

ParseRequest decodes a canonical request body — the wire is already canonical.

func (IdentityTranslator) ParseResponse

func (IdentityTranslator) ParseResponse(body []byte) (*Response, error)

ParseResponse decodes a canonical response body (reconstructing the Output item union — see the package ParseResponse).

func (IdentityTranslator) SerializeRequest

func (IdentityTranslator) SerializeRequest(req *Request) ([]byte, error)

SerializeRequest marshals a canonical request to the canonical wire (input included, model as string-or-array — see Request.MarshalJSON).

func (IdentityTranslator) SerializeResponse

func (IdentityTranslator) SerializeResponse(resp *Response, _ *Request) ([]byte, error)

SerializeResponse marshals the canonical response as-is. Item MarshalJSON methods render the output union; req is unused (no request-echo needed).

type ImagePart

type ImagePart struct {
	ImageURL string `json:"image_url,omitempty"`
	Detail   string `json:"detail,omitempty"` // "low" | "high" | "auto"
}

ImagePart is an input_image content part. Detail defaults to empty (server interprets as "auto").

func (*ImagePart) MarshalJSON

func (p *ImagePart) MarshalJSON() ([]byte, error)

func (*ImagePart) PartType

func (*ImagePart) PartType() PartType

type IncompleteDetails

type IncompleteDetails struct {
	Reason string `json:"reason,omitempty"`
}

IncompleteDetails explains why a response was not completed.

type Item

type Item interface {
	ItemType() ItemType
	// contains filtered or unexported methods
}

Item is a sealed interface for elements of the Input or Output array. Valid concrete types: *Message, *FunctionCall, *FunctionCallOutput, *Reasoning. External packages may not implement this interface.

func UnmarshalItem added in v0.3.0

func UnmarshalItem(data []byte) (Item, error)

UnmarshalItem decodes a single item from its wire JSON, dispatching on the "type" discriminator to the concrete Item type. Returns an explicit error for unsupported item types — consumers persisting or re-parsing items should use this instead of probing the type tag themselves, so a new item type fails loudly rather than being silently dropped.

func UnmarshalItems added in v0.3.0

func UnmarshalItems(data []byte) ([]Item, error)

UnmarshalItems decodes a JSON array of items via UnmarshalItem.

type ItemCacheConfig

type ItemCacheConfig struct {
	// Anchor marks this item as a cache breakpoint.
	Anchor bool `json:"anchor,omitempty"`
}

ItemCacheConfig is the per-item analogue of CacheConfig, carried on an input item (cache_config). It marks the item as a cache anchor: everything up to and including this item is a stable prefix. Same neutrality contract — supporting adapters emit a breakpoint at this item, others ignore it. Used for the rolling "stable history up to here" anchor as a conversation grows (the system_and_N pattern). Counts against the vendor breakpoint budget alongside the request-level CacheConfig flags.

type ItemCompletedEvent

type ItemCompletedEvent struct {
	ItemID string `json:"item_id"`
	Index  int    `json:"index"`
	Item   Item   `json:"item"`
}

ItemCompletedEvent signals that the current item has finished. Carries the fully assembled item for clients that want the complete value without accumulating deltas.

func (*ItemCompletedEvent) UnmarshalJSON added in v0.3.0

func (e *ItemCompletedEvent) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes the event, dispatching the polymorphic Item field via UnmarshalItem — Item is an interface, so plain json.Unmarshal cannot decode it. A missing or null item leaves the field nil.

type ItemDeltaEvent

type ItemDeltaEvent struct {
	ItemID string    `json:"item_id"`
	Index  int       `json:"index"`
	Kind   DeltaKind `json:"kind"`
	Delta  string    `json:"delta"`
}

ItemDeltaEvent carries an incremental chunk into the current item. Kind discriminates the delta payload: text for message content, arguments for function_call arguments, reasoning for reasoning content.

type ItemStartedEvent

type ItemStartedEvent struct {
	ItemID   string   `json:"item_id"`
	ItemType ItemType `json:"item_type"`
	// Index is the position of this item in the output array.
	Index int `json:"index"`
	// Name is the function name for FunctionCall items. Empty for other kinds.
	Name string `json:"name,omitempty"`
}

ItemStartedEvent signals that a new item has begun. Carries enough metadata to identify the item type without the full item body. For FunctionCall items Name is populated up front so downstream serializers (e.g. Anthropic's tool_use content_block_start, which requires the tool name on the open frame) can emit shape-correct wire bytes from the start event alone.

type ItemType

type ItemType string

ItemType is the wire discriminator for the input/output item union.

const (
	ItemTypeMessage            ItemType = "message"
	ItemTypeFunctionCall       ItemType = "function_call"
	ItemTypeFunctionCallOutput ItemType = "function_call_output"
	ItemTypeReasoning          ItemType = "reasoning"
)

type MCPTool

type MCPTool struct {
	Name      string            `json:"name,omitempty"`
	ServerURL string            `json:"server_url,omitempty"`
	Headers   map[string]string `json:"headers,omitempty"`
}

MCPTool is a relay-proxied MCP tool (v2). Wire-modeled in v1; runtime rejects it with tool_kind_not_implemented so future support is additive. ServerURL and Headers are for per-request ad-hoc MCP servers; Name alone references an operator-configured MCP server from the catalog.

func (*MCPTool) MarshalJSON

func (m *MCPTool) MarshalJSON() ([]byte, error)

func (*MCPTool) ToolType

func (*MCPTool) ToolType() ToolType

type Message

type Message struct {
	ID           string           `json:"id,omitempty"`
	Status       Status           `json:"status,omitempty"`
	Role         Role             `json:"role"`
	Content      []Part           `json:"-"` // normalized; use MarshalJSON/UnmarshalJSON
	CacheConfig  *ItemCacheConfig `json:"cache_config,omitempty"`
	ProviderData json.RawMessage  `json:"provider_data,omitempty"`
}

Message is an input or output message item (role + content). ProviderData carries vendor-specific opaque payloads for same-vendor round-trip fidelity. Customers never construct it.

func (*Message) ItemType

func (*Message) ItemType() ItemType

func (*Message) MarshalJSON

func (m *Message) MarshalJSON() ([]byte, error)

func (*Message) UnmarshalJSON

func (m *Message) UnmarshalJSON(data []byte) error

type ModelOpts

type ModelOpts struct {
	Sampling  *SamplingParams  `json:"sampling,omitempty"`
	Reasoning *ReasoningConfig `json:"reasoning,omitempty"`
	Output    *OutputConfig    `json:"output,omitempty"`
}

ModelOpts is per-model configuration keyed by model name in Request.ModelConfig. All fields are optional; nil means use the vendor default. Tool definitions are NOT here — they are task-level and live in Request.Tools (one spec shared across all models).

type ModelRefs

type ModelRefs []string

ModelRefs is the string-or-array union for the model field. Unmarshal accepts a JSON string OR a JSON array of strings. Always normalized to []string internally.

func (ModelRefs) MarshalJSON

func (m ModelRefs) MarshalJSON() ([]byte, error)

MarshalJSON emits a single ref as a bare string, multiple as an array.

func (*ModelRefs) UnmarshalJSON

func (m *ModelRefs) UnmarshalJSON(data []byte) error

type Name

type Name string

Name identifies an adapter at runtime. Catalog data references adapters by name; the registry maps names to live Translator instances.

type OutputConfig

type OutputConfig struct {
	Format    *Format `json:"format,omitempty"`
	Verbosity string  `json:"verbosity,omitempty"` // "low" | "medium" | "high"
}

OutputConfig controls output format and verbosity.

type OutputTextPart

type OutputTextPart struct {
	Text        string       `json:"text"`
	Annotations []Annotation `json:"-"` // polymorphic; see MarshalJSON
}

OutputTextPart is an output_text content part with optional annotations.

func (*OutputTextPart) MarshalJSON

func (p *OutputTextPart) MarshalJSON() ([]byte, error)

func (*OutputTextPart) PartType

func (*OutputTextPart) PartType() PartType

func (*OutputTextPart) UnmarshalJSON

func (p *OutputTextPart) UnmarshalJSON(data []byte) error

type Part

type Part interface {
	PartType() PartType
	// contains filtered or unexported methods
}

Part is a sealed interface for elements of a message's Content array. Valid concrete types: *TextPart, *ImagePart, *FilePart (input), *OutputTextPart (output). External packages may not implement this interface.

type PartType

type PartType string

PartType is the wire discriminator for the content part union.

const (
	PartTypeInputText  PartType = "input_text"
	PartTypeInputImage PartType = "input_image"
	PartTypeInputFile  PartType = "input_file"
	PartTypeOutputText PartType = "output_text"
)

type RawAnnotation

type RawAnnotation struct {
	Type string          `json:"type"`
	JSON json.RawMessage `json:"-"`
}

RawAnnotation preserves unknown annotation types for forward compatibility.

func (*RawAnnotation) AnnotationType

func (a *RawAnnotation) AnnotationType() string

func (*RawAnnotation) MarshalJSON

func (a *RawAnnotation) MarshalJSON() ([]byte, error)

type Reasoning

type Reasoning struct {
	ID           string          `json:"id,omitempty"`
	Summary      []SummaryText   `json:"summary,omitempty"`
	Content      string          `json:"content,omitempty"` // optional raw reasoning text
	Status       Status          `json:"status,omitempty"`
	ProviderData json.RawMessage `json:"provider_data,omitempty"`
}

Reasoning is an output item representing the model's reasoning steps. ProviderData carries vendor-specific opaque payloads (e.g. Anthropic thinking signatures, OpenAI encrypted_content) for same-vendor round-trip fidelity. Customers never construct it.

func (*Reasoning) ItemType

func (*Reasoning) ItemType() ItemType

func (*Reasoning) MarshalJSON

func (r *Reasoning) MarshalJSON() ([]byte, error)

type ReasoningConfig

type ReasoningConfig struct {
	Effort       string `json:"effort,omitempty"`
	Summary      string `json:"summary,omitempty"`
	BudgetTokens *int   `json:"budget_tokens,omitempty"`
}

ReasoningConfig controls reasoning effort. Effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh". Summary: "auto" | "concise" | "detailed".

type Registry

type Registry map[Name]Translator

Registry maps an adapter Name to its Translator. The composition root populates the registry; consumers look up by name. Read-only after startup.

func (Registry) Get

func (r Registry) Get(name Name) Translator

Get returns the translator for name, or nil if absent.

type RelayTiming

type RelayTiming struct {
	Upstream RelayUpstreamTiming `json:"upstream"`
	End      int64               `json:"end"` // start → response ready
}

RelayTiming is the per-request checkpoint breakdown. All values are microseconds elapsed from the request start (the anchor) — the unit lives here, on the struct, not in the field names, and every mark is anchored to start rather than chained. Derive intervals by subtracting:

relay pre-overhead = Upstream.Start
upstream TTFT      = Upstream.ResponseStart - Upstream.Start
stream body time   = Upstream.ResponseEnd   - Upstream.ResponseStart
relay tail         = End                    - Upstream.ResponseEnd

type RelayUpstreamTiming

type RelayUpstreamTiming struct {
	Start         int64 `json:"start"`          // start → handed to upstream
	ResponseStart int64 `json:"response_start"` // start → first upstream byte (TTFT)
	ResponseEnd   int64 `json:"response_end"`   // start → upstream done
}

RelayUpstreamTiming groups the upstream-leg checkpoints, each µs from the request start.

type RelayUsage

type RelayUsage struct {
	RequestID    string       `json:"request_id,omitempty"`
	Tokens       usage.Tokens `json:"tokens,omitempty"`
	FinishReason FinishReason `json:"finish_reason,omitempty"`
	Attempts     int          `json:"attempts,omitempty"` // upstream tries (>1 = failover)
	Streamed     bool         `json:"streamed,omitempty"`
	Timing       *RelayTiming `json:"timing,omitempty"`
}

RelayUsage is the caller-facing slice of relay's per-request telemetry, emitted only when echo is requested. Deliberately a public subset of the internal usage record — no relay-key hash, policy/host UUIDs, or other operator-only attribution.

type Request

type Request struct {
	Input        []Item `json:"-"` // normalized from string-or-array at parse
	Instructions string `json:"instructions,omitempty"`

	Model       ModelRefs             `json:"model"`
	ModelConfig map[string]*ModelOpts `json:"model_config,omitempty"`

	// Tools is the task-level tool spec (definitions + choice + parallel),
	// shared across every model in a multiplex request. It is NOT per-model:
	// the spec is a property of the task, and the upstream adapter decides how
	// to render it. Per-model knobs (sampling/reasoning/output) live in
	// ModelConfig.
	Tools *ToolsConfig `json:"tools,omitempty"`

	// CacheConfig is the vendor-neutral prompt-cache configuration. Supporting
	// adapters emit breakpoints; others ignore it. See CacheConfig type.
	CacheConfig *CacheConfig `json:"cache_config,omitempty"`

	OutputMode string `json:"output_mode,omitempty"` // "sync" | "stream"

	User       string                     `json:"user,omitempty"`
	Metadata   map[string]string          `json:"metadata,omitempty"`
	Extensions map[string]json.RawMessage `json:"extensions,omitempty"`
}

Request is the canonical inbound request body for /v1/generate. Input is always normalized to []Item internally; callers never see the string form.

func Parse

func Parse(body []byte) (*Request, error)

Parse decodes a canonical /v1/generate request body into a *Request.

Normalization applied:

  • string input → []Item{&Message{Role:RoleUser, Content:[]Part{&TextPart{...}}}}
  • string content inside messages → []Part{&TextPart{...}}
  • unsupported item types return an explicit error (caller maps to 400)
  • unsupported tool types return an explicit error (caller maps to 400)
  • model string → []string{model}; array accepted but multiplex rejected at runtime

func (*Request) MarshalJSON

func (r *Request) MarshalJSON() ([]byte, error)

MarshalJSON emits a single model as a bare JSON string and multiple as an array — symmetric with UnmarshalJSON. The single-string form keeps the wire compatible with minimal `{"model": string}` probes on the receiving side.

type Response

type Response struct {
	ID           string       `json:"id"`
	Object       string       `json:"object"`     // always "response"
	CreatedAt    int64        `json:"created_at"` // unix seconds
	Model        string       `json:"model"`
	Status       Status       `json:"status"`
	FinishReason FinishReason `json:"finish_reason,omitempty"`
	Output       []Item       `json:"output,omitempty"`

	// Usage is the orthogonal-meter token map (input, output, cache_read,
	// cache_creation, reasoning, audio_input, audio_output, …). Keys
	// match pricing.MeterForUsageKey so the same vocabulary flows from
	// adapters through observers through pricing without translation.
	// Some keys are sub-breakdowns of a coarser one (reasoning/audio_output
	// ⊂ output) — so a provider total_tokens is input + output, not
	// Tokens.Sum() over the whole map, which would double-count them.
	Usage usage.Tokens `json:"usage,omitempty"`

	Error             *Error             `json:"error,omitempty"`
	IncompleteDetails *IncompleteDetails `json:"incomplete_details,omitempty"`

	// RelayUsage is relay-produced observability for this request: token
	// counts, finish reason, timing (TTFT, total), retry attempts. It is
	// the ONE field no vendor adapter ever populates — it's always nil on
	// a normal round-trip, and only set when the caller opts in with
	// `X-WR-Usage: full`. Declared here (a relay-native first-class field,
	// like CacheConfig) so
	// the canonical client and schema stay honest about what relay can put
	// on the wire. On vendor-shaped responses relay injects the same JSON
	// as a top-level `relay_usage` key after translation; vendor SDKs
	// ignore it.
	RelayUsage *RelayUsage `json:"relay_usage,omitempty"`

	// Extensions carries vendor-specific or cross-cutting response fields.
	Extensions map[string]json.RawMessage `json:"extensions,omitempty"`
}

Response is the canonical non-streaming response. It carries only what was produced — no request-echo fields. Vendor adapters that require echo (e.g. OpenAI Responses) receive the original *Request explicitly via SerializeResponse.

func ParseResponse

func ParseResponse(body []byte) (*Response, error)

ParseResponse decodes a canonical response body — the inverse of marshaling a *Response. It exists because Output is an interface slice ([]Item) whose concrete types are chosen by each item's "type" field, so the stdlib decoder can't reconstruct them on its own. Used by canonical clients reading /v1/generate responses.

func UnmarshalResponse

func UnmarshalResponse(data []byte) (*Response, error)

UnmarshalResponse decodes a wire JSON response into a *Response. Output items are dispatched via UnmarshalItem.

type Role

type Role string

Role enumerates valid message roles.

const (
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
	RoleSystem    Role = "system"
	RoleDeveloper Role = "developer"
)

type SSEFrame

type SSEFrame struct {
	Event string // one of the Event* constants in events.go
	Data  []byte // JSON-marshaled event payload
}

SSEFrame is one server-sent event ready for the wire: an event name plus the JSON-marshaled event payload.

func (SSEFrame) Bytes

func (f SSEFrame) Bytes() []byte

Bytes serializes the frame to its on-wire SSE form:

event: <name>\ndata: <json>\n\n

type SamplingParams

type SamplingParams struct {
	Temperature      *float64 `json:"temperature,omitempty"`
	TopP             *float64 `json:"top_p,omitempty"`
	TopK             *int     `json:"top_k,omitempty"`
	MaxTokens        *int     `json:"max_tokens,omitempty"`
	Stop             []string `json:"stop,omitempty"`
	Seed             *int     `json:"seed,omitempty"`
	FrequencyPenalty *float64 `json:"frequency_penalty,omitempty"`
	PresencePenalty  *float64 `json:"presence_penalty,omitempty"`
}

SamplingParams controls token sampling. All fields default-OK when nil.

type ServerTool

type ServerTool struct {
	Name string `json:"name"`
}

ServerTool is a relay-executed tool (v2). Wire-modeled in v1; runtime rejects it with tool_kind_not_implemented so future support is additive.

func (*ServerTool) MarshalJSON

func (s *ServerTool) MarshalJSON() ([]byte, error)

func (*ServerTool) ToolType

func (*ServerTool) ToolType() ToolType

type Status

type Status string

Status is the item or response lifecycle state.

const (
	StatusCompleted  Status = "completed"
	StatusIncomplete Status = "incomplete"
	StatusFailed     Status = "failed"
	StatusInProgress Status = "in_progress"
)

type StreamSummarizer added in v0.6.0

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

StreamSummarizer is the incremental counterpart to ExtractSummary's SSE path: instead of buffering a whole vendor SSE body and walking it once at the end, it harvests the Summary frame-by-frame as they arrive, retaining only the running canonical stream state and the last usage-bearing Summary. Feeding every frame of a body to a StreamSummarizer yields the same Summary that ExtractSummary would return for the concatenated body — same per-frame translation, same "last non-empty summary wins" rule — so a streamed observer never has to retain the whole stream to report usage.

Not safe for concurrent use: one stream, one summarizer, one goroutine (the translator closure it holds carries per-stream state).

func NewStreamSummarizer added in v0.6.0

func NewStreamSummarizer(tr Translator) *StreamSummarizer

NewStreamSummarizer builds a summarizer bound to tr's to-canonical stream transform. A nil translator yields a no-op summarizer (Summary stays zero), matching ExtractSummary(nil, …).

func (*StreamSummarizer) Observe added in v0.6.0

func (s *StreamSummarizer) Observe(frame []byte)

Observe feeds one vendor SSE frame — a single event, WITHOUT the trailing blank-line separator (it is re-appended internally, mirroring extractSummaryFromSSE which feeds the closure separator-terminated chunks). Usage/finish from a terminal generation.completed event replaces the retained Summary wholesale (last non-empty wins), exactly as the batch ExtractSummary does.

func (*StreamSummarizer) Summary added in v0.6.0

func (s *StreamSummarizer) Summary() Summary

Summary returns the Summary harvested so far (zero until a usage-bearing frame is seen). Nil-safe.

type Summary

type Summary struct {
	Tokens       usage.Tokens
	FinishReason FinishReason
}

Summary is the canonical post-flight view of a response body: token counts plus the finish reason. Both are harvested in a single decode (one ParseResponse / one SSE walk) so observers don't double-parse.

func ExtractSummary

func ExtractSummary(tr Translator, body []byte) (Summary, error)

ExtractSummary decodes a vendor wire response body — sync JSON or SSE stream, optionally gzipped — into a canonical Summary. Returns the zero Summary when the body carries no completion block; returns an error only for decompression failures we want to surface. Same three-layer normalization as ExtractUsage (which is now a thin wrapper).

type SummaryText

type SummaryText struct {
	Text string `json:"text"`
}

SummaryText is one element of a Reasoning item's summary array.

type TextCitationAnnotation

type TextCitationAnnotation struct {
	StartIndex int `json:"start_index"`
	EndIndex   int `json:"end_index"`
}

TextCitationAnnotation is a text_citation annotation referencing a span in an upstream document. StartIndex and EndIndex are byte offsets into the cited source text.

func (*TextCitationAnnotation) AnnotationType

func (*TextCitationAnnotation) AnnotationType() string

func (*TextCitationAnnotation) MarshalJSON

func (a *TextCitationAnnotation) MarshalJSON() ([]byte, error)

type TextPart

type TextPart struct {
	Text string `json:"text"`
}

TextPart is an input_text content part.

func (*TextPart) MarshalJSON

func (p *TextPart) MarshalJSON() ([]byte, error)

func (*TextPart) PartType

func (*TextPart) PartType() PartType

type Tool

type Tool interface {
	ToolType() ToolType
	// contains filtered or unexported methods
}

Tool is a sealed interface for elements of the Tools array. Valid concrete types: *FunctionTool, *ServerTool, *MCPTool. External packages may not implement this interface.

type ToolChoice

type ToolChoice struct {
	Mode         string // "auto" | "required" | "none" | "function"
	FunctionName string // only when Mode == "function"
}

ToolChoice is polymorphic: a string shorthand ("auto", "required", "none") or a {type:"function", name:"..."} object.

func (ToolChoice) MarshalJSON

func (tc ToolChoice) MarshalJSON() ([]byte, error)

func (*ToolChoice) UnmarshalJSON

func (tc *ToolChoice) UnmarshalJSON(data []byte) error

type ToolType

type ToolType string

ToolType is the wire discriminator for the tool union.

const (
	ToolTypeFunction ToolType = "function"
	ToolTypeServer   ToolType = "server"
	ToolTypeMCP      ToolType = "mcp"
)

type Tools

type Tools []Tool

Tools is a polymorphic slice of Tool values.

func (Tools) MarshalJSON

func (ts Tools) MarshalJSON() ([]byte, error)

func (*Tools) UnmarshalJSON

func (ts *Tools) UnmarshalJSON(data []byte) error

type ToolsConfig

type ToolsConfig struct {
	Definitions Tools       `json:"definitions,omitempty"`
	Choice      *ToolChoice `json:"choice,omitempty"`
	Parallel    *bool       `json:"parallel,omitempty"`
}

ToolsConfig is the task-level tool spec carried on Request.Tools. It groups the tool definitions with their selection knobs (choice/parallel). One spec applies to every model in a multiplex request — tools are a property of the task, not the model, and each upstream adapter renders this onto its own wire shape.

type Translator

type Translator interface {
	// ParseRequest reads a vendor's wire request body and returns canonical.
	ParseRequest(body []byte) (*Request, error)

	// SerializeRequest emits a vendor's wire request body from canonical.
	SerializeRequest(req *Request) ([]byte, error)

	// ParseResponse reads a vendor's wire response body and returns canonical.
	ParseResponse(body []byte) (*Response, error)

	// SerializeResponse emits a vendor's wire response body from canonical.
	// req is the original canonical request, passed for wire shapes that
	// require request-echo on the response (e.g. OpenAI Responses). May
	// be nil if the caller doesn't have it or the adapter doesn't need it.
	SerializeResponse(resp *Response, req *Request) ([]byte, error)

	// NewToCanonicalStream returns a stateful per-stream function that
	// converts one SSE chunk from the vendor's stream shape into one or
	// more canonical SSE chunks. Returns nil if no transform is needed
	// (identity, e.g. when the wire IS canonical).
	NewToCanonicalStream() func(chunk []byte) ([]byte, error)

	// NewFromCanonicalStream returns a stateful per-stream function that
	// converts one SSE chunk from canonical into one or more chunks of
	// the vendor's stream shape. Returns nil for identity.
	NewFromCanonicalStream() func(chunk []byte) ([]byte, error)
}

Translator converts between a vendor's wire shape and canonical. All methods are stateless — a single Translator value is reused across requests. Per-stream state lives in the closures returned by the two stream factories.

type URLCitationAnnotation

type URLCitationAnnotation struct {
	StartIndex int    `json:"start_index"`
	EndIndex   int    `json:"end_index"`
	URL        string `json:"url"`
	Title      string `json:"title,omitempty"`
}

URLCitationAnnotation is a url_citation annotation on output text.

func (*URLCitationAnnotation) AnnotationType

func (*URLCitationAnnotation) AnnotationType() string

func (*URLCitationAnnotation) MarshalJSON

func (a *URLCitationAnnotation) MarshalJSON() ([]byte, error)

Jump to

Keyboard shortcuts

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