The Four Layers
Public Layer
This is what application code usually touches. Three operation facades provide a stable interface for provider interactions:Inference— for chat completions and text generationEmbeddings— for generating vector embeddingsDecision— for typedNoul,Choice, andScorejudgments
Runtime Layer
Runtimes assemble the moving parts needed for a provider call. They wire together configuration, a driver, the HTTP client, and event dispatch, and own the operation lifecycle and retry policy. The key classes are:InferenceRuntime— coordinates inference execution and createsPendingInferencehandlesEmbeddingsRuntime— coordinates embeddings execution and createsPendingEmbeddingshandlesDecisionRuntime— coordinates decision execution and createsPendingDecisionhandles
HttpClientBuilder. Runtimes also expose onEvent() and wiretap() methods for hooking into the event system.
Request and Response Layer
Requests and responses are normalized into package data objects that are provider-agnostic:InferenceRequest— messages, model, tools, tool choice, response format, options, cached context, retry policy, response cache policyInferenceResponse— one ordered assistantMessage, usage, finish reason, and raw HTTP response dataPartialInferenceDelta— ordered assistant-message chunks plus finish reason, usage, and provider replay dataEmbeddingsRequest— input texts, model, options, retry policyEmbeddingsResponse— vectors and usageDecisionRequest— text or structured state, typed questions, model, retry policy, and telemetry correlationDecisionResponse— typed answers, model, usage, provider request ID, and raw HTTP response data
with*() mutators for building modified
copies.
PendingInference is the laziness boundary — nothing is sent until you ask for a result. Behind it, InferenceExecutionSession drives one request to one response and divides that job with two per-execution collaborators, both in Inference/Core/:
InferenceLifecycleEmitter— every lifecycle event, the execution and attempt stopwatches, the attempt counter, and per-attempt telemetry correlationInferenceRetryLoop— the attempt and length-recovery budgets, backoff delay, and length-recovery request rewriting
response() repeatedly returns the identical instance because the session reads it back off the InferenceExecution it already holds — which works for every ResponseCachePolicy, not only Memory. ResponseCachePolicy still matters, but at the HTTP layer: it becomes the StreamCachePolicy that decides whether a stream is replayable.
See lifecycle.md for the event sequence each path emits.
Driver Layer
Drivers translate Polyglot requests into provider-native HTTP payloads and normalize the results back. Drivers implementCanProcessInferenceRequest,
CanHandleVectorization, or CanProcessDecisionRequest for their operation
family. Inference drivers are further composed from these responsibilities:
- Request adapters (
CanTranslateInferenceRequest) — convertInferenceRequestinto anHttpRequest - Response adapters (
CanTranslateInferenceResponse) — convert rawHttpResponsedata intoInferenceResponseor stream ofPartialInferenceDelta - Message formatters (
CanMapMessages) — map typedMessagesto provider-specific structures, composing aMessageMapperutility for iteration - Body formatters (
CanMapRequestBody) — assemble the full request body with mode-specific adjustments - Usage formatters (
CanMapUsage) — extract token usage from provider responses
BaseInferenceRequestDriver, which provides the standard HTTP execution flow and stream handling. Every bundled provider is declared as an InferenceDriverSpec — a row naming its adapters and formatters — and built by that shared driver. Providers that assemble their own URL or headers select bespoke request adapters in that row; the provider-specific behavior does not require a driver class.
Decision drivers use DecisionRequestAdapter and DecisionResponseAdapter to
translate between the stable Decision domain and provider wire formats.
TypeSafe, Jeff, and Laya use the System One shape, while classifier.dev uses its dimensions API.
See Configuration and runtime for the registry contract.
Shared Support
Inference, embeddings, and Decision are separate operation families, but a few primitives belong to none of them. They live underCognesy\Polyglot\Support\:
Support\Redaction\SensitiveDataRedactor— decides what is sensitive: which header names, query parameters and option keys are masked before a value can reach an event payload or an exception message.Support\Redaction\RedactsHttpPayloads— decides where the drivers apply it.BaseInferenceRequestDriverandBaseEmbedDriverboth use this trait, so a tightened rule takes effect on both sides at once. Redaction runs on error paths only; nothing here executes on a successful request.Support\Retry\RetryBackoff,RetryJitter,RetryPolicyInvariants— the delay computation, jitter strategies, and constructor invariants shared by inference, embeddings, and Decision retry policies.Support\Pricing\Cost— the value object every cost calculator returns, on both sides. Note that the calculators themselves are not shared:Inference\Pricing\FlatRateCostCalculatorprices five token categories andEmbeddings\Pricing\FlatRateCostCalculatorprices one, andInferencePricingandEmbeddingsPricingcarry different rate fields. They share a name, not a signature.
Inference\, which
forced other operation families to import from the inference subsystem. Cost
was already neutral, at a top-level Polyglot\Pricing\; it moved here so that
Support\ is the package’s single answer to “where do things no operation
family owns live?” rather than one of two competing conventions.
How the Layers Connect
Key Design Decisions
Immutability. The public facades and request/response objects are immutable. Calling methods such aswithMessages(), withInput(), or withModel() returns
a new instance rather than modifying the original.
Lazy execution. Calling create() returns a PendingInference,
PendingEmbeddings, or PendingDecision handle without triggering the HTTP
call. Execution begins when the application reads from the handle.
Driver registry. Inference and Decision use InferenceDriverRegistry and
DecisionDriverRegistry; embeddings use EmbeddingsDriverFactory. Each
operation family supports custom runtime wiring.
Provider-agnostic data. InferenceResponse::message() preserves one ordered
assistant turn regardless of provider. Text, reasoning, and tool calls are projections
of that message; provider-specific HTTP details remain available through
responseData(). EmbeddingsResponse provides the corresponding normalized vector
surface for embeddings. DecisionResponse provides typed answers and preserves
the provider request ID and normalized HTTP response for diagnostics.