CoreMesh

GPT-Live Decisions Integration: Act While the User Speaks

Set up the native Decisions integration in GPT-Live: the two trigger paths, a minimal walkthrough, delta debouncing code, costs, and the gotchas.

GPT-Live Decisions Integration: Act While the User Speaks

As of October 16, 2026, GPT-Live has a native Decisions integration. The OpenAI changelog entry from October 15 describes it in one line: your app can act while your user is speaking, or react to what Live says. There are two ways in. Either Live calls the Decisions API itself through native delegation, or your code triggers a decision as input or output transcript deltas arrive.

The practical effect is that a voice session no longer has to wait for the turn to end before anything happens. Decisions turns text and images into typed answers, so you can ask a narrow question like "is the caller trying to cancel?" mid-sentence and get back a value your code can switch on. Below is the minimal setup, the two trigger paths, a way to avoid firing a decision on every syllable, and what it costs.

What the gpt-live decisions integration actually is#

Two products meet here, and it helps to keep them apart.

  • GPT-Live is the full-duplex voice model. The model ID is gpt-live-1 and sessions run on v1/live/sessions. It became generally available in the API on September 10, 2026. Its job is to hold a natural voice conversation that keeps going while a backend model or agent handles reasoning and tools.
  • Decisions is a separate API on v1/decisions, released in beta on October 6, 2026 with gpt-6-luna. Its pitch is narrow: turn text and images into typed answers, and do it, per the changelog, 10x faster than the Responses API.

The October 15 entry connects them. Before that date, a Live session could delegate to a Responses model or to your own backend through client delegation, and both of those were built around turns. Now Live can call Decisions directly, and transcript deltas become a hook point you can act on before the turn finishes.

Think of it as a fast classifier sitting beside the conversation. Live keeps talking. Decisions answers small typed questions about what is being said. Your app does something with the answers.

Two ways to trigger a decision#

The changelog names two mechanisms. They put control in different places, and you can use both in one app.

Trigger path Who initiates When it fires Good for
Native delegation Live When Live decides it needs a typed answer Least code; letting the voice model gate its own behavior
Input transcript deltas Your app As the user's speech is transcribed, piece by piece Acting while the user is still speaking
Output transcript deltas Your app As Live's own speech is transcribed Reacting to what Live says: UI updates, logging, guardrails

Native delegation is the hands-off option. Live calls Decisions directly, so you don't write the trigger logic. The trade-off is visibility: you have less say over exactly when a decision is requested.

Transcript-driven triggers are more work but more predictable. Every decision request originates in your code, so you can log it, rate-limit it, and test the trigger policy without a live microphone. Input deltas are the ones that let you act while the user speaks. Output deltas let you react to what Live says, which is useful for things like showing a card in the UI the moment Live mentions a product, or flagging a response for review.

My advice: if the goal is "act while the user is speaking", start with input transcript deltas. You control the cadence and can see every trigger. Add native delegation later for cases where Live itself should decide to ask.

Minimal setup walkthrough#

The steps below are the shape of a working integration. The exact request fields for sessions and decisions live in the GPT-Live and Decisions guides on platform.openai.com, and I'd keep those open while wiring this up rather than copying field names from memory.

  1. Open a GPT-Live session. Create it on v1/live/sessions with gpt-live-1. Audio flows both ways over that session. Nothing about Decisions changes how the session itself is created.
  2. Write the question as a type first. Decisions returns typed answers, so the question has to be answerable as one. "intent: cancel, billing, or other" is a decision. "Summarize the call so far" is not; that's a Responses job.
  3. Pick a trigger path. Native delegation if you want Live to call Decisions on its own. Transcript deltas if you want your code to decide when. For the delta path, add a small gate so you request a decision on meaningful chunks, not on every fragment (example in the next section).
  4. Call Decisions on v1/decisions with gpt-6-luna and the transcript chunk as text. The October 6 entry says it accepts text and images, so a screenshot of the user's screen can ride along if that helps the decision.
  5. Dispatch the typed answer. Map each possible value to an action, and make the dispatcher idempotent, because deltas will produce the same answer more than once (second example below).
  6. Hook output transcript deltas too if any part of your UI should react to what Live says rather than what the user says.

That's the whole loop. The session keeps the conversation going; your gate and dispatcher run beside it.

Firing on transcript deltas without over-triggering#

Transcript deltas are small. If you send every delta to Decisions, you'll pay for a lot of calls that return the same answer, and you'll get answers on fragments like "I'd like to" that mean nothing yet.

A gate that accumulates deltas and only requests a decision at a clause boundary or after an idle gap fixes most of this. Here's a stand-alone version with simulated deltas and timestamps so you can tune the thresholds before touching a real session:

python
import re

class DeltaGate:
    '''Collect transcript deltas and say when to request a decision.'''

    def __init__(self, min_chars=24, idle_ms=600):
        self.full = ''
        self.pending = ''
        self.min_chars = min_chars
        self.idle_ms = idle_ms
        self.last_ts = None

    def feed(self, delta, ts_ms):
        idle = self.last_ts is not None and ts_ms - self.last_ts >= self.idle_ms
        self.last_ts = ts_ms
        self.full += delta
        self.pending += delta
        clause_end = re.search(r'[.?!,]\s*$', self.pending) is not None
        if (clause_end or idle) and len(self.pending.strip()) >= self.min_chars:
            chunk = self.pending.strip()
            self.pending = ''
            return chunk
        return None

deltas = [
    ('Hi, ', 0), ("I'd like to ", 180), ('cancel my ', 400),
    ('subscription, ', 650), ('the one on the ', 900),
    ('annual plan', 1150), (' please.', 1400),
]
gate = DeltaGate()
for delta, ts in deltas:
    chunk = gate.feed(delta, ts)
    if chunk:
        print(f'{ts:>5} ms  decision requested on: {chunk!r}')
print('full transcript:', gate.full)

The two knobs are the minimum chunk length and the idle gap. Shorter chunks mean earlier actions and more calls. A longer idle threshold means fewer false triggers on pauses, at the cost of reacting later. Start conservative and loosen once you've looked at real transcripts.

One detail that matters: the gate returns only the new chunk, not the whole transcript. For intent-style decisions that's usually what you want, since the question is "what did they just say", not "what has the call been about". If a decision needs context, pass the last couple of chunks along with the new one rather than the full transcript, to keep the input small and the answer fast.

Turning typed answers into actions safely#

A stream of decisions will repeat itself. The user says "cancel" three different ways and you get "cancel" three times. Your dispatcher needs to act once, ignore repeats, and refuse values it doesn't recognize. Here's that logic on its own:

javascript
const ACTIONS = {
  cancel: () => 'show retention offer in UI',
  billing: () => 'open invoice history panel',
  other: () => null,
};

function makeRouter() {
  const acted = new Set();
  let last = null;
  return function route(decision) {
    if (!(decision in ACTIONS)) return `ignored: unknown value ${JSON.stringify(decision)}`;
    if (decision === last) return `no-op: still ${decision}`;
    last = decision;
    if (acted.has(decision)) return `no-op: already acted on ${decision}`;
    const effect = ACTIONS[decision]();
    if (effect === null) return `no action defined for ${decision}`;
    acted.add(decision);
    return `ACT: ${effect}`;
  };
}

const route = makeRouter();
const stream = ['other', 'cancel', 'cancel', 'billing', 'cancel', 'refund'];
for (const d of stream) console.log(d.padEnd(8), '->', route(d));

The allow-list is doing real work here. Decisions returns typed answers, but your code is the last line of defense against a value you didn't plan for, and silently acting on "refund" because it looked plausible is how voice apps do something the user didn't ask for.

Keep the actions themselves cheap and reversible while the user is still talking. Showing a card, pre-filling a form, or fetching data in the background are good mid-sentence actions. Submitting an order is not. Wait for the turn to end, or for an explicit confirmation, before anything that's hard to undo.

Models, status, and what it costs#

The pieces and their state as of October 16, 2026, per the OpenAI changelog:

Piece ID or endpoint Status Date
Voice model gpt-live-1 on v1/live/sessions Generally available September 10, 2026
Decisions API v1/decisions with gpt-6-luna Beta October 6, 2026
Native Decisions integration in GPT-Live gpt-live-1, gpt-6-luna Shipped October 15, 2026

On pricing, the September 10 entry states that voice sessions cost $0.05 per minute, billed per second, and that backend model and tool usage is charged separately. So the Decisions calls are an additional line item on top of the session time, whichever trigger path you use.

For gpt-6-luna, the September 22 entry lists standard pricing per 1M tokens for prompts up to 272K input tokens as $0.10 input, $0.01 cached input, and $0.50 output. The October 6 Decisions entry doesn't restate a Decisions-specific rate, so confirm the current numbers on the OpenAI pricing page before estimating a per-call cost.

The gap between the input and cached-input rates is the reason to structure every decision prompt as a fixed instruction followed by the short variable chunk. The changelog doesn't say how caching applies to Decisions requests specifically, but if the usual prefix-reuse rules hold, that layout is what benefits. The mechanics are the same idea I covered for Claude prompt caching and reading cache usage, and the habit transfers.

The changelog doesn't list a general-availability date for the Decisions API or any usage limits specific to the Live integration. Treat it as beta and check the changelog before relying on it for anything customer-facing.

Common mistakes and gotchas#

  • Asking Decisions open-ended questions. It's built for typed answers. If you find yourself wanting a paragraph back, that's a Responses or client delegation call, not a decision.
  • Requesting a decision per delta. Deltas are fragments. Gate them on clause boundaries or idle gaps, or you'll pay for dozens of identical answers per sentence.
  • Acting on every answer, including repeats. Deduplicate on value and keep a record of what you've already done in this session. The router above is the minimum.
  • Doing irreversible things mid-sentence. The point of acting while the user speaks is to be ready, not to commit. The user may finish the sentence with "actually, never mind".
  • Forgetting output transcript deltas. The integration explicitly supports reacting to what Live says. If your UI should mirror Live's speech, that's the hook, and it's easy to overlook when you're focused on the user's side.
  • Confusing the two model IDs. gpt-live-1 is the voice session. gpt-6-luna is the Decisions model. They're billed separately.
  • Treating beta as stable. Decisions is in beta as of October 6, 2026. Keep a feature flag so the app degrades to turn-based behavior if a call fails.
  • Expecting a decision to change what Live says next. Acting in your UI is one thing. Steering the conversation is a different problem that depends on your delegation setup, and nothing in the October 15 entry says a decision result is fed back into Live's speech automatically.

Quick reference#

  • Session: gpt-live-1 on v1/live/sessions, generally available since September 10, 2026.
  • Decisions: gpt-6-luna on v1/decisions, beta since October 6, 2026; text and image inputs, typed answers.
  • Integration shipped October 15, 2026: native delegation (Live calls Decisions) or app-triggered on input and output transcript deltas.
  • Session cost: $0.05 per minute, billed per second. Backend model and tool usage billed separately.
  • Gate deltas before deciding: clause boundary or idle gap, plus a minimum chunk length.
  • Dispatch through an allow-list, dedupe repeats, act once per value.
  • Mid-sentence actions: cheap and reversible only. Commit after the turn ends.
  • Re-check the changelog and pricing page before shipping; both the beta status and the Decisions rate can move.

Quick answers

What does the GPT-Live Decisions integration do?

It lets a GPT-Live voice session use the Decisions API without waiting for the turn to end. Live can call Decisions directly through native delegation, or your app can request a decision as input or output transcript deltas arrive.

Which models does it use?

The voice session runs on gpt-live-1 via v1/live/sessions. The decisions themselves run on gpt-6-luna via v1/decisions, which is the model the Decisions API launched with in beta on October 6, 2026.

Does using Decisions from GPT-Live cost extra?

Yes. The changelog lists voice sessions at $0.05 per minute, billed per second, and says backend model and tool usage is charged separately. Decisions calls are billed on top of session time; check the OpenAI pricing page for the current per-token rate.

Is the Decisions API generally available?

No. As of October 16, 2026 it's in beta, released October 6, 2026. The changelog doesn't list a general-availability date yet.

Should I use native delegation or transcript deltas?

Start with input transcript deltas if you want to act while the user is speaking, because your code controls exactly when a decision is requested. Use native delegation when you'd rather let Live decide on its own when it needs a typed answer.

Did this solve it?

One tap. No account.

Saved you an hour? Send a tip.

USDC or ETH on Base, Ethereum, Arbitrum and more. Keeps the notes free and the examples running.

Base

Network

0xc783bc5c3fa14cEC3f09A22284bC91C5AF0d59e1
Open in wallet · 5 USDC

On a computer? Scan the code with your phone wallet, or copy the address.

Pick the network your wallet or exchange uses. USDC works on all six; ETH on Base, Ethereum, Arbitrum and Optimism. Don't send on Tron or Solana: this address doesn't exist there. Tips are optional and unlock nothing; every guide stays free.

Discussion

Start the discussion

Indra Wijaya

Builds and runs AI agents, bots and content pipelines, and writes down what works and what broke.

About · Email · RSS

Keep reading

New notes, no spam.

One post at a time, only when there's something worth reading. Follow in any feed reader.

Subscribe via RSS