Documentation / guides
Codec architecture
Understand request, response, server, and stream codec ownership.
The codec boundary is a typed composition of request encoding, response decoding, and optional stream handling. It owns wire semantics only. The transport owns HTTP status mapping, body limits, authorization, and the request context.
Ownership
type EncodedRequest struct {
Header http.Header
Body io.Reader // consumed exactly once
}
type RequestEncoder interface {
EncodeRequest(inference.Request, RequestMode) (EncodedRequest, error)
}
type ResponseDecoder interface {
DecodeResponse([]byte) (*inference.Response, error)
}
type StreamDecoder interface {
DecodeStream(*http.Response) (*stream.StreamReader[content.Chunk], error)
}
type Codec interface {
RequestEncoder
ResponseDecoder
}
Codec intentionally does not embed StreamDecoder, so a non-streaming API
can satisfy the one-shot contract without a fake stream implementation.
StreamingCodec adds the optional decoder. EncodedRequest.Body is single-use;
the transport clears http.Request.GetBody and never retries it itself.
Stream lifetime
DecodeStream takes ownership of resp.Body. A successful return transfers
close responsibility to the returned reader. If framing or decoder setup fails
before a reader is returned, the decoder must close the body. The reader exposes
chunks through Next, publishes terminal metadata only after clean io.EOF,
and requires callers to call Close even after EOF.
%%{init: {"theme":"base","themeVariables":{"background":"#111827","primaryColor":"#1f2937","primaryTextColor":"#f9fafb","primaryBorderColor":"#60a5fa","lineColor":"#94a3b8","secondaryColor":"#172033","tertiaryColor":"#0f172a","fontFamily":"Inter, ui-sans-serif, system-ui"}}}%%
sequenceDiagram
participant H as HTTP response
participant C as Codec
participant R as StreamReader
H->>C: DecodeStream(resp)
C->>R: frame and map body
C-->>R: return reader
R-->>C: Next() chunks
R->>H: Close() owns body
Source and proof
Run go test ./codec/... ./stream/... ./transport/....