Documentation
¶
Overview ¶
Package transport is Polaris's single outbound HTTP core. Every provider adapter issues upstream requests through a transport.Client, which owns the one retry loop (full-jitter backoff, Retry-After, per-provider attempt count), authentication decoration (Bearer, API-key headers, SigV4, OAuth, HMAC), error translation into apierror, and provider client spans. It replaces the ~8 copy-pasted retry loops that previously lived in each provider package.
Index ¶
- func AddObserver(hook AttemptHook)
- func ResetObservers()
- type AttemptHook
- type AttemptInfo
- type AuthFunc
- type Client
- func (c *Client) BaseURL() string
- func (c *Client) Do(ctx context.Context, r Request) (*http.Response, error)
- func (c *Client) HTTPClient() *http.Client
- func (c *Client) JSON(ctx context.Context, method, path string, in, out any, mods ...ReqOption) error
- func (c *Client) ProviderName() string
- func (c *Client) Raw(ctx context.Context, method, path string, body io.Reader, contentType string, ...) (*http.Response, error)
- func (c *Client) Stream(ctx context.Context, method, path string, in any, mods ...ReqOption) (*http.Response, error)
- type ErrorTranslator
- type Options
- type ReqOption
- type Request
- type RetryPolicy
- type SSEFrame
- type SSEReader
- type SSRFClient
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddObserver ¶
func AddObserver(hook AttemptHook)
AddObserver registers a process-lifetime observer invoked for every attempt on every Client. Intended to be called during startup (before serving); safe to call concurrently.
func ResetObservers ¶
func ResetObservers()
ResetObservers removes all registered observers. Tests only.
Types ¶
type AttemptHook ¶
type AttemptHook func(AttemptInfo)
AttemptHook observes a single attempt. Hooks must not block; they feed health/latency accounting and span annotation.
type AttemptInfo ¶
type AttemptInfo struct {
Provider string // display name, e.g. "OpenAI"
Slug string // stable low-cardinality key, e.g. "openai" (matches config/registry)
Attempt int
Method string
Path string
Status int
Err error
Latency time.Duration
}
AttemptInfo describes one HTTP attempt for observers (the reliability manager and tracing). It is emitted once per attempt, including retries.
type AuthFunc ¶
AuthFunc decorates an outbound request with credentials. It receives the exact request body bytes so signing strategies (AWS SigV4, Volcengine HMAC) can hash the payload. It is invoked once per attempt on a freshly built request. A nil AuthFunc leaves the request unauthenticated (e.g. local Ollama).
func APIKeyHeaderAuth ¶
APIKeyHeaderAuth returns an AuthFunc that sets a single API-key header, e.g. ("x-api-key", key) for Anthropic or ("xi-api-key", key) for ElevenLabs.
func BearerAuth ¶
BearerAuth returns an AuthFunc that sets "Authorization: Bearer <token>".
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a configured outbound HTTP client for one provider.
func (*Client) Do ¶
Do runs the retry loop and returns the raw response. The caller owns and must close resp.Body. Do never returns a drained/closed response: a status- or transport-level retry that is interrupted mid-backoff returns an error.
func (*Client) HTTPClient ¶
HTTPClient exposes the underlying *http.Client for the rare adapter that must issue a bespoke request (e.g. binary asset download) outside the retry loop.
func (*Client) JSON ¶
func (c *Client) JSON(ctx context.Context, method, path string, in, out any, mods ...ReqOption) error
JSON marshals in (when non-nil) as the request body, executes the request, and decodes a success response into out (when non-nil). Non-2xx responses are converted through the provider's ErrorTranslator.
func (*Client) ProviderName ¶
ProviderName returns the display name used in error messages.
func (*Client) Raw ¶
func (c *Client) Raw(ctx context.Context, method, path string, body io.Reader, contentType string, mods ...ReqOption) (*http.Response, error)
Raw executes a request with a caller-provided body reader (e.g. multipart) and returns the raw response. The caller owns and must close resp.Body.
func (*Client) Stream ¶
func (c *Client) Stream(ctx context.Context, method, path string, in any, mods ...ReqOption) (*http.Response, error)
Stream marshals in (when non-nil) and returns the raw response for the caller to read (SSE or binary). The caller owns and must close resp.Body. Error statuses are translated and the body closed before returning.
type ErrorTranslator ¶
ErrorTranslator converts an upstream error response (status + body) into a canonical Polaris APIError. Each provider supplies one so its native error envelope is parsed while the resulting taxonomy stays uniform.
type Options ¶
type Options struct {
BaseURL string
ProviderName string // display name used in error messages, e.g. "OpenAI"
ProviderSlug string // low-cardinality slug for provider spans, e.g. "openai"
Auth AuthFunc
StaticHeaders map[string]string
Timeout time.Duration
Retry RetryPolicy
ErrorTranslator ErrorTranslator
Hooks []AttemptHook
// HTTPClient overrides the constructed client (tests). When set, Timeout and
// the provider-span RoundTripper are not applied.
HTTPClient *http.Client
}
Options configures a Client.
type ReqOption ¶
type ReqOption func(*Request)
ReqOption mutates a Request built by the JSON/Stream/Raw helpers.
func WithHeader ¶
WithHeader sets one per-request header.
func WithHeaders ¶
WithHeaders sets several per-request headers.
type Request ¶
type Request struct {
Method string
Path string // relative to BaseURL, or an absolute URL
Query url.Values
Body []byte
BodyReader io.Reader
ContentType string
Accept string
Headers map[string]string
}
Request is one logical outbound request. Body carries the canonical payload bytes so the retry loop can rebuild a fresh *http.Request each attempt; use BodyReader only for non-retryable streaming bodies (multipart uploads), which force a single attempt.
type RetryPolicy ¶
type RetryPolicy struct {
MaxAttempts int
InitialDelay time.Duration
MaxDelay time.Duration
RespectRetryAfter bool
}
RetryPolicy governs the transport's per-request retry loop. MaxAttempts is taken from each provider's configuration exactly as before (1 == no retry), so migrating a provider onto the transport never changes how many times it retries. The behavior improvements over the old per-provider loops are: full-jitter backoff, honoring Retry-After, and never returning a drained response when a backoff sleep is interrupted.
type SSEFrame ¶
SSEFrame is one server-sent-events frame: an optional event name and the concatenated data payload.
type SSEReader ¶
type SSEReader struct {
// contains filtered or unexported fields
}
SSEReader parses a text/event-stream body into frames. It is modality-neutral: callers translate each frame's Data (JSON) into their own chunk types. It handles CRLF, multi-line data accumulation, `event:` names, comment lines (leading ':'), and a trailing frame with no terminating blank line, and guards against pathologically large frames.
func NewSSEReader ¶
NewSSEReader wraps r with the default max-frame guard (1 MiB).
type SSRFClient ¶
type SSRFClient struct {
// contains filtered or unexported fields
}
SSRFClient is an outbound HTTP client hardened against server-side request forgery: it enforces an allowed-scheme list, a denied-host list, and blocks private/reserved IPs at both URL-validation and dial time (so DNS rebinding cannot slip a public hostname onto an internal address). It is used to fetch caller-supplied file URLs.
func NewSSRFClient ¶
func NewSSRFClient(cfg config.FileSSRFConfig, timeout time.Duration) *SSRFClient
NewSSRFClient builds an SSRFClient from the files SSRF configuration.
func (*SSRFClient) ValidateURL ¶
func (c *SSRFClient) ValidateURL(rawURL string) error
ValidateURL enforces the scheme allow-list, host deny-list, and literal-IP block.