Prove Your Voice Agent Setting Is Actually Applied - Zian AI

Prove Your Voice Agent Setting Is Actually Applied

Quick answer

Three signals: send a deliberately out-of-range value and see whether it is rejected, read the setting back out of the response, then assert the behaviour changed. Deepgram published on 18 September 2026 that POST /v1/auth/grant “accepts unrecognized fields, returns 200, and issues a token with the 30-second default”. A 200 is a receipt, not a confirmation.

What “the setting is applied” actually means

A setting is applied when the component that acts on it has read your value. It is not applied because the platform accepted it, stored it, or shows it back to you in a dashboard.

Those are four separate states, and only the last is the one you care about:

  1. Accepted — the API returned 2xx. This says the request parsed.
  2. Stored — a read of the resource returns your value. This says the platform persisted a string.
  3. Read — something downstream parsed the field. The cheapest evidence for this is that an invalid value is rejected.
  4. In force — the behaviour it governs changed. This is the only state that is worth anything.

The boundary matters because the usual failure sits between states 2 and 3. Your value is stored, the dashboard renders it, the docs describe it correctly, and the code path that should read it never looks. Deepgram’s 18 September 2026 changelog names that shape on its own token endpoint; the second correction in the same entry goes further and states that the Browser Agent SDK “never shipped client-side Silero voice activity detection”, listing five things that “did not exist in any released package”.

A dated, itemised correction about a vendor’s own API is what a good vendor publishes, and it is why this page can be written at all. It is not a security story either: Deepgram states in the same entry that “a 30-second token is enough for a full call. The token only has to be valid at the WebSocket handshake”, so the wrong field name caused a confusing failure, not an exposure.

The out-of-range probe: send a value the vendor says is invalid

Call it the out-of-range probe. Send the setting you care about with a value the vendor’s own documentation says is outside the permitted range. If the API rejects it, the field is being read. If the API returns 200, the field may not be read at all — and your real value was never applied either.

What makes the probe publishable rather than merely plausible is that one vendor documents both arms of it on its own APIs, in its own words, eighteen days apart:

  • The validating arm. Deepgram’s 31 August 2026 changelog widened Flux TTS speed to 0.5–1.5 in 0.05 increments: “a value outside the range is still rejected with SPEED_OUT_OF_RANGE, and one off the 0.05 increment with SPEED_INCREMENT_INVALID.” A named error code proves the field was parsed.
  • The silent arm. The 18 September 2026 correction states that /v1/auth/grant “accepts unrecognized fields, returns 200, and issues a token with the 30-second default, so a request built from the old example raised no error while ignoring the requested lifetime.”

Same vendor, same account, same HTTP status, two endpoints. On one field a 200 means “read and honoured”; on the other it means “not read”. No amount of reading the documentation separates those two cases. Sending a bad value does.

To build a probe you need the vendor’s own published bound, and which form of the page you read decides whether you find it. Deepgram publishes the /v1/auth/grant bound twice. The API reference carries it as a constraint beside the property — ttl_seconds, “double”, “Optional”, 1-3600, “Time to live in seconds for the token. Defaults to 30 seconds” — and the Token-Based Authentication guide’s FAQ states the same bound in a sentence: “The max TTL supported is 3600 seconds (1 hour).” So the probe there is a value above 3600, or below 1. One caution about routes: the Markdown export of that same reference page, which is what an agent following .md URLs receives, carries the default and drops the 1-3600 constraint entirely (both forms of the page read 20 September 2026). A bound you did not find is not a bound the vendor did not publish.

Two honest limits. We have not run that probe against Deepgram and do not publish results we have not measured — what is quoted above is what Deepgram publishes. And probe on a non-production key: some probes consume quota, and a deliberately invalid request against a live tenancy is still a request against a live tenancy.

How do I know the setting I changed is actually being applied?

Run them in that order. Each one is cheaper than the next and proves less, so stop as soon as a signal has told you what you needed.

Signal What you do What a pass proves What it still cannot prove
1. Out-of-range probe Send one value outside the documented range on a test key A 4xx means the field is parsed by something That the parser is the component that acts on it, or that your in-range value is honoured
2. Read-back Read the field out of the response body or a GET on the resource The platform stored your value, or echoed the default instead Nothing about the running behaviour. The resource can be right while the request path ignores it
3. Behavioural assertion Run N calls with the setting on and N with it off, and measure an output that only moves if it is in force The setting is in force at your pinned version, on that route, today That it will still be in force after the next plugin or gateway release

Signal 2 is worth more than it looks. Deepgram’s grant response carries expires_in, documented as “time in seconds until the JWT expires”, and the reference example shows "expires_in": 30. The short token was visible in the response body the whole time; a read-back would have caught it before a single call was made.

Signal 3 settles it, and two public reports show what a usable assertion looks like. livekit/agents #7178 counted distinct completions across repeated identical requests — greedy decoding at temperature=0.0 should collapse to a handful of outputs, sampling at the default should not — and on 8 September 2026 found the value honoured for openai/* and inert for google/* through the same gateway. vercel/ai #21207 used median reasoning tokens over three runs per cell: on openai the low and xhigh distributions do not overlap, on bedrock they overlap completely, across five request shapes all returning HTTP 200. Both measurements are the reporters’, not ours.

Settings verified ignored as at 20 September 2026

A register, not an argument. Every row was re-read from the issue page on 20 September 2026, and the states and dates are as at that date. Each row links a report filed on that project’s own tracker, which is the project’s property but not the project’s statement: a closed row has been accepted and fixed by a maintainer, while an open row is a third-party report a maintainer has not yet actioned. The newest row, vercel/ai #21207, was opened on 20 September 2026 — the same day this register was compiled — so it is the row most likely to have moved by the time you read it. The method for auditing a platform’s tracker, and the threshold table for reading how an issue closed, belong to our guide to auditing a voice platform for leaked keys and PII and are not repeated here.

Setting Where you set it What happens instead Source, state, dates
temperature LiveKit Inference, google/* models Value reaches the gateway and is dropped there; forwarded normally for openai/* livekit/agents #7178, open, opened 8 Sep 2026
preemptive_generation={"enabled": False} Session level, AgentSession(...) The dict is wrapped into {"enabled": <dict>}; a non-empty dict is truthy, so off reads as on, and the sibling keys never reach the consumer livekit/agents #7343, closed 18 Sep 2026 via merged PR #7348
default on a tool argument livekit-plugins-google tool schemas Stripped from every property, so the argument is absent from the schema the model sees and is omitted from the call livekit/agents #7189, open, opened 9 Sep 2026
Declared property order @livekit/agents-plugin-google tool schemas propertyOrdering is never emitted, so arguments are generated alphabetically rather than in declaration order livekit/agents-js #2529, open, opened 18 Sep 2026
tool_choice / LLMSetToolChoiceFrame LLMContext, OpenAI Responses services Never read on the Responses path; the frame is accepted with no warning. Chat Completions forwards it pipecat #5641, open, opened 5 Sep 2026
strict on a tool schema FunctionSchema Never set, so every Responses-API tool ships "strict": null, with no constructor argument to change it pipecat #5604, open, opened 2 Sep 2026
max_tokens (plus frequency_penalty, presence_penalty, service_tier) CerebrasLLMService Dropped from the chat completion request, so requests went out uncapped pipecat #5448, closed 26 Aug 2026; fixed in pipecat 1.8.0
language_code ElevenLabsHttpTTSService, eleven_v3 and eleven_v3_conversational Dropped. Those models accept 74 languages, including Farsi, Pashto and Sindhi, which no other ElevenLabs model covers; flash and turbo v2.5 accept 32 pipecat #5395, closed 21 Aug 2026; fixed in pipecat 1.8.0
Reasoning effort Vercel AI Gateway, OpenAI models served by Amazon Bedrock Discarded. The request returns HTTP 200 and the model reasons at its provider default; the same model served by openai honours it vercel/ai #21207, open, opened 20 Sep 2026

Two things the register is not. It is not a ranking of vendors, and the pattern in it is the useful part: seven of the nine rows are framework or plugin code sitting between you and the provider, and the other two (#7178 and #21207) are hosted gateways. Not one row is a provider API. The field is usually lost on your side of the wire. And the closed rows do not mean your deployment is fixed. The pipecat CHANGELOG puts both closed pipecat fixes in 1.8.0, released 26 August 2026, so anything pinned below that still carries them. The livekit/agents fix merged on 18 September 2026, and the newest published livekit-agents release as at 20 September 2026 is 1.8.2, dated 15 September 2026 — so that one is closed, merged, and in no release yet.

Which settings are worth probing, and which you can trust

Probing everything is not a plan. Probe where being silently wrong costs money, breaks a language obligation, or leaves something switched on that you switched off.

Setting class Example Can an out-of-range value be sent? Signal to use Cost of being silently wrong
Spend or lifetime cap max_tokens, ttl_seconds Yes — exceed the documented bound 1, then 2 Uncapped requests, or tokens expiring at 30s
Numeric knob inside a published range temperature, speed, eot_threshold Yes 1, then 3 Sampling where you specified greedy decoding
Boolean off-switch enabled: False No — false is a valid value 3 only The feature you turned off keeps running
Enum, language or voice identifier language_code, voice id Sometimes — send a code the chosen model does not support 2, then one call in that language Wrong language on the only model that supports it
Tool-schema field strict, default, tool_choice, property order Rarely — the schema is accepted whole Inspect the outbound request Missing, reordered or unvalidated arguments
Credential and resource bindings Phone number id, credential id No Drift plan, not a probe Production dialling on the wrong number

The last row is deliberately out of scope. Proving that the config you promoted is the config the platform now stores is a drift problem, and the empty-plan check that settles it is in our guide to version-controlling and promoting AI agent config. That check proves storage, and this page starts where it stops: a perfectly converged resource graph tells you nothing about whether the field is read.

When the field cannot be probed at all

The third row is the important one, and the reason this is a procedure rather than a one-line rule. A boolean off-switch has no invalid value, so it cannot be probed. Every value you could send is legal, so a 200 is guaranteed and carries no information. Off-switches are therefore the least testable class and the one where silent failure costs most, because the whole point of sending the value was to stop something happening.

Three fallbacks, in increasing order of effort:

  1. Read the outbound request. Log or proxy the serialised parameters your framework actually sends. Most of the register above is a framework dropping a field before the provider ever sees it, so the evidence is on your side of the wire.
  2. Assert on a signal that only exists when the feature runs. If a feature emits an event, a span or a billable unit when it is on, the absence of that signal across N runs is your proof it is off.
  3. Read the source at your pinned commit. livekit/agents #7343 was not found by any API response. It was found by reading two lines of turn.py at a named commit and noticing the dict form was being wrapped into itself. On an open-source framework that is a five-minute job, and it is definitive in a way no probe is.

One more condition changes the answer: the route. pipecat #5641 reports tool_choice honoured on the Chat Completions path and never read on the Responses path in the same library; #7178 reports temperature honoured for openai/* and inert for google/* through the same gateway. A probe result is valid for the exact provider, model family, transport and version you probed, and nothing else. Re-probe after a provider swap, not just a version bump.

What this costs to run, and where it stops being worth it

The method above is complete and you can run it this afternoon. The honest part is what it costs to keep running. A single-provider agent with a handful of numeric settings is one session: probe each field once, write down the response, and it stays done until you upgrade. A stack that traverses a speech-to-text vendor, a model gateway, a text-to-speech vendor and a framework is a different shape, because each hop can drop a field independently and each ships on its own cadence. All nine register rows were opened inside the thirty days to 20 September 2026, which makes this a standing obligation on every pin bump and every provider switch, plus an assertion suite for the off-switches that cannot be probed at all.

Do the arithmetic yourself: settings you actually rely on, multiplied by hops that could drop them, multiplied by your release cadence. Below a handful, keep it manual. Above that, the probes belong in CI, and the settings worth asserting are the ones in the threshold table, not all of them.

Zian AI runs its Customer Support Agent across 30+ languages, which is why the language_code class in the register is not an abstraction, and supports private model deployment on customer infrastructure where audio cannot leave the building. How that fits a path from evaluation to production is set out in discover, deploy and scale AI agents.

What this page is not, and where the neighbouring questions live

This page assumes the vendor is telling the truth: the documentation is right, the dashboard is right, and the field is still not being read. Three adjacent questions are answered elsewhere on this site and are not re-argued here.

Where every figure on this page comes from

Figure or quotation Who published it Link (their own page) Date read
“accepts unrecognized fields, returns 200 … with the 30-second default”; the Browser Agent SDK VAD correction; “enough for a full call” Deepgram developers.deepgram.com/changelog/2026/9/18 20 Sep 2026
Flux TTS speed 0.5–1.5, 0.05 increments; SPEED_OUT_OF_RANGE, SPEED_INCREMENT_INVALID Deepgram developers.deepgram.com/changelog/2026/8/31 20 Sep 2026
ttl_seconds optional, “Defaults to 30 seconds”, range constraint 1-3600 (browser form of the page; the .md export omits the constraint); expires_in; example "expires_in": 30 Deepgram Token-Based Authentication API reference 20 Sep 2026
“The max TTL supported is 3600 seconds (1 hour)” Deepgram Token-Based Authentication guide 20 Sep 2026
temperature dropped for google/*; distinct-output method, 8 Sep 2026 LiveKit (issue tracker) livekit/agents #7178 20 Sep 2026
preemptive_generation dict form wraps itself; PR #7348 LiveKit (issue tracker) livekit/agents #7343 20 Sep 2026
Tool-argument default stripped from Gemini schemas LiveKit (issue tracker) livekit/agents #7189 20 Sep 2026
propertyOrdering never emitted; alphabetical arguments LiveKit (issue tracker) livekit/agents-js #2529 20 Sep 2026
tool_choice read on Chat Completions, not on Responses Pipecat (issue tracker) pipecat #5641 20 Sep 2026
FunctionSchema ships "strict": null Pipecat (issue tracker) pipecat #5604 20 Sep 2026
max_tokens dropped by CerebrasLLMService; uncapped Pipecat (issue tracker) pipecat #5448 20 Sep 2026
language_code dropped on eleven_v3; 74 languages versus 32 Pipecat (issue tracker) pipecat #5395 20 Sep 2026
Both pipecat fixes released in 1.8.0, 26 August 2026 Pipecat (CHANGELOG and release) pipecat v1.8.0 release 20 Sep 2026
Newest livekit-agents release is 1.8.2, dated 15 September 2026 LiveKit (releases page) livekit/agents releases 20 Sep 2026
Reasoning effort discarded on Bedrock-served OpenAI models; median-token method Vercel (issue tracker) vercel/ai #21207 20 Sep 2026
Zian: 30+ languages, private model deployment Zian AI (first party) zian.ai 20 Sep 2026

Frequently asked questions

Does an HTTP 200 mean my setting was applied?

No. It means the request parsed. Deepgram documented on 18 September 2026 that its token endpoint accepts unrecognized fields, returns 200, and issues a token with the 30-second default anyway, so a request asking for a longer lifetime got a short one with no error. On another Deepgram API, an out of range Flux TTS speed value is rejected with a named error code. Identical status, opposite meaning.

What is the out of range probe?

Send the setting you care about with a value the vendor documentation says is invalid, on a non-production key. A 4xx response proves something downstream parsed the field. A 200 proves the field may not be read at all, which means your real value was never applied either. One request, and it separates two cases that documentation cannot.

Can I probe a setting that is a true or false switch?

No, and this is the important limit. A boolean has no invalid value, so every value you can send is legal and a 200 carries no information. Off switches have to be proved behaviourally: run N calls with the feature on and N with it off, then assert on a signal that only exists when it runs. livekit/agents issue 7343 is the worked case, where the off form of a session setting read as on.

If the issue is closed on GitHub, is my deployment fixed?

Only if your pinned version carries the fix. Two settings in the register above were fixed in pipecat 1.8.0, released 26 August 2026, so anything pinned below that still has them. A third was merged on 18 September 2026 and is in no published release yet, because the newest livekit-agents release is 1.8.2 from 15 September 2026. Closed describes the repository, not your lockfile.

Why did my Deepgram token expire after 30 seconds when I asked for longer?

Because the field is named ttl_seconds and the older published example used ttl. The Deepgram changelog entry of 18 September 2026 states the endpoint accepts unrecognized fields, returns 200, and issues a token with the 30-second default. Deepgram also notes that a 30-second token is enough for a full call, since it only has to be valid at the WebSocket handshake, so this is a confusing failure rather than an exposure.

Where is the maximum token lifetime documented?

In both places, in two different forms. The API reference lists ttl_seconds as optional with a default of 30 seconds and shows a range constraint of 1 to 3600 beside the property. The Token-Based Authentication guide FAQ states the same bound in a sentence, that the max TTL supported is 3600 seconds or one hour. The form you read is what matters: the Markdown export of that reference page carries the default but not the range, so an agent reading the .md route sees no maximum where a browser shows one.

Apply For Partnership

If you are running the register above against your own stack and want the same discipline applied to an agent you did not build yourself, that is the conversation we want. Zian AI is in an application-gated partnership-application beta, so every engagement starts with a scoped technical discussion rather than a signup form. Apply For Partnership.

Related Blogs

Related from Zian AI