Después de conectarte a GPT-Live, usa los eventos de sesión para agregar contexto, mostrar transcripciones y gestionar la conexión. GPT-Live puede escuchar y hablar al mismo tiempo. Lleva un registro por separado del texto transcrito, del audio reproducido y del progreso de las tareas del backend para que tu interfaz pueda mostrar lo que dice el asistente y qué tareas siguen en curso.
Esta guía presupone que tu conexión ya emitió session.started. Consulta Conexiones para configurar la conexión y transmitir audio, y Delegación y herramientas para gestionar el trabajo del backend.
Configurar una sesión
Elige el modelo, la voz y el modo de delegación al crear la sesión. Dale al modelo instrucciones para la conversación e incluye el historial pertinente. GPT-Live gestiona el contexto automáticamente a medida que avanza la conversación.
Campos de configuración
| Ajuste | Configuración al inicio | Cambios durante la sesión |
|---|---|---|
| Modelo | Define el campo obligatorio model. |
Inicia una sesión nueva para cambiarlo. |
| Instrucciones | Usa instructions para definir el comportamiento durante la conversación, con un máximo de 16 384 tokens. |
Agrega instrucciones con session.instructions.append. |
| Historial | Incluye en input los mensajes de texto anteriores que sean pertinentes. El valor predeterminado es []. |
Usa los eventos que permiten agregar contexto. |
| Voz | Asigna a audio.output.voice una voz compatible o una voz personalizada autorizada. El valor predeterminado es marin. |
Inicia una sesión nueva para cambiarla. |
| Delegación | Establece delegation.type en client o responses. Si omites la delegación o le asignas null, se selecciona el modo cliente. |
Actualiza los ajustes de Responses dentro del modo actual. |
| Almacenamiento | Establece store en true para poder crear un fork de la sesión. El valor predeterminado es false. |
Elige el valor al inicio. |
Opciones de voz
Elige una voz al crear la sesión. Asigna a audio.output.voice el nombre que usa la API, por ejemplo, "quartz". GPT-Live incluye estas opciones de voz adicionales:
| Voz | Nombre en la API | Idioma | Influencia regional | Presentación | Origen |
|---|---|---|---|---|---|
| Quartz | quartz |
Inglés | Australiana | Femenina | Generada |
| Ripple | ripple |
Inglés | Australiana | Masculina | Natural |
| Vesper | vesper |
Inglés | Británica | Masculina | Natural |
| Willow | willow |
Inglés | Irlandesa | Femenina | Natural |
| Stone | stone |
Inglés | Irlandesa | Masculina | Natural |
| Gleam | gleam |
Inglés | Norteamericana | Femenina | Natural |
| Meridian | meridian |
Inglés | Norteamericana | Masculina | Natural |
| Bossa | bossa |
Portugués | Brasileña | Femenina | Natural |
| Tempo | tempo |
Portugués | Brasileña | Masculina | Natural |
| Beacon | beacon |
Inglés | Filipina | Masculina | Generada |
| Delta | delta |
Inglés | Del sur de EE. UU. | Femenina | Generada |
| Cinder | cinder |
Inglés | Del sur de EE. UU. | Masculina | Generada |
| Nuri | nuri |
Alemán | — | Femenina | Natural |
| Juni | juni |
Alemán | — | Femenina | Natural |
| Flitz | flitz |
Alemán | — | Masculina | Natural |
| Brise | brise |
Francés | — | Femenina | Natural |
| Sillage | sillage |
Francés | — | Masculina | Natural |
| Nira | nira |
Hindi | — | Femenina | Natural |
| Harema | harema |
Japonés | — | Femenina | Natural |
| Shida | shida |
Japonés | — | Masculina | Natural |
| Noeul | noeul |
Coreano | — | Femenina | Natural |
La influencia regional describe el estilo de habla de una voz. Prueba la voz con los idiomas y la pronunciación que necesita tu aplicación. Para crear una voz a partir de una descripción escrita o de una grabación aprobada, consulta Voces personalizadas.
Para WebSocket, elige audio.format al inicio. El mismo formato se aplica al audio de entrada y de salida de la sesión. Para usar otro formato, inicia una sesión nueva. WebRTC negocia el formato de audio al establecer la conexión, así que omite audio.format en las solicitudes de WebRTC. Consulta Formatos de audio de WebSocket para conocer los formatos compatibles y los detalles de la transmisión.
Actualizar una sesión en curso
Usa session.update para modificar session.delegation.responses en una sesión que ya use la delegación de Responses. Envía solo los ajustes que quieras cambiar. Los que omitas conservarán sus valores. Consulta Configurar la delegación de Responses para conocer los ajustes y el procedimiento de actualización.
Elige el modo de delegación y define los campos model, instructions, input, audio y store al inicio. Usa session.update solo para los ajustes de Responses compatibles que se describen arriba. Los demás campos de configuración se rechazan. Para cambiar de modo de delegación, crea una sesión nueva. Al inicio, delegation: null selecciona la delegación en el cliente y no restablece los ajustes predeterminados de Responses.
Cuando la actualización se completa correctamente, se emite session.updated con la configuración resultante de la sesión. Asocia ese evento con el event_id que enviaste mediante client_event_id. Gestiona los comandos rechazados en el mismo bucle de eventos. Usa los eventos correspondientes para seguir por separado el trabajo del backend y lo que dice el asistente.
Proporcionar historial y contexto
Usa el historial al inicio para retomar un tema y agrega contexto pertinente a medida que avanza la conversación. Mantén las instrucciones de confianza de la aplicación separadas de los mensajes del usuario y de los resultados que aportan datos.
Iniciar una sesión con una conversación anterior
Incluye los mensajes de texto anteriores en session.input al crear la sesión. Por ejemplo, agrega este campo input a la configuración de creación de la sesión:
export const session = {
model: "gpt-live-1",
input: [
{
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "I need help with my recent order.",
},
],
},
{
type: "message",
role: "assistant",
content: [
{
type: "output_text",
text: "What is the order number?",
},
],
},
],
};La lista admite hasta 128 mensajes con un máximo de 8192 tokens en total. Cada mensaje tiene una sola parte de texto y uno de estos roles: developer, user o assistant. Los mensajes del desarrollador y del usuario usan input_text. Los del asistente usan text u output_text. Coloca las instrucciones de confianza de la aplicación en instructions o en un mensaje del desarrollador.
Selecciona los mensajes de texto del historial que necesites para la siguiente interacción y envíalos al inicio. Durante la sesión, agrega actualizaciones mediante los eventos de contexto que se describen a continuación. Envía los elementos específicos del backend, como los resultados de herramientas, mediante el flujo de delegación.
Entender cuándo llega el contexto al modelo
Incluye en input todo el contexto que el modelo necesite desde el principio. El contenido completo del campo está disponible al iniciarse la sesión.
Durante la sesión, session.instructions.append, session.thinking.append y session.commentary.append permiten agregar contexto de forma progresiva. La confirmación llega cuando la línea de tiempo de la sesión alcanza el final estimado del contexto agregado. Los campos start_ms y end_ms de la confirmación indican la ubicación aproximada de esa actualización en la línea de tiempo de la sesión.
Estos tiempos corresponden exclusivamente a la entrega del contexto. Los tiempos de habla y de reproducción se registran por separado. El modelo puede responder antes de haber usado toda la actualización. Si una acción depende de una instrucción o de un dato nuevo, verifica el comportamiento resultante en tu aplicación.
Si la línea de tiempo de la sesión deja de avanzar, la confirmación puede quedar pendiente. Asocia cada confirmación con el event_id que enviaste mediante client_event_id y sigue gestionando los errores mientras esperas. Al cerrar la sesión, se devuelven errores para las solicitudes de agregar contexto que aún estén pendientes.
Agregar contexto durante la conversación
Elige el evento según el uso que deba darle el modelo a la actualización:
session.instructions.append: agrega instrucciones de confianza de la aplicación que influyen en el comportamiento del modelo y en lo que dice.session.thinking.append: agrega datos de contexto sin pedirle al modelo que los comunique de inmediato.session.commentary.append: proporciona información para que el modelo la diga en voz alta. El modelo puede parafrasearla.
Cada evento recibe content como una cadena de texto simple de hasta 500 tokens y requiere un delegation_id. Usa null para el contexto que se aplica a toda la sesión. Por ejemplo, envía lo siguiente después de que tu aplicación haya verificado que el usuario aceptó y haya iniciado la consulta:
export function sendUpdate(connection) {
connection.send({
type: "session.thinking.append",
event_id: "context_1",
delegation_id: null,
content:
"The user has already accepted the terms. The account lookup is still running.",
});
}Para hacer un seguimiento de esta actualización, procesa session.thinking.appended con client_event_id: "context_1" o el error correspondiente. Consulta Entender cuándo llega el contexto al modelo para saber cuándo llega la confirmación.
El asistente puede repetir información que reciba mediante cualquiera de estos eventos. Envía solo información apropiada para la conversación y conserva las credenciales y los secretos en tu backend. Usa session.instructions.append para el comportamiento que define tu aplicación. Proporciona como contexto los datos que devuelven las herramientas. En el código de la aplicación, haz cumplir los permisos y exige las confirmaciones necesarias.
Para la navegación entre páginas, las selecciones y otros cambios en la interfaz, consulta Compartir el contexto de la interfaz. Allí encontrarás cómo enviar actualizaciones concisas que ayuden a GPT-Live a entender a qué se refiere el usuario.
Para enviar una actualización sobre una tarea específica del backend, usa el ID de la delegación en el cliente correspondiente. El ID de delegación identifica la tarea de Live. Los ID de respuesta de Responses y los ID de llamada a herramientas identifican otros objetos. Consulta Enviar el tipo de actualización adecuado para conocer el procedimiento.
Cuando tu aplicación detecte un problema, envía una corrección breve mediante el WebSocket principal de la sesión o un WebSocket auxiliar. Consulta Aplicar medidas de protección a la conversación para conocer las verificaciones, los controles de acciones y el manejo de la reproducción.
Gestionar la voz y las transcripciones
Fragmentos de transcripción
Escucha los eventos session.input_transcript.delta para la voz del usuario y session.output_transcript.delta para la del asistente. Cada evento contiene un fragmento de texto y el intervalo que ocupa en la línea de tiempo de la sesión:
{
"type": "session.input_transcript.delta",
"event_id": "event_transcript_1",
"delta": "What is",
"start_ms": 1000,
"end_ms": 1200
}
Concatena los fragmentos delta de cada hablante tal como los recibes, conservando los espacios y las palabras repetidas. Conserva también sus valores de start_ms y end_ms. Estos valores se expresan en milisegundos desde el inicio de la sesión. El ejemplo anterior abarca desde los 1000 ms hasta los 1200 ms, sin incluir este último instante. Los valores indican el intervalo aproximado del fragmento, sin delimitar cada palabra con exactitud. Úsalos para organizar la transcripción en lugar de usar los tiempos de llegada de los paquetes.
Los eventos de transcripción corresponden a intervalos que contienen texto y pueden llegar a un ritmo irregular. Un fragmento puede contener solo parte de una oración. Una pausa en la entrega puede deberse a un retraso de la red. Los fragmentos de transcripción no tienen un ID de elemento ni hay un evento que marque el final de un turno de conversación, así que tu aplicación decide cómo agruparlos para mostrarlos.
Procesar los fragmentos de transcripción es opcional. Puedes usarlos para actualizar la interfaz, ejecutar verificaciones o iniciar tareas antes de que termine la conversación. Para verificaciones sencillas, considera usar un modelo pequeño como gpt-5.6-luna con un esfuerzo de razonamiento bajo. Consulta Reaccionar a fragmentos de transcripción para ver ejemplos e indicaciones sobre la conexión.
Usa medidas de protección basadas en la transcripción para supervisar la conversación y activar intervenciones mientras los participantes siguen hablando. Si tu aplicación necesita verificar lo que dice el asistente antes de reproducirlo, consulta Verificar la voz antes de reproducirla para gestionar el almacenamiento en búfer, la aprobación, las interrupciones y la recuperación.
Distingue los tiempos de la transcripción de los tiempos de reproducción del audio. En WebSocket, los eventos session.output_audio.delta no tienen campos de tiempo ni hay un evento que indique que terminó el audio de salida. WebRTC entrega el audio mediante su pista de medios. Consulta Conexiones para gestionar el audio.
Mostrar subtítulos
GPT-Live funciona en modo dúplex completo: la persona que llama y el asistente pueden hablar al mismo tiempo. Actualiza los subtítulos de cada participante de forma independiente para que ambos textos puedan seguir ampliándose cuando hablen a la vez.
Si tu aplicación usa burbujas de chat, los fragmentos “Me gustaría” y “ cambiar mi reserva” pueden aparecer en una misma burbuja de la persona que llama. Si el asistente dice “Claro” mientras la persona sigue hablando, muestra esa respuesta por separado y permite que la burbuja de la persona siga ampliándose. Conserva los fragmentos originales y sus marcas de tiempo para que el texto que llegue más tarde actualice la burbuja correspondiente.
Usa session.output_transcript.delta para los subtítulos de voz y muestra las actualizaciones del backend por separado. Deja las decisiones sobre ejecutar herramientas o cancelar trabajo en la lógica de tareas de tu aplicación, separadas de la lógica que agrupa el texto para mostrarlo.
Controlar la entrada del micrófono
Envía session.input_audio.mute para silenciar la entrada sin finalizar la sesión:
export function sendUpdate(connection) {
connection.send({
type: "session.input_audio.mute",
event_id: "mute_1",
});
}Espera a recibir session.input_audio.muted con client_event_id: "mute_1" antes de dar el comando por aceptado. Para reactivar la entrada, envía session.input_audio.unmute y espera a recibir session.input_audio.unmuted. Gestiona los errores de ambos comandos.
Al silenciar la entrada, la sesión sigue activa. El modelo puede seguir generando voz y las tareas delegadas pueden continuar. Si también necesitas detener la grabación o la reproducción local, usa los controles de captura del micrófono y del reproductor de audio de tu aplicación.
Saludar antes de que hable la persona que llama
Si quieres que GPT-Live inicie la conversación, obtendrás mejores resultados si, al crear la sesión, incluyes instrucciones de saludo en un mensaje developer dentro de session.input. En WebSocket, incluye el mensaje en el evento session.start. Así, las instrucciones de saludo estarán disponibles desde el inicio.
Especifica el idioma, qué debe decir el asistente y que debe empezar de inmediato y luego hacer una pausa para escuchar. Usa el idioma de saludo elegido por la aplicación hasta que hable la persona que llama. Por ejemplo, usa este texto para el mensaje del desarrollador:
Saluda ahora en inglés a la persona que llama. Preséntate como el asistente de soporte y pregúntale cómo puedes ayudarla. Luego haz una pausa y escucha.
- Agrega el mensaje a
session.inputconrole: "developer"y una sola parte de contenido de tipoinput_text. Consulta Iniciar una sesión con una conversación anterior para conocer el formato del mensaje. - Espera a recibir
session.startedy luego envía las mismas instrucciones de saludo una sola vez mediantesession.commentary.append, con unevent_idúnico ydelegation_id: null, como se muestra a continuación. Mantén activo el audio de entrada, incluido el silencio antes de que la persona empiece a hablar. En WebSocket, sigue enviandosession.input_audio.append. En WebRTC, mantén activa la pista de audio de entrada. - Comprueba el audio de salida y la transcripción para verificar que el asistente saludó a la persona que llama. Las instrucciones iniciales pueden mejorar el saludo, pero no garantizan que el modelo hable.
{
"type": "session.commentary.append",
"event_id": "greeting_1",
"delegation_id": null,
"content": "Greet the caller now in English. Introduce yourself as the support assistant and ask how you can help. Then pause and listen."
}
El evento session.commentary.appended confirma la recepción de la solicitud, pero no que el saludo se haya dicho o reproducido. GPT-Live puede parafrasear el saludo, agregar palabras o quedarse en silencio.
Si necesitas que el saludo se reproduzca de forma predecible, que se usen palabras exactas o saber en qué momento termina la reproducción, reproduce una grabación verificada o un clip de audio generado desde tu aplicación y controla la reproducción de GPT-Live mientras suena. Prueba los saludos en los idiomas que admite tu aplicación, incluso cuando la persona empieza a hablar durante el saludo. Consulta Prompts para modelos de voz para diseñar tus prompts.
Comunicar un aviso
Usa session.instructions.append para pedir que el asistente comunique un aviso en voz alta con una redacción específica. Con session.commentary.append, el modelo puede parafrasear el texto. Por ejemplo, después de recibir session.started, envía lo siguiente:
export function sendUpdate(connection) {
connection.send({
type: "session.instructions.append",
event_id: "disclosure_1",
delegation_id: null,
content:
"Immediately say the following disclosure exactly and in full before responding to the caller: This call may be recorded for quality and training purposes.",
});
}Mantén activo el audio de entrada, como se indica en Saludar antes de que hable la persona que llama. Una instrucción enviada durante la conversación puede interrumpir una intervención en curso.
Verifica el aviso generado y su reproducción antes de marcarlo como entregado. La confirmación de la instrucción indica que se aceptó. Comprueba en el audio qué palabras se usaron. Si necesitas una redacción exacta y saber en qué momento termina la reproducción, reproduce una grabación verificada o un clip de audio generado desde tu aplicación y controla la salida de GPT-Live mientras suena. Consulta Controlar la reproducción cuando sea necesario.
Gestionar conversaciones largas
GPT-Live gestiona automáticamente las conversaciones largas y conserva las instrucciones originales que proporcionaste al inicio.
La ventana de contexto predeterminada admite 128 000 tokens, que incluyen tus instrucciones, el texto de la conversación y los tokens de audio que no aparecen en la transcripción.
GPT-Live resume en segundo plano las partes más antiguas del historial. Cuando el uso de la ventana de contexto supera el 90 %, inicia un motor de voz de reemplazo dentro de la misma sesión. El nuevo motor recibe tus instrucciones originales y hasta 8192 tokens del historial de la conversación, que incluyen mensajes recientes y, si está disponible, un resumen de los mensajes más antiguos. Preparar un resumen no cambia de inmediato el contexto del motor en ejecución.
Algunos detalles de las partes más antiguas de la conversación pueden resumirse u omitirse. Conserva en tu aplicación los datos importantes, las acciones confirmadas y el estado actual de las tareas. Proporciona el contexto pertinente cuando sea necesario.
Almacenar una sesión y crear un fork
Un fork inicia una sesión nueva a partir de una conversación de voz guardada. Úsalo para ejecutar varias pruebas de evaluación a partir de la misma conversación de referencia o para que un usuario pueda continuar una conversación después de que haya terminado la sesión anterior. Cada fork obtiene una conexión y un ID de sesión nuevos, y toma como punto de partida la conversación de origen y su configuración guardada.
Ejecutar evaluaciones a partir de una conversación de referencia
Supongamos que quieres probar cómo responde tu agente cuando la persona que llama quiere modificar un pedido. Graba una sola vez la conversación inicial hasta el momento en que la persona identifica el pedido. Cierra la sesión y espera a que finalice antes de que la persona pida modificarlo. Cada evaluación puede entonces crear un fork de la misma sesión de referencia y recibir como siguiente intervención el mismo audio de la persona que llama: “Actually, can you send it to my office instead?”.
En cada prueba, restablece el mismo pedido de prueba y el mismo estado de la aplicación, proporciona la siguiente intervención de la persona que llama y evalúa la nueva respuesta y las acciones de las herramientas. Puedes repetir el escenario o comparar los ajustes compatibles del backend de Responses. Mide por separado el tiempo de inicio del fork y el tiempo de respuesta. Consulta la guía de evaluación de GPT-Live para elegir escenarios y medir los resultados.
Los forks heredan el modelo de GPT-Live, la voz y las instrucciones originales. Para comparar otro modelo de voz u otro prompt inicial, crea sesiones nuevas con esa configuración. La API de fork usa la grabación finalizada de la sesión de origen, así que termina la sesión de referencia en el punto donde quieras que empiece la evaluación.
Continuar después de que termine una sesión
Por ejemplo, una persona puede colgar y volver a llamar más tarde, o volver a conectarse después de que se corte la llamada. Si la sesión anterior tiene una grabación almacenada y finalizada, tu aplicación puede crear un fork mediante una conexión nueva y continuar desde la conversación guardada.
Guarda el estado de las tareas de la aplicación junto con el ID de la sesión de origen. Antes de continuar, verifica el estado de las tareas pendientes del backend y proporciona a la nueva sesión los resultados actuales. Por ejemplo, si ya enviaste una actualización de un pedido, confirma su resultado antes de intentar actualizarlo otra vez. Usa el nuevo ID de sesión para los controles y las conexiones auxiliares, y dirige los resultados posteriores del backend a la nueva sesión.
Preparar una sesión para crear un fork
- Activa el almacenamiento al crear la sesión de origen. Establece
store: trueen la configuración de la sesión. El valor predeterminado del almacenamiento esfalse. Tu proyecto debe tener habilitado el almacenamiento y su política de datos debe permitir la persistencia. - Guarda el ID de la sesión de origen. Obtenlo de
session.startedo de la respuesta de creación de WebRTC y asócialo con el registro de la conversación en tu aplicación. - Termina y cierra la sesión de origen. Completa el trabajo necesario del backend y sigue las indicaciones de Uso y cierre ordenado. Mantén abierta la conexión hasta recibir
session.closedy gestiona los errores de finalización. Para crear un fork se necesita una grabación almacenada y finalizada. Guardarla puede prolongar la finalización. - Inicia un fork mediante una conexión nueva. Usa el ID de origen con el procedimiento de transporte que se describe a continuación, guarda el nuevo ID de sesión y completa el inicio antes de continuar la conversación. Define explícitamente
storeen la sesión derivada: usatruesi quieres crear otro fork más adelante a partir de la continuación, ofalsesi no necesitas almacenar esa prueba. Si omites el campo, se hereda el ajuste de la sesión de origen.
Las grabaciones almacenadas están disponibles durante 30 días. Con la retención cero de datos (ZDR), store se trata como false y no se pueden crear forks. Para realizar evaluaciones con forks, usa una organización sin ZDR y con el almacenamiento habilitado para el proyecto.
Si no tienes una grabación almacenada y finalizada, inicia una sesión nueva con los mensajes pertinentes del historial de texto guardado. Consulta Controles de datos de GPT-Live para conocer los requisitos de almacenamiento.
Por ejemplo, define este campo en la configuración de session.start para WebSocket o en la solicitud de creación para WebRTC de la sesión de origen:
{
"store": true
}
Inicia el fork con el transporte que usa tu aplicación:
| Transporte | Cómo iniciar el fork |
|---|---|
| WebSocket | Conéctate a wss://api.openai.com/v1/live/sessions/{source_session_id}/fork. |
| WebRTC | Envía una oferta SDP nueva a POST /v1/live/sessions/{source_session_id}/fork. Aplica la respuesta devuelta en transport.sdp a la nueva conexión entre pares. |
Un fork hereda el modelo, las instrucciones originales y la entrada de la sesión de origen. Al inicio, envía solo los ajustes que se pueden modificar:
- WebSocket:
store, los ajustes de delegación de Responses y el campoaudio.formatde la nueva conexión. Envía un eventosession.startcon un objetosession. Usa{}para conservar los ajustes que se puedan heredar. - WebRTC:
store, los ajustes de delegación de Responses y los permisos del cliente en el frontend.
Para un fork con WebSocket, define audio.format para la nueva conexión o usa el formato predeterminado PCM16 a 24 kHz. No se heredan el formato de audio de origen ni los permisos del canal de datos del frontend. WebRTC negocia el formato de audio al establecer la conexión, así que omite audio.format. WebRTC conserva los ajustes de permisos del frontend a menos que los modifiques.
En WebSocket, espera a recibir session.started antes de enviar más comandos. En WebRTC, la solicitud HTTP inicia la sesión. Continúa mediante la conexión negociada sin enviar otro session.start.
Iniciar un fork con WebSocket
Define OPENAI_API_KEY. Los ejemplos usan el ID que tu aplicación guardó para la sesión de origen almacenada. Confirman el inicio y luego cierran el fork. Para continuar la conversación, envía y recibe audio después de session.started mediante el procedimiento de conexión con WebSocket. Consulta la referencia de forks con WebSocket para conocer los campos y eventos de inicio.
import OpenAI from "openai";
import { ForksWS } from "openai/resources/live/forks/ws";
async function forkSession(sourceSessionId) {
const ws = new ForksWS(new OpenAI(), { session_id: sourceSessionId });
let finalized = false;
let closeRequested = false;
try {
for await (const event of ws) {
if (event.type === "open") {
ws.send({ type: "session.start", session: {} });
} else if (event.type === "error") {
throw event.error;
} else if (event.type === "message") {
if (event.message.type === "session.started") {
console.log("Fork ready:", event.message.session.id);
// This startup example closes the fork after confirming it is ready.
ws.send({ type: "session.close" });
closeRequested = true;
} else if (event.message.type === "session.closed") {
console.log("Final usage:", event.message.usage);
if (!closeRequested) {
throw new Error("Fork ended before startup completed");
}
finalized = true;
break;
}
}
}
if (!finalized) throw new Error("Connection closed before session.closed");
} finally {
ws.close();
}
}Iniciar un fork con WebRTC
Crea una oferta SDP nueva en el frontend y envíala al backend. Los siguientes ejemplos de backend usan esa oferta y el ID que tu aplicación guardó para la sesión de origen almacenada:
import OpenAI from "openai";
async function forkSession(sourceSessionId, offerSdp) {
const client = new OpenAI();
const fork = await client.live.sessions.fork(sourceSessionId, {
transport: { type: "webrtc", sdp: offerSdp },
});
console.log(JSON.stringify(fork));
}Devuelve la respuesta al frontend, aplica transport.sdp como respuesta a la oferta de la nueva conexión entre pares y conserva el nuevo session.id. Mantén la clave de API en el backend.
Usa el nuevo ID de sesión para las conexiones auxiliares y los controles de sesión. Antes de reintentar una acción pendiente, comprueba su resultado en el backend y restablece el estado actual de las tareas de la aplicación. Si no tienes una grabación almacenada y finalizada, inicia una sesión nueva con el historial guardado.
Descargar una grabación
Una vez finalizada la grabación almacenada, descarga el audio con GET /v1/live/sessions/{session_id}/content. La respuesta contiene datos binarios en formato WAV estéreo, con el audio de entrada en el canal izquierdo y el de salida en el derecho. Los ejemplos usan el ID que tu aplicación guardó para la sesión almacenada y escriben la respuesta en recording.wav a medida que la reciben:
import OpenAI from "openai";
import { createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
async function downloadRecording(sessionId) {
const client = new OpenAI();
const response = await client.live.sessions.downloadRecording(sessionId);
if (!response.body) throw new Error("Recording response has no body");
await pipeline(response.body, createWriteStream("recording.wav"));
}Cerrar sesiones inactivas y retomar la conversación
Si en tu aplicación pasa mucho tiempo entre interacciones, cierra la sesión de voz durante los períodos de inactividad e inicia una sesión nueva cuando regrese el usuario. Conserva el contexto de la conversación y el estado de las tareas de la aplicación para que el usuario pueda continuar sin repetir lo que ya dijo. Por ejemplo, un asistente en un automóvil puede retomar la conversación cuando el conductor vuelva a activar la voz, y un asistente de programación puede mantener en ejecución su proceso de trabajo en el backend entre conversaciones de voz.
- Decide cuándo cerrar la sesión. Define en tu aplicación un tiempo de espera por inactividad que tenga en cuenta la actividad de audio, la reproducción de la voz del asistente y las interacciones con la aplicación. Deja margen para pausas previsibles, por ejemplo, cuando el usuario esté leyendo o pensando. Cierra la sesión solo cuando haya terminado la reproducción y ninguna tarea pendiente necesite la sesión de voz actual. Una pausa entre eventos de transcripción no basta para determinar que hay silencio.
- Guarda el estado y cierra la sesión de forma ordenada. Guarda el ID de la sesión de origen, el contexto de la conversación y el estado actual de las tareas. Completa las tareas necesarias de Responses y sigue las indicaciones de Uso y cierre ordenado: registra el detector de
session.closed, envíasession.closey espera a recibirsession.closedantes de liberar la conexión. Con la delegación en el cliente, las tareas del backend que gestiona tu aplicación pueden continuar de forma independiente mientras la sesión de voz está cerrada. - Detecta cuándo volver a iniciar la conversación. Ofrece un botón con la etiqueta Reanudar conversación, un control que el usuario pueda mantener presionado para hablar o un mecanismo de activación gestionado por la aplicación. Una sesión de Live cerrada no puede escuchar al usuario. Si usas detección local de voz para reiniciar la conversación automáticamente, mantén activa la captura del micrófono y guarda en un búfer el audio inicial mientras se establece la conexión. Entrega ese audio cuando la nueva sesión esté lista para conservar las primeras palabras del usuario.
- Restablece el contexto en una sesión nueva. Si creaste la sesión de origen con
store: true, el almacenamiento está habilitado y permitido, y la grabación finalizó correctamente, crea un fork de la sesión almacenada. De lo contrario, inicia una sesión nueva con el historial de texto guardado. Guarda el nuevo ID de sesión, verifica el estado de las operaciones pendientes del backend y dirige los resultados posteriores a la nueva sesión. Conserva el estado de las operaciones en tu aplicación para que al reiniciar no se repitan acciones ya completadas.
Si silencias el micrófono, la sesión sigue activa. Para elegir el tiempo de espera por inactividad, compara la duración de voz que ahorrarías con el costo de crear una sesión y el tiempo que tardaría la voz en volver a estar disponible. Consulta Costos de las sesiones de voz y Cargos de inicialización de WebRTC.
Gestionar errores y finalizar la sesión
Sigue leyendo los eventos de la sesión hasta que finalice. Distingue entre un comando rechazado, una conexión fallida y una sesión finalizada para que tu aplicación pueda recuperarse de forma adecuada.
Gestionar comandos rechazados
Lee los eventos error junto con las confirmaciones. Si está presente, error.client_event_id identifica el comando que enviaste y que falló:
{
"type": "error",
"event_id": "event_error",
"error": {
"type": "invalid_request_error",
"code": "immutable_field_update",
"message": "The delegation type cannot change after session startup.",
"param": "session.delegation.type",
"client_event_id": "event_update"
}
}
Implementa un controlador de errores general para los errores cuyo código sea null o que no incluyan un ID de evento del cliente. Si el error se debe a que el campo es inmutable, conserva la configuración actual o crea una sesión nueva con los ajustes deseados.
Gestionar la moderación
La moderación puede afectar la sesión de dos maneras:
- Algunos eventos de moderación finalizan la sesión.
- Otros interrumpen el audio del asistente durante el resto de su intervención actual y emiten un evento
errorsin finalizar la sesión.
Sigue gestionando los eventos error mientras se reproduce el audio. Lleva un registro por separado de las interrupciones de audio y del cierre de la sesión. Marca un mensaje de voz como entregado solo después de comprobar su reproducción. Aplica tus propias medidas de protección para la conversación junto con la moderación integrada.
Uso y cierre ordenado
session.usage.updated indica la duración acumulada de voz en segundos:
{
"type": "session.usage.updated",
"event_id": "event_usage_1",
"usage": { "seconds": 12 },
"context_window": { "usage_ratio": 0.42 }
}
Usa el valor más reciente de usage.seconds como total acumulado de la duración de voz. Por ejemplo, si una actualización indica 12 segundos y la siguiente indica 15, el uso total es de 15 segundos. Registra por separado el uso de tokens del backend a partir de los eventos anidados de finalización de Responses. Consulta Optimización de costos para conocer cómo se contabiliza el uso.
Para cerrar la sesión de forma ordenada:
- Completa las tareas delegadas a Responses que necesite tu aplicación, incluidos los resultados pendientes de funciones y las continuaciones de respuestas.
- Registra el detector de
session.closedantes de enviarsession.close. - Envía
session.closey deja de enviar tareas nuevas a la sesión. Mantén activos la conexión WebSocket o WebRTC, el canal de datos y cualquier receptor auxiliar conectado mientras se procesan los eventos de sesión pendientes. - Lee el valor final de
usage.seconds, el camporeasony la instantánea de la sesión ensession.closed. Conserva los datos de uso de las tareas delegadas que ya recibiste medianteresponse.event. - Libera los transportes y los dispositivos de audio después de recibir ese evento. Si la finalización falla o supera el tiempo de espera definido en tu aplicación, informa que la finalización quedó incompleta y libera los recursos.
Al enviar session.close, se cancelan las solicitudes de Responses que estén en la cola y se rechazan los comandos posteriores. Una respuesta activa puede terminar, pero una que esté esperando el resultado de una función no podrá continuar una vez iniciado el cierre. Decide por separado si quieres completar o cancelar las tareas que tu aplicación ejecuta mediante la delegación en el cliente.
Usa session.closed para confirmar la finalización y leer la instantánea de la configuración final. Mantén abierto el transporte hasta recibir este evento. Si el socket se cierra antes, registra la finalización como no confirmada. Si se cierra después de recibir un session.closed válido, conserva el resultado confirmado.
El campo reason del evento final indica por qué terminó la sesión:
| Motivo | Significado |
|---|---|
close_requested |
Tu aplicación envió session.close o llamó al punto de acceso para colgar. |
expired |
La sesión alcanzó su límite de duración. |
content |
Un filtro de seguridad finalizó la sesión. |
remote_hangup |
La conexión principal remota se cerró de forma ordenada. |
connection_lost |
La conexión principal o la conexión con el servicio de origen se perdió de forma inesperada. |
El evento session.closed confirma la finalización incluso si el motivo fue una pérdida de conexión o un cierre por seguridad. Sin ese evento, el uso final queda sin confirmar. Una sesión almacenada puede tardar más en finalizar mientras se guarda la grabación. Elige un tiempo de espera para tu aplicación que tenga en cuenta el tiempo de almacenamiento.
Recuperarse de una falla de conexión
Un error HTTP al crear una sesión significa que la sesión no llegó a emitir session.started. Gestiona los errores de inicio por separado de los que se produzcan en una sesión en curso. Si una conexión activa falla antes de recibir session.closed, conserva los datos de uso más recientes que hayas recibido y marca el uso final como no confirmado.
Si hay una grabación almacenada y finalizada, crea un fork para continuar en una sesión nueva. De lo contrario, crea una sesión de reemplazo con los mensajes pertinentes del historial guardado. Antes de continuar, consulta en el backend el estado de las acciones pendientes, restablece el estado actual de las tareas y actualiza el enrutamiento de los resultados para que los que lleguen tarde de la sesión anterior no sobrescriban el trabajo más reciente.