inference

package
v0.9.3 Latest Latest
Warning

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

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

Documentation

Overview

Package inference's Dispatch is the shape-agnostic per-request flow. It owns: classification branching (proxy vs normal), routing resolution, translator chaining (inbound ↔ canonical ↔ upstream), pipeline invocation, and response wrapping.

Per-shape routes (registered via app/adapter.MountRoutes) own only:

  1. Minimal parse to extract the model name + stream flag.
  2. The Dispatch call with the inbound shape Name.

This keeps shape-specific files out of app/httpapi/inference/.

Package inference is the data-plane HTTP API: /v1/* and /healthz.

Mount(r, deps) wires huma+chi onto an existing chi router and returns the huma.API. The package owns its huma.Config; main.go constructs Deps and calls Mount.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidProxyMode   = errors.New("inference: invalid X-WR-Proxy-Mode value")
	ErrMissingUpstreamKey = errors.New("inference: proxy mode requires Authorization: Bearer <upstream-key>")
)

Sentinel errors returned by Classify. The middleware maps these to 400.

Functions

func ClassifyMiddleware

func ClassifyMiddleware() func(http.Handler) http.Handler

ClassifyMiddleware runs Classify once per request and stashes the result on ctx. Shape-invalid requests get a 400 envelope; everything else falls through to the next handler. Gating (Settings.ProxyMode flags, unknown-slug rejection) lives downstream so this middleware stays snapshot-free.

func Dispatch

func Dispatch(d Deps, w http.ResponseWriter, r *http.Request, in DispatchInput)

Dispatch runs the shape-agnostic flow. Called from route handlers after a minimal parse to extract ModelName + Stream.

func ExtractModelStream

func ExtractModelStream(body []byte) (model string, stream bool, err error)

ExtractModelStream parses the caller-supplied model name and stream flag from a request body. Reused by the batch subsystem's per-item runner.

func ForwardUpstreamHeaders

func ForwardUpstreamHeaders(dst, src http.Header)

ForwardUpstreamHeaders copies src → dst, dropping hop-by-hop. The caller is responsible for any further adjustments (e.g. clearing Content-Length when the body size will change between upstream and client). Exported so adapter packages can use it from their own cross-shape handlers.

func MapPipelineErr

func MapPipelineErr(w http.ResponseWriter, err error)

MapPipelineErr is the exported form for adapter-side cross-shape handlers that drive pipeline.Pipeline.Run directly.

func Mount

func Mount(r chi.Router, d Deps) huma.API

Mount installs the data-plane huma API on r and registers all operations. Returns the huma.API so the caller can attach test-only operations.

func ReadinessMiddleware

func ReadinessMiddleware(cat *appcatalog.Catalog) func(http.Handler) http.Handler

ReadinessMiddleware short-circuits inbound /v1/* requests with 503 until the catalog has built its first snapshot. Until then, lookups against the empty zero-value snapshot would look identical to a legitimately empty catalog — better to refuse traffic explicitly so the caller retries instead of seeing a misleading 404. /healthz is mounted outside this middleware so liveness/readiness probes can still report.

func RelayKeyAuthMiddleware

func RelayKeyAuthMiddleware(cat *appcatalog.Catalog) func(http.Handler) http.Handler

RelayKeyAuthMiddleware authenticates the inbound relay key according to the request's Mode classification (set by ClassifyMiddleware upstream):

  • ModeNormal — relay key is required; lookup must succeed.
  • ModeProxyAuthed — relay key is required; lookup must succeed.
  • ModeProxyAnonymous — no relay key; this middleware is a no-op and no *RelayKey is stashed on ctx.

Snapshot is read on every request so admins toggling Enabled / RevokedAt take effect within the NOTIFY debounce window.

func RelayKeyFromContext

func RelayKeyFromContext(ctx context.Context) *relaykey.RelayKey

RelayKeyFromContext returns the authenticated relay key from ctx, or nil if no relay-key middleware fired.

func RewriteModelField

func RewriteModelField(body []byte, upstreamModel string) []byte

RewriteModelField returns body with its "model" field rewritten to upstreamModel (the resolved upstream model name). Reused by the batch subsystem's per-item runner.

func SplitSSEChunks

func SplitSSEChunks(data []byte, atEOF bool) (advance int, token []byte, err error)

SplitSSEChunks is exported so adapter packages can use the same SSE chunking logic in their cross-shape stream handlers.

func WithClassification

func WithClassification(ctx context.Context, c Classification) context.Context

WithClassification returns a child ctx carrying c.

func WriteAPIError

func WriteAPIError(w http.ResponseWriter, status int, errType, code, msg string, attrs ...any)

WriteAPIError emits an OpenAI-shape error envelope. Exported so per-shape route packages (app/adapters/<name>/routes.go) can use it without depending on shape-specific helpers. Extra slog attrs are attached to the warning log only — never to the client envelope.

Types

type Classification

type Classification struct {
	Mode Mode
	// RelayKey is the raw inbound relay-key token. Empty in
	// ModeProxyAnonymous. In ModeNormal pulled from X-WR-API-Key first,
	// then Authorization (Bearer). In ModeProxyAuthed pulled from
	// X-WR-API-Key only.
	RelayKey string
	// UpstreamAuth is the verbatim Authorization header value (including
	// the "Bearer " prefix when present) supplied by the caller for proxy
	// mode. The proxy forwarder re-attaches it on the outbound request.
	// Empty in ModeNormal.
	UpstreamAuth string
	// UpstreamHost is the X-WR-Upstream-Host slug naming a configured
	// Host row. Empty in ModeNormal. Required in proxy mode; the proxy
	// dispatcher rejects missing/unknown values.
	UpstreamHost string
	// ClientIP is the resolved client address — XFF-walked when the peer
	// matches RELAY_TRUSTED_PROXIES, RemoteAddr otherwise.
	ClientIP string
}

Classification carries the result of Classify. Stashed on ctx by the classifier middleware and read by downstream handlers / pipeline / proxy. The classifier is pure — it does not touch the catalog snapshot or any settings; gating decisions happen later.

func ClassificationFrom

func ClassificationFrom(ctx context.Context) Classification

ClassificationFrom returns the mode classification from ctx. The zero Classification (Mode == ModeUnknown) is returned if no classifier ran.

func Classify

func Classify(r *http.Request) (Classification, error)

Classify extracts the mode, credentials, and client IP from r. Pure; no ctx writes, no snapshot reads. Returns an error only for shape- invalid inputs (bad header value, missing upstream key in proxy mode); the caller maps errors to HTTP responses.

type Deps

type Deps struct {
	// Pinger reports backend health for /healthz. Storage satisfies
	// this; tests can pass a stub.
	Pinger Pinger

	// Catalog is the in-memory snapshot used for relay-key auth lookup
	// and the /v1/models listing.
	Catalog *appcatalog.Catalog

	// Resolver translates inbound model+policy refs into a pipeline-
	// ready Plan against the snapshot.
	Resolver *routing.Resolver

	// Pipeline orchestrates one normal-mode inference request.
	Pipeline *pipeline.Pipeline

	// Proxy orchestrates a proxy-mode (BYO upstream key) request.
	Proxy *proxy.Pipeline

	// Lifecycle is the observer registry. Dispatch uses it to fire a
	// failure post-flight event for requests rejected before a runner is
	// reached (routing / proxy gating / translate errors) — runner-stage
	// failures are fired by the runner. Same registry the runners hold.
	Lifecycle *lifecycle.Registry

	// Adapters keys the wire-protocol implementation by adapters.Name.
	// Handlers look up the binding's Adapter Name here at request time;
	// proxy mode looks up the extractor by inbound endpoint shape.
	Adapters map[adapters.Name]pipeline.Adapter

	// Specs is the generic adapter registry. Dispatch uses it to look up
	// inbound and upstream translators and to determine routing strategy
	// (byte-pass vs canonical cross-shape). Built once at boot and
	// populated from cmd/relay/main.go.
	Specs *adapter.Registry

	// RouteMounters are per-adapter route registration functions. Each
	// adapter (or the generic framework) exposes a MountRoutes function
	// that satisfies RouteMounter; cmd/relay/main.go wires them in.
	RouteMounters []RouteMounter

	// TrustEventTime makes Dispatch honor the X-WR-Event-Time header as
	// the usage Event timestamp (RELAY_DEV_TRUST_EVENT_TIME). Dev/replay
	// tooling only; off by default.
	TrustEventTime bool
}

Deps is the typed dependency bundle for the data plane.

type DispatchInput

type DispatchInput struct {
	// Inbound is the wire shape the caller spoke (the route's Name).
	Inbound adapters.Name

	// Body is the raw inbound request body, already consumed from r.Body.
	Body []byte

	// ModelName is the caller-supplied model identifier extracted by the
	// per-shape minimal parse. Routing resolution uses this.
	ModelName string

	// Stream is the caller-supplied stream flag from the minimal parse.
	// Determines whether the response leg streams chunks or buffers + emits.
	Stream bool
}

DispatchInput is what a per-shape route passes to Dispatch after its own minimal parse. The route knows the inbound shape Name (because it owns the URL); Dispatch handles everything from routing onward.

type Mode

type Mode int

Mode classifies the proxy mode of an inbound inference request.

const (
	ModeUnknown Mode = iota
	// ModeNormal — default; no X-WR-Proxy-Mode; relay key authenticates
	// against a Policy and the upstream key comes from the keypool.
	ModeNormal
	// ModeProxyAuthed — X-WR-Proxy-Mode: Proxy + relay key in X-WR-API-Key
	// + caller-supplied upstream key in Authorization. Logged against the
	// relay key; subject to the inference-api-proxy system rate limit.
	ModeProxyAuthed
	// ModeProxyAnonymous — X-WR-Proxy-Mode: Proxy + caller-supplied
	// upstream key in Authorization, no relay key. Subject to the
	// inference-api-proxy-anonymous per-IP rate limit. Gated by
	// Settings.ProxyMode.AllowUnauthenticated.
	ModeProxyAnonymous
)

type Pinger

type Pinger interface {
	Ping(ctx context.Context) error
}

Pinger reports backend health for /healthz. Storage satisfies this via its own Ping method; tests can supply a stub.

type RouteMounter

type RouteMounter = func(api huma.API, d Deps, mw huma.Middlewares)

RouteMounter is what an adapter package exposes to mount its own inbound HTTP surface. Each adapter (openai, anthropic, ...) provides a MountRoutes(api, deps, mw) function matching this signature.

func MountRegistry

func MountRegistry(reg *adapter.Registry) RouteMounter

MountRegistry returns a RouteMounter that registers one POST route per InboundPath across all specs in reg. Each route performs a minimal JSON parse (model + stream), then calls Dispatch with the spec's Name as the inbound shape.

This is the generic route mounter that replaces per-shape MountRoutes functions. The composition root calls it once with the populated registry.

Jump to

Keyboard shortcuts

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