Message across Polyglot,
Instructor, and Agents. This is an intentional breaking change. There is no
deprecated compatibility layer for the previous flattened response or streaming
delta shapes.
The release also removes Polyglot’s lazy aliases for classes moved under
Cognesy\Polyglot\Support in v2.7. Applications must use the canonical
Support\Redaction\SensitiveDataRedactor, Support\Retry\RetryBackoff,
Support\Retry\RetryJitter, Support\Retry\RetryPolicyInvariants, and
Support\Pricing\Cost FQCNs.
Exact-offering model catalog
Polyglot now provides an optional deterministic model catalog keyed by exact(driver, wire model). Ordinary inference does not discover or load it. Applications compose a
catalog explicitly when they need local capability enforcement, model metadata, or facts required
by a selected processor. Unknown custom offerings remain executable and carry explicit unknown
facts when inspected.
Offering facts are stored as individual versioned YAML files using the connection-preset loading
pattern. Runtime construction reads no model records; exact lookup loads only the selected
offering and reuses its immutable profile. Project records use
config/llm/models/<encoded-driver>/<encoded-model>.yaml; monolithic runtime models.json
discovery was removed. Strict record parsing rejects unknown keys and malformed facts.
This replaces and removes CanDescribeCapabilities, DriverCapabilities, and
SpecifiedInferenceDriver. Default providers now use BaseInferenceRequestDriver directly.
Reasoning capability facts also live in the exact offering record; provider drivers retain only
the constant wire format used to render an already-approved selection.
Request preflight is an in-process preparation step, not an LLM API request. It reads only facts
explicitly attached to the request, rejects features and combinations marked unsupported, and
preserves unknown facts for custom offerings. Missing model facts do not create a catalog veto.
Reasoning translation can instead receive the narrow required facts directly. Model-name regexes
are no longer a capability source.
Provider adapters now render the approved intent or throw a precise protocol error; they never
silently strip a response format or weaken tool choice. Known semantic fallback is disabled by
default and requires LLMConfig::$allowLossyFallback === true (allow_lossy_fallback in Laravel
and Symfony connection configuration). Every accepted fallback is recorded on the effective
request and emitted with InferenceRequested.
Catalog maintenance is explicit and offline: edit the reviewed source inputs, run
just models-build, and use just models-check plus just models-validate as deterministic QA.
There is no runtime refresh, staging, apply, mapping, or provenance subsystem.
LLMConfig and connection presets no longer own contextLength, maxOutputLength, or
pricing. Put limits, modalities, and capabilities in a model catalog record. Supply pricing
explicitly to the existing inference or embeddings cost calculator. LLMConfig::fromArray()
ignores fields outside its canonical constructor shape; Agents has no legacy migration layer.
Anthropic prompt caching
Inference::withCachedContext() and StructuredOutput::withCachedContext() now
accept an optional ttl: '5m' or ttl: '1h'. Omitting it keeps Anthropic’s
five-minute default. Explicit block TTLs are preserved, including when cached
contexts are serialized and restored.
Cached tool-use and tool-result messages now place the breakpoint on the actual
eligible content block, without inserting an empty text block. Signed thinking
history remains intact and is not used as a breakpoint target.
Automatic caching remains opt-in through
->withOptions(['cache_control' => ['type' => 'ephemeral']]); add 'ttl' => '1h'
inside that object for a one-hour automatic cache. This is distinct from the
explicit-prefix withCachedContext() API. The caching guide now explains both
modes, their shared limits, and model-specific minimum prefix lengths.
Ordered Assistant Messages
InferenceResponse now carries one assistant Message. Its ordered
ContentParts can contain text, reasoning, tool calls, and tool results without
splitting a turn into unrelated response fields. Text, reasoning, and tool-call
accessors are projections on Message:
Inference::get() and PendingInference::get() now return that Message, not
a string. Call ->content()->toString() explicitly when an application needs
only text.
Provider adapters and streaming use the same assistant-message assembler. Stable
block identities preserve interleaved content, reasoning, and parallel tool calls.
Anthropic thinking signatures, Gemini thought signatures, and OpenAI Responses
reasoning replay state remain attached to their blocks so a completed assistant
turn can be sent back on the next request.
Structured output streams now retain token usage reported in a provider’s terminal
usage-only event. After finalValue() or finalResponse(), $stream->usage() and
the final response expose the provider-reported input, output, cache, and reasoning
counts.
The openai-compatible, ollama, and together drivers now preserve reasoning
returned in reasoning_content, reasoning, thinking, or analysis fields for
both synchronous and streamed responses. For synchronous responses without one of
those fields, an inline <think>...</think> block is moved from visible content
into the message’s reasoning part.
Agents now archive the exact response message. They no longer reconstruct an
assistant message from text, infer tool calls from separate fields, or JSON-parse
text to guess whether a provider leaked tool arguments.
Migration
Tell runtime and composition
Tell now has one direct execution path:Tell creates a fresh concrete
TellRuntime through the final Core\Execution\TellRuntimeFactory. The shallow
runner and runtime-factory interface chain was removed. CLI, conversations, and
the one-run protocol use the same factory; request-scoped cancellation still
overrides the host cancellation source.
Direct tool dispatch now resolves TellRequest configuration through
CanResolveTellConfiguration. It no longer receives the complete runtime merely
to obtain effective configuration, and it still does not execute an agent turn.
StandaloneTellBuilder exposes only named, typed replacement points. Migrate
custom integrations as follows:
There are no aliases, deprecated interfaces, dual registrations, or generic
container-binding fallback in 2.10.
The four default driver tables now have one entry point on their registry. The old static wrapper
classes and reasoning capability accessors were removed without aliases:
ModelModalities::$inputFile was also removed because Polyglot has no maintained generic file
message-to-wire route. ModelCapabilities::$reasoning remains an optional typed model fact, and
the narrower reasoning facts can be attached directly to a request. Custom driver registrations
should start from InferenceDriverRegistry::default() when they want the shipped table, or
InferenceDriverRegistry::make() when they want an empty one.
Replace flattened response access with the canonical message:
Construct responses with an assistant message:
Message serialization is canonicalized at the same boundary. Message::toArray()
now writes parts as the only semantic payload; it no longer duplicates those
blocks into top-level content, tool_calls, or tool_result fields. Hydration
rejects flattened tool fields because their original position cannot be recovered.
content, tool_calls, and tool_result into an
ordered parts list before calling Message::fromArray(). There is no runtime
fallback because appending flattened fields would invent an order.
Streaming deltas no longer expose flattened contentDelta,
reasoningContentDelta, toolId, toolName, or toolArgs fields. Consume their
ordered AssistantMessageChunks instead:
InferenceResponse(message: ...) for
synchronous output and emit PartialInferenceDelta(messageChunks: ...) with a
stable provider block index for streaming output.
Bundled examples now use messageChunks->textDelta() for streamed text. Retry
recordings also preserve the assistant tool-call block that is sent back to the
model, and Anthropic prompt-based JSON extraction uses OutputMode::MdJson so
request preflight does not claim native JSON Object support.
Provider and retry corrections
Structured-output retries now preserve the rejected assistant tool call and append a matching tool-error result with the same call ID. This keeps retry history valid for providers that require every assistant tool call to have a corresponding tool message. DeepSeek V4 requests now downgrade a forced function choice toauto while the
provider’s default thinking mode is active, matching the live Chat API. A
specific function choice remains available when the request explicitly disables
thinking. Retriable HTTP transport failures without a response, including
timeouts, are now classified as transient provider errors so configured retry
policies can retry them.
The Hugging Face preset now uses the supported
openai/gpt-oss-120b:fireworks-ai route, and JSON Schema requests use the
router’s OpenAI-compatible response_format.json_schema envelope. The
OpenAI-compatible reasoning example can target a private endpoint through
environment variables and otherwise runs against DeepSeek’s OpenAI-compatible
endpoint. Its assertions verify both the visible answer and separately
projected reasoning content.
Cerebras, Fireworks, Moonshot, OpenRouter, SambaNova, and Together presets now
reference exact model IDs returned by each provider’s live model catalog. The
Fireworks, Moonshot, OpenRouter, and Together inference and structured-output
examples have fresh live recordings and are enabled in the Hub replay suite.
Agent CLI compatibility and replay isolation
Tell no longer exposes thetell planes command or the associated
CanDescribeOperationalPlane, OperationalPlane, PlaneOperation, and
PlaneMap metadata API. This removes duplicated architectural descriptions
from every command. Use each command’s own help for its supported inputs and
behavior; Tell’s composition and ownership boundaries remain documented in the
package README. There is no deprecated command alias or metadata compatibility
layer.
The AgentCtrl Codex bridge now targets the current codex exec interface. The
removed --full-auto flag and fullAuto() builder method are replaced by
--approve-for-me and approveForMe(). Explicit sandbox selection, automatic
approval, and dangerous bypass are mutually exclusive; selecting one mode on the
builder clears the others. Pi commands now include --print for explicit
non-interactive execution.
The Gemini CLI bridge is supported again after verification against the current
Gemini CLI. Its live integration tests now run when the binary and credentials
are available, and its basic and streaming examples assert response text,
session and usage metadata, streamed output, and tool-call delivery.
The runtime-switching example now verifies every AgentType factory mapping
offline. Live mode is explicit, runs one selected backend, and uses a 30-second
timeout instead of invoking every installed CLI serially.
The AgentCtrl package PHPStan command now invokes the analyse command
explicitly, and all bridge, event, response, and configuration payloads carry
the iterable value types required by its level 6 configuration.
Instructor Hub now extracts executable PHP fences from Markdown files with LF or
CRLF line endings. AgentCtrl examples that launch external CLI processes are
tagged no-replay, so the offline replay gate does not depend on locally
installed agents, their credentials, or their provider quotas.
Multi-request examples now use stable request labels and deterministic tool
outputs, and their recordings have been refreshed for the message and model
catalog changes. Examples that supply their own HTTP client are tagged
no-replay because they bypass the Hub recorder by design.
Serialized InferenceResponse data now requires a message entry. The old
top-level content, reasoningContent, and toolCalls entries are rejected;
stored payloads must be migrated before hydration.
The rejection also applies when old fields appear beside message; they are not
silently ignored. Remove the flattened fields after migrating their data into the
ordered message parts.