Skip to main content

Codec

Trait Codec 

Source
pub trait Codec:
    Send
    + Sync
    + 'static {
    // Required methods
    fn name(&self) -> &'static str;
    fn capabilities(&self, model: &str) -> Capabilities;
    fn encode(&self, request: &ModelRequest) -> Result<EncodedRequest>;
    fn decode(
        &self,
        body: &[u8],
        warnings_in: Vec<ModelWarning>,
    ) -> Result<ModelResponse>;

    // Provided methods
    fn auto_output_strategy(&self, _model: &str) -> OutputStrategy { ... }
    fn extract_rate_limit(
        &self,
        _headers: &HeaderMap,
    ) -> Option<RateLimitSnapshot> { ... }
    fn encode_streaming(&self, request: &ModelRequest) -> Result<EncodedRequest> { ... }
    fn decode_stream<'a>(
        &'a self,
        bytes: BoxByteStream<'a>,
        warnings_in: Vec<ModelWarning>,
    ) -> BoxDeltaStream<'a> { ... }
}
Expand description

Stateless encoder/decoder for ONE provider wire format.

A Codec knows nothing about HTTP, auth, or retries. It turns IR into bytes and bytes into IR. Streaming uses the same trait — decode_stream owns the codec’s parser state machine.

Required Methods§

Source

fn name(&self) -> &'static str

Stable codec identifier — "anthropic-messages", "openai-chat", etc. Used in logs and metrics tags.

Source

fn capabilities(&self, model: &str) -> Capabilities

Capability surface the codec advertises for the given model. Codecs vary by model (small models lacking vision, etc.).

Source

fn encode(&self, request: &ModelRequest) -> Result<EncodedRequest>

Encode IR → wire body for a one-shot (non-streaming) call. Implementors push warnings onto the returned EncodedRequest::warnings for any IR field they had to drop or coerce.

Source

fn decode( &self, body: &[u8], warnings_in: Vec<ModelWarning>, ) -> Result<ModelResponse>

Decode wire body → IR. warnings_in are the encode-time warnings that should be carried forward into ModelResponse::warnings so the caller sees the full advisory list in one place.

Provided Methods§

Source

fn auto_output_strategy(&self, _model: &str) -> OutputStrategy

Resolve OutputStrategy::Auto to the codec’s preferred dispatch shape for model. Called once at codec-construction time per request — never per-delta or per-retry, so the resolved strategy is part of the SessionGraph event log’s deterministic-replay surface.

Default returns OutputStrategy::Native — most codecs ship vendor-native structured output (OpenAI Responses text.format=json_schema, Gemini responseJsonSchema, Bedrock Anthropic-passthrough). Codecs whose native channel is newer / less mature than the tool-call surface (Anthropic Messages today — output_config ships without a strict toggle) override to OutputStrategy::Tool.

Source

fn extract_rate_limit(&self, _headers: &HeaderMap) -> Option<RateLimitSnapshot>

Extract a RateLimitSnapshot from response headers, if the vendor exposes rate-limit state in headers. Default returns None — codecs whose providers publish rate-limit headers override this and parse them.

Source

fn encode_streaming(&self, request: &ModelRequest) -> Result<EncodedRequest>

Encode IR → wire body for a streaming call. Default impl delegates to encode and marks the request as streaming; codecs that need a different body shape (e.g. stream: true field) or extra headers (e.g. Accept: text/event-stream) override.

Source

fn decode_stream<'a>( &'a self, bytes: BoxByteStream<'a>, warnings_in: Vec<ModelWarning>, ) -> BoxDeltaStream<'a>

Decode an incremental byte stream → IR StreamDelta stream.

Implementors own their parser state machine — Anthropic walks SSE events, OpenAI splits data: lines, Gemini reads NDJSON, Bedrock parses AWS event-stream frames. Default impl is a graceful fallback: collects every chunk, runs decode once at the end, and emits the resulting ModelResponse as a single StreamDelta::Stop. Concrete codecs replace it as soon as they support real token-level streaming.

Implementors§