Skip to main content
Polyglot normalizes all provider interactions into a small set of data objects. These objects are immutable — every mutation returns a new instance, making them safe to pass around and branch from.

InferenceRequest

InferenceRequest encapsulates everything needed for an LLM call. It stores the conversation messages, model selection, tools, response format, options, and caching/retry configuration. Namespace: Cognesy\Polyglot\Inference\Data\InferenceRequest

Key Properties

A note on updatedAt

updatedAt is not a “last mutation” timestamp. A copy made by with() inherits the source object’s updatedAt instance rather than reading the clock, so for an object built in the normal way updatedAt === createdAt no matter how many withers have run. The same holds for InferenceResponse, InferenceAttempt and InferenceExecution. Withers run several times per attempt, and nothing on any execution path reads updatedAt — InferenceRequest::toArray() does not even emit it — so recomputing it was a clock read and an allocation for nobody. The one thing the field still does is survive a fromArray() → with() → toArray() round trip: a value you deserialise is preserved, not overwritten with the load time. If you need “when was this copy made”, record it yourself.

Reading Values

Predicate methods are also available: hasMessages(), hasModel(), hasTools(), hasToolChoice(), hasResponseFormat(), hasNonTextResponseFormat(), hasTextResponseFormat(), hasOptions().

Modifying a Request

All mutators return a new instance, preserving the original request ID and creation timestamp:
The with(...) method allows setting multiple fields in a single call:

Cached Context

The cached context mechanism allows you to separate stable parts of a prompt (system messages, tool definitions, response format) from the dynamic parts (user messages). When withCacheApplied() is called, the cached context is merged into the request:
After applying, the merged request has an empty cached context to prevent double-application.

Serialization

Requests can be serialized to and from arrays for storage or transport:

PendingInference

PendingInference is a lazy handle for a single inference operation. It does not execute the request until you access the results. This enables the fluent Inference API to defer execution to the moment of consumption. Namespace: Cognesy\Polyglot\Inference\PendingInference

Consuming Results

The underlying InferenceExecutionSession handles retry logic, event dispatching, and response caching. Once execution completes, the response is cached for the lifetime of the PendingInference instance.
Important: Calling stream() on a non-streaming request will throw an InvalidArgumentException. Enable streaming via withStreaming(true) on the facade before calling create().

InferenceResponse

InferenceResponse is a final readonly envelope around the provider’s complete assistant Message and inference metadata. The message preserves the provider’s block order; text, reasoning, and tool calls are projections rather than parallel response fields. Namespace: Cognesy\Polyglot\Inference\Data\InferenceResponse

Reading the Response

Message predicates such as isEmpty() and hasToolCalls() live on Message; hasFinishReason() remains on the response envelope.

JSON Extraction

The response provides convenience methods for extracting structured data:
When a response has a single tool call, findToolCallJsonData() returns the arguments of that call. When there are multiple tool calls, it returns an array of all tool call data.

Reasoning Normalization

Some providers embed reasoning in <think> tags within a text field rather than in a dedicated block. Response adapters normalize that representation before constructing the assistant message:
Dedicated reasoning blocks remain ordered and retain provider replay metadata.

Finish Reason

The finishReason() method returns an InferenceFinishReason enum. The hasFinishedWithFailure() method checks whether the response ended with an error, content filter, or length limit:

Serialization

Responses support round-trip serialization:

PartialInferenceDelta

During streaming, the driver emits PartialInferenceDelta objects for each SSE event. Each delta carries ordered assistant-message block changes from that event. Namespace: Cognesy\Polyglot\Inference\Data\PartialInferenceDelta

Fields

The InferenceStream applies the chunks to a shared assistant-message assembler and constructs the same Message shape produced by synchronous adapters. Stable block indices preserve interleaving and allow replay metadata to round-trip.

InferenceUsage

The InferenceUsage object tracks token consumption across several categories: Namespace: Cognesy\Polyglot\Inference\Data\InferenceUsage

Cost Calculation

Inference cost is calculated externally using a calculator rather than through methods on the usage object. The caller supplies current pricing in USD per 1 million tokens; inference model catalog records do not contain pricing:

Accumulation

Usage and cost can be accumulated across multiple requests:

Embeddings Data Objects

EmbeddingsRequest

Holds the input texts, model, options, and retry policy for an embeddings call:

EmbeddingsResponse

Normalizes the provider’s embeddings result:
Missing provider usage remains null, distinct from a reported zero. Embedding cost calculation therefore returns null when a nonzero rate requires a token count that the provider did not report.

PendingEmbeddings

A lazy handle similar to PendingInference. Calling get() triggers the HTTP request and returns an EmbeddingsResponse. The response is cached after the first call. Retry logic is handled internally based on the EmbeddingsRetryPolicy attached to the request, using the same exponential backoff pattern as inference retries.

Decision Data Objects

DecisionRequest carries text or structured input, a non-empty Questions collection, an optional model override, retry policy, request ID, and telemetry correlation. Its toArray() representation deliberately includes only input, questions, and the optional model. PendingDecision is the lazy execution boundary. The first get() returns typed Answers; response() returns DecisionResponse. Both successful and failed terminal results are memoized on that pending handle. DecisionResponse contains typed answers, model, nullable token usage, the provider request ID, and normalized HttpResponse. There is no partial delta or streaming counterpart. See Question design for request primitives and Response handling for typed accessors and probability distributions.