Logprobs Migration
Audience: SDK consumers that previously needed to request token log
probabilities through provider_options because the SDK had no first-class
field.
What Changed in v0.9.3
Section titled “What Changed in v0.9.3”The Rust wrapper, Python SDK, Go SDK, and the C ABI now expose first-class unary chat logprobs:
- Request side:
ChatRequest.logprobs: Option<bool>andChatRequest.top_logprobs: Option<u8>(Rust); equivalents in Python and the C ABI envelope. Use the Rust builderswith_logprobs(true)/with_top_logprobs(n), the PythonChatRequest(..., logprobs=True, top_logprobs=5), or set the JSON fields directly when calling the C ABI. - Response side:
ChatResponse.logprobs: Option<LogprobsData>with typedTokenLogprob(selected token + bytes) andTopLogprob(each alternative + bytes). The wire path islogprobs.content[](matches OpenAI; pinned bypackages/nxuskit-engine/crates/nxuskit-core/tests/logprobs_abi_passthrough_test.rs). - Engine behavior:
parameter_adapter.rs::adapt_logprobsperforms warn-and-drop when a provider’sProviderCapabilities.supports_logprobsisfalse, emits a structuredInfowarning withparameter == "logprobs", and drops both first-class fields. It does not tunnel logprobs throughprovider_options.
Migration For Existing Callers
Section titled “Migration For Existing Callers”If you previously stuffed logprobs into provider_options to work around
the missing first-class field:
// OLD (pre-v0.9.3) — pattern still parses but never reaches the providerlet req = ChatRequest::new("gpt-5.4") .with_message(Message::user("...")) .with_provider_options(serde_json::json!({ "logprobs": true, "top_logprobs": 5, }));Switch to the first-class fields:
// NEW (v0.9.3+) — first-class, capability-gated, surfaces typed responselet req = ChatRequest::new("gpt-5.4") .with_message(Message::user("...")) .with_logprobs(true) .with_top_logprobs(5);Python:
from nxuskit import ChatRequest
req = ChatRequest( model="gpt-5.4", messages=[{"role": "user", "content": "..."}], logprobs=True, top_logprobs=5,)C ABI / direct JSON:
{ "model": "gpt-5.4", "messages": [{"role": "user", "content": "..."}], "logprobs": true, "top_logprobs": 5}Why The Switch Matters
Section titled “Why The Switch Matters”- Capability gating: the engine only forwards logprobs to providers
whose capability map enables it. The legacy
provider_optionspath bypasses this check and silently dies on unsupported providers. - Typed responses:
ChatResponse.logprobsreturns a typedLogprobsDatarather than raw provider JSON. Selected token and alternative tokens are addressable as fields, including UTF-8 bytes when present. - Cross-language parity: Rust, Python, Go, and the C ABI all use the
same wire shape (
logprobs.content[]withtoken,logprob,bytes,top_logprobs). Switching once works everywhere. - No silent drops: unsupported providers now emit a structured warning instead of swallowing the request, so callers can detect and fall back.
v0.9.4 update
Section titled “v0.9.4 update”- Streaming logprobs shipped in v0.9.4 (sprint S1 / branch 098).
StreamChunknow carrieslogprobs: Option<StreamLogprobsDelta>(Rust),Logprobs *StreamLogprobsDelta(Go),logprobs: Optional[StreamLogprobsDelta](Python) - additive, defaults toNone/nilfor non-supporting providers.ProviderCapabilities.supports_streaming_logprobsgates it (withsupports_streaming_logprobs => supports_logprobsenforced). OpenAI is the only provider withsupports_streaming_logprobs = trueper fixture evidence; all others arefalseper the evidence-first rule. See the v0.9.4 CHANGELOG entry for the cross-language parity harness. CapabilityManifestv2 - a public preview subset for provider/model capability discovery was introduced in v0.9.4 (sprint S2/S3 / branch 099); the full internal manifest is unchanged. The publication decision is recorded in the 099 artifacts.