GPT-Live Decisions: Native Delegation and Transcript Triggers

TL;DR
GPT-Live can now call the Decisions API itself, mid-sentence. How native delegation and transcript triggers work, the session config, and the events to handle.
Last updated: October 18, 2026
GPT-Live can now call OpenAI's Decisions API on its own, while your user is still talking. OpenAI added it on October 15, 2026 as a native integration with two modes. Native delegation lets Live hand a request straight to Decisions, which answers the typed questions you defined. Transcript triggers run Decisions on every input or output transcript delta, which is how you animate an avatar or flag intent mid-sentence. Before this, Live notified your app and your app had to call Decisions itself. Native delegation removes that round trip.
If GPT-Live is new to you, start with our breakdown of how GPT-Live works. If Decisions is new, our Decisions API comparison covers what it is, what it costs and how it compares. This post covers wiring the two together.
What shipped#
From the Connect voice to Decisions guide:
- Native delegation: set
session.delegationto{ type: "decisions", decisions: { model, questions } }. Your session instructions tell Live when to delegate, and the questions tell Decisions what to return. One decision request answers all the questions independently. Live sends the conversation transcript to Decisions automatically. - Transcript triggers: add entries to
session.triggerswithevent_typeset tosession.input_transcript.deltaorsession.output_transcript.delta. Live supplies the model and trigger ID, and triggers run independently of delegation. - Requirements: a working Live connection and the
api.decisions.writepermission. Use your usual Live connection headers; there is no Decisions-specific alpha header. - Mutability: the delegation type is fixed when the session is created. The questions can change mid-session with
session.update, and you wait forsession.updatedbefore adding a decision item for that step.
%% title: Native Decisions delegation in a GPT-Live session
sequenceDiagram
participant U as User
participant L as GPT-Live
participant D as Decisions
participant A as Your app
U->>L: "I feel a little cold."
L->>A: session.delegation.created (delegation.id)
L->>D: transcript + your questions
D-->>L: answers
L->>A: decision.event (answers by question name)
A->>A: run the action, read back real state
A->>L: decision.item.create (new state snapshot)
A->>L: session.commentary.append (delegation_id)
L->>U: "I turned up the temperature a bit."Step 1: Configure the session#
OpenAI's example is a car voice assistant: cabin temperature and a windshield defogger the app can control directly, plus a needs_response question that routes anything bigger, like navigation, to the Responses API. This TypeScript version uses the official example values (trimmed to two delegation questions) and adds one transcript trigger:
import type {
CommentaryAppendEvent,
DecisionEvent,
DelegationCreatedEvent,
MediaSessionConfig
} from "openai/resources/live/live";
// Native delegation: Live calls Decisions directly. The delegation type is
// fixed for the session; questions can change later via session.update.
const session: MediaSessionConfig = {
model: "gpt-live-1",
instructions:
"Delegate the driver's whole request, including cabin controls, navigation, and local search. Wait for the app to report what happened, then tell the driver in natural language.",
delegation: {
type: "decisions",
decisions: {
model: "gpt-6-luna",
questions: [
{
type: "choice",
name: "cabin_temperature",
instructions:
"Choose temperature_up if the driver feels cold or wants more heat, temperature_down if they feel hot or want to cool down, or none if the request is unrelated.",
choices: [{ value: "temperature_up" }, { value: "temperature_down" }, { value: "none" }]
},
{
type: "choice",
name: "needs_response",
instructions:
"Choose yes if any part of the request goes beyond these cabin controls, such as getting directions. Otherwise choose no.",
choices: [{ value: "yes" }, { value: "no" }]
}
]
}
},
// Transcript triggers run independently of delegation.
triggers: [
{
type: "decisions",
event_type: "session.input_transcript.delta",
decisions: {
questions: [
{
type: "choice",
name: "expression",
instructions: "Choose your expression as you listen to the person's latest words.",
choices: [{ value: "neutral" }, { value: "happy" }, { value: "sad" }, { value: "concerned" }]
}
]
}
}
]
};
For WebRTC, this object goes under session in your session request, next to your existing transport. Note that a trigger has no model field; per the guide, Live supplies it.
Step 2: Handle the events#
Save delegation.id from session.delegation.created. Then, on each decision.event with a matching delegation_id, check that event.type is decision.completed and read the answers by question name from event.decision.answers. An answer of none means do nothing for that action.
let delegationId: string | null = null;
function onDelegationCreated(e: DelegationCreatedEvent) {
delegationId = e.delegation.id;
}
// Returns the commentary event to send back to Live, or null when nothing ran.
function onDecision(e: DecisionEvent): CommentaryAppendEvent | null {
if (e.delegation_id === null || e.delegation_id !== delegationId) return null;
const choices = new Map<string, string | boolean>();
for (const answer of e.event.decision.answers) {
if (answer.type === "choice" && answer.name) choices.set(answer.name, answer.choice);
}
if (choices.get("cabin_temperature") === "temperature_up") {
// Raise the temperature in your app and read back the real setting here.
return {
type: "session.commentary.append",
delegation_id: e.delegation_id,
content: "I raised the cabin temperature and confirmed the new setting on the dashboard."
};
}
return null;
}
Both snippets type-check with tsc --strict against openai 7.37.0, which ships typed MediaSessionConfig, DecisionEvent, DelegationCreatedEvent and CommentaryAppendEvent definitions for Live. They were not run against a live session. A wrong event_type string fails to compile.
The guide's full loop has two more steps around that handler:
- Feed real state back to Decisions. After the action runs, read the actual state back and send a compact snapshot with
decision.item.create, for example "Cabin temperature is set to 22 °C in automatic mode. Windshield defogger is off." Append a snapshot only when state changes, and treat the newest one as current. Keeping earlier inputs in place preserves the prefix for prompt caching. - Tell Live what happened. Wait for
decision.item.created, then sendsession.commentary.appendwith the samedelegation_id. Whenneeds_responseisyes, call the Responses API from your server (withapi.responses.write), run its function calls, and send Live only the concise final answer plus the confirmed state.
Transcript triggers: reacting while the user talks#
Triggers are for timing that follows the conversation rather than a request. OpenAI's example is a digital person: hearing "I got the job!" on session.input_transcript.delta returns happy, medium and nod, and an output trigger on session.output_transcript.delta can make the smile broaden as Live answers "That's wonderful!".
A trigger result comes back as a decision.event with delegation_id: null, plus trigger_id, source_event_type and source_event_id naming the transcript delta that caused it. Two rules from the guide matter in practice:
- Results can arrive out of order, and Live can combine pending deltas. Match
source_event_id, apply the newest relevant result in each direction, and drive mouth movement from the audio, not from decisions. - Event filters must allow both sides. If you filter WebRTC events, allow
decision.eventand the transcript event for each trigger. Live only delivers a trigger result when its source transcript event is also allowed. For delegation, allowsession.delegation.createdanddecision.event.
Gotchas and limits#
Pick the delegation type up front. It is fixed for the session. If you might need custom delegation (your app calls Decisions) for some users and native for others, that is a per-session choice made at creation.
Answers are not only choices. In the SDK types, decision.answers entries can be predicate, choice, score or refusal. Branch on answer.type, and treat a refusal as "do nothing" rather than letting your choice map silently miss a key.
Report verified state, not intent. The guide's pattern is to read back the actual setting before telling Live or Decisions anything. If you report what you asked the car to do and it failed, Live will confidently say something that is not true.
One request, many questions. One native decision request answers every question independently. Design each question so none (or no) is a safe default, because most turns will not touch most controls.
Updating questions is a handshake. Send session.update, then wait for session.updated before you add a decision item for the next step. Firing both at once races.
The closest alternative#
Custom delegation, the previous route, is still there: Live notifies your app and your app calls Decisions or anything else. It costs a round trip, but your server sees every request first, which matters if you need to log, rate-limit or rewrite before a model decides. Native delegation is the better default when the decision is a fast classification over the conversation and your app only needs the answer.
What people are actually saying#
- A Reddit post in r/CodexAutomation restates the launch and calls out transcript triggers for reactions such as an avatar's expression.
- Most of the coverage so far is restated changelog text. There is no Hacker News thread of note yet, and we could not find a practitioner report of latency in production. Treat the "low-latency while your user is still speaking" claim as OpenAI's until you measure it in your own app.
What to do Monday#
- Add
api.decisions.writeto the key your Live server uses. - Move one simple intent (a toggle or an on/off setting) to native delegation with a
nonechoice, and keep everything else on your current path. - Write the
decision.item.createstate snapshot and thesession.commentary.appendreply before you add more questions. - If you render an avatar, add one input transcript trigger, and confirm your event filter allows both
decision.eventandsession.input_transcript.delta.
FAQ#
What is native Decisions delegation in GPT-Live?#
It lets a GPT-Live session call the Decisions API directly instead of notifying your app first. You set session.delegation to type decisions with a model and questions, Live sends the transcript automatically, and your app reads answers from a decision.event.
What is the difference between delegation and transcript triggers?#
Delegation runs when Live recognizes a request your app should handle. Transcript triggers in session.triggers run on input or output transcript deltas and follow the conversation itself. Triggers run independently of delegation.
Can I change the Decisions questions during a GPT-Live session?#
Yes. Send session.update and wait for session.updated before adding a decision item for that step. The delegation type stays fixed for the session.
Do I need a special header to use Decisions in GPT-Live?#
No. Use your usual Live connection headers. Your key needs the api.decisions.write permission.
Continue Reading#
- How OpenAI Built GPT-Live: Full-Duplex Voice, WARP, and the Death of the Turn Detector - the voice model doing the delegating
- OpenAI Decisions API vs Jev vs Clef: Price, Speed, Which to Pick - what Decisions costs and when it is the right model
- OpenAI Realtime Voice API: Getting Started Guide - the WebRTC and WebSocket connection plumbing
Sources#
Get the next deep dive like this in your inbox
One email a week on OpenAI and the rest of the AI dev stack. Free.
Read next on AI coding tools
How OpenAI Built GPT-Live: Full-Duplex Voice, WARP, and the Death of the Turn Detector
How OpenAI built GPT-Live: a full-duplex voice model with no turn detector, Go on the media path, stateful handoffs, and the new WARP WebRTC transport.
8 min readOpenAI Decisions API vs Jev vs Clef: Price, Speed, Which to Pick
OpenAI Decisions API costs $0.10 per million input tokens, 2.4x Jev. Pick Jev for cheap text decisions, Clef-flash for speed, Decisions API for images.
9 min readOpenAI Realtime Voice API: Getting Started Guide
The Realtime API uses WebSockets for two-way voice interaction with function calling and stateful conversations. Here is how to set it up and build on it.
8 min readNew here? Start with
Technical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.






