Documentation
¶
Overview ¶
Package clientcore provides the plumbing shared by the hand-rolled model provider clients (anthropic, gemini, openai): common construction defaults, the streaming request pipeline (retry, status classification, idle-timeout guard), SSE event decoding, and error-detail sanitization. Everything provider-specific — wire types, SSE event-accumulation grammar, error-body JSON shapes, auth headers — stays in the provider packages.
Index ¶
Constants ¶
const ( // DefaultMaxTokens is the output-token ceiling used when the caller passes // <= 0. The anthropic client previously defaulted to 4096, diverging from // openai/gemini; the app layer always passes a resolved value, so that // divergence was dead in practice — aligned to 8192 here. DefaultMaxTokens = 8192 // ResponseHeaderTimeout caps the wait for response headers // (time-to-first-byte); the streamed body then has no flat deadline (a // long completion is legitimate). ResponseHeaderTimeout = 2 * time.Minute // IdleTimeout aborts a stream that stalls (no bytes) for this long — the // streaming counterpart of an overall deadline, without killing an // actively-sending stream. IdleTimeout = 2 * time.Minute )
Variables ¶
This section is empty.
Functions ¶
func Detail ¶
Detail formats a provider error's structured kind/message pair as a sanitized ": kind: message" error suffix. Control characters are collapsed to spaces (log-injection defense) and the message is truncated, so a 4xx cause is diagnosable without echoing arbitrary upstream content into an Error-level log. Each provider parses its own error-body JSON shape and passes the extracted fields here.
func RawObject ¶
func RawObject(args string) json.RawMessage
RawObject ensures a tool call's argument payload is a JSON object ("" → {}) before it goes on the wire.
func SSEEvents ¶
SSEEvents parses an SSE stream into decoded events of type E. It wraps the generic httpx.SSEData framing primitive and json-unmarshals each event's data payload; a framing/read error or a JSON decode error is surfaced via the second yield value.
A provider whose stream grammar doesn't fit (e.g. openai's non-JSON [DONE] sentinel) keeps its own loop over httpx.SSEData.
Types ¶
type Base ¶
Base carries the configuration fields common to every provider client. Provider clients embed it and add their own knobs (e.g. reasoning effort).
func NewBase ¶
NewBase normalizes the shared constructor inputs: an empty baseURL falls back to defaultBaseURL (which may itself be empty for providers without a public default), trailing slashes are trimmed, maxTokens <= 0 falls back to DefaultMaxTokens, and the HTTP client is the hardened streaming client.
func (*Base) Stream ¶
func (b *Base) Stream(ctx context.Context, req Request, accumulate func(io.Reader) (providers.CompletionResponse, error)) (providers.CompletionResponse, error)
Stream sends req as a streaming POST and hands the response body — guarded by the idle-timeout reader — to accumulate, which folds the provider's SSE stream into a single CompletionResponse.
type Request ¶
type Request struct {
// Op names the operation in error messages (e.g. "messages", "chat").
Op string
// URL is the full endpoint URL.
URL string
// Body is the provider's wire-format request struct, marshaled as JSON.
Body any
// SetHeaders sets the provider's headers (content type, auth, version).
SetHeaders func(*http.Request)
// ErrorDetail parses a provider error body into a sanitized
// ": kind: message" suffix for the status error (see Detail), or "" if
// the body isn't a recognizable provider error.
ErrorDetail func(body []byte) string
}
Request describes one streaming completion call. Everything provider-specific about the HTTP exchange is injected here; the pipeline itself (retry, status classification, idle-timeout guard) is shared.