Después de conectarte a GPT-Live, usa los eventos de sesión para actualizar el contexto, mostrar transcripciones y gestionar el ciclo de vida de la conexión. El modelo puede escuchar y hablar al mismo tiempo, así que mantén separados los eventos recibidos, la reproducción de audio y el estado de las tareas del backend en tu aplicación.
Esta guía supone que tu conexión ya emitió session.started. Consulta Conexiones para configurar la conexión y la transmisión continua de audio, y Delegación y herramientas para 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 la conversación se extiende.
Campos de configuración
| Ajuste | Configurar al inicio | Cambiar durante la sesión |
|---|---|---|
| Modelo | Configura el campo obligatorio model. | Inicia una nueva sesión para cambiarlo. |
| Instrucciones | Configura instructions para definir el comportamiento durante la conversación, con un máximo de 16 384 tokens. | Agrega instrucciones con session.instructions.append. |
| Historial | Establece input con los mensajes de texto anteriores pertinentes. Su valor predeterminado es []. | Agrega contexto; no reemplaces el historial inicial. |
| Voz | Establece audio.output.voice en una voz compatible o una voz personalizada autorizada. El valor predeterminado es marin. | Inicia una nueva sesión para cambiarla. |
| Delegación | Establece delegation.type en client o responses. Si se omite la delegación o se establece en null, se selecciona el modo cliente. | Actualiza la configuración de Responses dentro del modo actual. |
| Almacenamiento | Establece store en true para permitir la creación de un fork de la sesión. Su valor predeterminado es false. | Elige al inicio. |
Opciones de voz
Elige una voz al crear la sesión. Establece audio.output.voice en el nombre que usa la API, como "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 Estados Unidos | Femenina | Generada |
| Cinder | cinder | Inglés | Del sur de Estados Unidos | Masculina | Generada |
La influencia regional describe el estilo de habla de una voz, pero no garantiza la fidelidad del acento. Para usar una voz aprobada creada a partir de tu propia grabación, consulta Voces personalizadas.
Para WebSocket, elige el valor compartido de audio.format al inicio; no se puede cambiar durante la sesión. Para WebRTC, omite este campo porque la conexión negocia su formato de audio. Consulta Formatos de audio de WebSocket para obtener detalles sobre el formato y la transmisión continua.
Actualizar una sesión en curso
Usa session.update para cambiar session.delegation.responses en una sesión que ya use la delegación a Responses. Envía solo los ajustes que quieras cambiar; los ajustes omitidos conservan sus valores. Consulta Configurar la delegación a Responses para conocer los ajustes y el flujo de trabajo de actualización.
No puedes cambiar el modo de delegación después del inicio. En particular, establecer delegation en null selecciona el modo cliente; no restablece una sesión de Responses. Los campos de inicio model, instructions, input, audio y store no se aceptan en las actualizaciones. Los campos de configuración desconocidos se rechazan.
Una actualización exitosa emite session.updated con la configuración completa de la sesión, con todos los valores resueltos. Cuando proporcionas un event_id, el acuse de recibo lo devuelve como client_event_id. Revisa si hay comandos rechazados, además de acuses de recibo. La aceptación confirma la actualización de la configuración; no demuestra que se haya ejecutado una tarea del backend ni que el modelo haya hablado.
Proporcionar historial y contexto
Usa el historial de inicio para retomar un tema y agrega contexto relevante a medida que avance la conversación. Mantén las instrucciones confiables de la aplicación separadas de los mensajes del usuario y de los resultados con información factual.
Iniciar una sesión con una conversación previa
Incluye mensajes de texto previos en session.input al crear la sesión. Por ejemplo, agrega este campo input a tu 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 acepta hasta 128 mensajes y un total de 8192 tokens. Los roles admitidos son developer, user y assistant, cada uno con una parte de texto. Los mensajes del desarrollador y del usuario usan input_text; los del asistente usan text o output_text. Incluye las instrucciones confiables de la aplicación en instructions o en un mensaje del desarrollador. La lista no acepta el rol system.
Selecciona el historial necesario para la siguiente interacción. input es un campo de inicio, no una forma de reemplazar el historial durante una sesión en curso. Tampoco acepta todos los tipos de elementos de entrada del backend que se usan en la delegación a Responses.
Entender cuándo llega el contexto al modelo
Todo el contenido de input proporcionado al crear la sesión está disponible para el modelo cuando esta comienza. Incluye en este campo el contexto que el modelo necesita desde el principio.
Durante una sesión en curso, los eventos session.instructions.append, session.thinking.append y session.commentary.append incorporan contenido al modelo de forma progresiva. Sus acuses de recibo esperan hasta que el avance de las tramas alcance el final estimado de la inyección de contexto. Los valores devueltos de start_ms y end_ms describen un intervalo estimado en la línea de tiempo de la sesión, no la finalización del habla ni de la reproducción. No demuestran que el modelo haya procesado toda la actualización. No supongas que lo siguiente que diga reflejará la actualización completa.
Si el avance de las tramas se detiene, un acuse de recibo puede quedar pendiente. Al cerrar la sesión, se informa un error para las adiciones pendientes. Relaciona cada acuse de recibo con el event_id enviado mediante client_event_id y sigue manejando los errores mientras esperas.
Agregar contexto durante la conversación
Elige un evento según cómo deba usar el modelo la actualización:
session.instructions.append: agrega instrucciones confiables de la aplicación que influyan en el comportamiento y el habla.session.thinking.append: agrega contexto factual sin pedirle al modelo que lo diga de inmediato.session.commentary.append: proporciona información para que el modelo la diga en voz alta, aunque puede parafrasearla.
Cada evento recibe content como una cadena de texto simple de hasta 500 tokens y requiere delegation_id. Usa null para el contexto que se aplique a toda la sesión. Por ejemplo, envía lo siguiente después de que tu aplicación haya verificado la aceptación del usuario e 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.",
});
}Espera a recibir session.thinking.appended con client_event_id: "context_1" o maneja un error. El acuse de recibo confirma que se aceptó el contexto. No confirma que se haya hablado, reproducido audio ni completado una acción externa.
El contexto silencioso puede influir en lo que se diga más adelante; no constituye una barrera de privacidad. No incluyas en ninguno de los tres eventos credenciales, secretos ni texto que el modelo nunca deba revelar. Usa el evento de instrucciones para el comportamiento definido por la aplicación, no para resultados de herramientas que no sean confiables. Haz cumplir los permisos y las confirmaciones requeridas en tu aplicación.
Para la navegación entre páginas, las selecciones y otros cambios en la interfaz, consulta Compartir contexto de la interfaz para enviar actualizaciones concisas que ayuden a GPT-Live a entender a qué se refiere el usuario.
Para los resultados asociados a una tarea del backend, usa un ID conocido de delegación del cliente y sigue las indicaciones de Enviar el tipo de actualización adecuado. Ese ID no es un ID de respuesta de Responses ni un ID de llamada a herramienta.
Usa instrucciones para orientar la conversación cuando se active una comprobación de la aplicación. Tu servidor puede monitorear eventos y enviar estas correcciones a través de un WebSocket de canal lateral conectado a la sesión existente, o a través de su WebSocket principal. Consulta Aplicar medidas de protección a la conversación para conocer las comprobaciones simultáneas, el bloqueo de acciones y el control de la reproducción.
Crear la interfaz de conversación
Muestra las transcripciones y el estado del micrófono independientemente del progreso del backend. Recibir texto del asistente no indica cuánto audio ha escuchado el usuario.
Deltas de transcripción
Escucha los eventos session.input_transcript.delta para la voz del usuario y session.output_transcript.delta para la voz del asistente. Cada evento contiene un fragmento de texto y su intervalo 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
}
Agrega los fragmentos en orden para cada interlocutor y conserva start_ms y end_ms. Estos valores representan milisegundos en la línea de tiempo de la sesión, con intervalos que incluyen el inicio y excluyen el final. No son marcas de tiempo del reloj, horas de llegada de los paquetes ni alineaciones exactas de palabras.
Solo los intervalos que contienen texto de transcripción producen eventos, y la entrega por la red puede ser irregular. No deduzcas que hay silencio por la ausencia de un evento ni trates un fragmento como un turno completo del usuario. Los deltas de transcripción no tienen un ID de elemento ni un evento que confirme de forma definitiva que el turno terminó.
Procesar los fragmentos de transcripción es opcional. Puedes usarlos para actualizar tu interfaz, ejecutar comprobaciones o comenzar el trabajo anticipadamente mientras continúa la conversación. Para comprobaciones ligeras, considera un modelo pequeño como gpt-5.6-luna con un esfuerzo de razonamiento bajo. Consulta Reaccionar a los fragmentos de transcripción para ver ejemplos y orientación sobre la conexión.
Para aplicar medidas de protección a la conversación, comprueba el texto acumulado del usuario y del asistente a medida que llega. La entrega de transcripciones no proporciona un búfer anticipado para aprobar lo que se dice antes de reproducirlo. Consulta Controlar la reproducción cuando sea necesario.
Si tu interfaz agrupa el texto en turnos, permite modificar esa agrupación. Conserva los fragmentos originales, permite que los intervalos del usuario y del asistente se superpongan y ajusta cualquier tiempo de espera entre fragmentos usando conversaciones grabadas. Una breve respuesta de asentimiento del otro interlocutor puede formar parte de un intercambio en curso. La agrupación de fragmentos no debe activar por sí sola la ejecución de herramientas ni cancelar trabajo del backend.
Mantén la información temporal de las transcripciones separada de la reproducción de audio. Los eventos session.output_audio.delta de WebSocket no tienen campos de tiempo ni un evento que indique que el audio de salida terminó; WebRTC entrega el audio a través de su pista multimedia. Consulta Conexiones para obtener información sobre el manejo del audio.
Mostrar subtítulos
Crea filas de subtítulos que puedan ampliarse mientras ambos interlocutores hablan:
- Conserva el texto. Guarda los valores originales de
delta,start_msyend_msde cada interlocutor. Concatena el texto exactamente como lo recibes, incluidos los espacios y las palabras repetidas. No elimines espacios de los extremos de los fragmentos ni insertes espacios entre ellos. - Actualiza el texto de cada interlocutor de forma independiente. Permite que las filas del usuario y del asistente se amplíen cuando hablan al mismo tiempo. Mantén visible el texto anterior del asistente después de una interrupción e inicia una fila nueva cuando el asistente vuelva a hablar.
- Mantén estables las filas. Asigna IDs de visualización en tu aplicación y conserva el orden de las filas a medida que se agrega texto. No derives la identidad de una fila del texto cambiante ni de las marcas de tiempo de finalización, ni muevas una fila al final cada vez que recibe un fragmento.
- Revisa la agrupación cuando lleguen fragmentos con retraso. Usa las marcas de tiempo de la transcripción para agrupar fragmentos cercanos del mismo interlocutor. Permite que el texto que llega con retraso actualice filas anteriores y modifica la asignación de fragmentos sin perder los originales. Estos grupos de visualización no son turnos semánticos completos; cualquier umbral de separación es una decisión de la aplicación que debes probar.
- Deja que quien lee controle el desplazamiento. Desplaza la vista para seguir el texto nuevo mientras la persona se encuentre al final. Pausa el desplazamiento automático cuando se desplace hacia arriba y ofrece una forma de volver a los subtítulos más recientes.
- Muestra el progreso de las herramientas en un área de estado. Usa los eventos de transcripción del asistente para los subtítulos de voz. Muestra la actividad de las herramientas y los resultados del backend fuera de los subtítulos; recibir un resultado no significa que el asistente lo haya dicho.
Prueba la visualización con voces superpuestas, respuestas breves de asentimiento, interrupciones, pausas largas y traducciones en las que el texto de los dos interlocutores llegue a ritmos distintos.
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 considerar que el comando fue aceptado. Para reanudar la entrada, envía session.input_audio.unmute y espera a recibir session.input_audio.unmuted. Maneja los errores de ambos comandos.
Silenciar la entrada no detiene la inferencia, el trabajo delegado ni la voz generada. Controla la captura del micrófono y la reproducción de audio por separado en tu aplicación cuando necesites esos controles.
Saludar antes de que hable la persona que llama
Para solicitar un saludo después de session.started:
- Envía un único comando
session.instructions.appendnuevo condelegation_id: null. Incluye el saludo, su idioma y una instrucción explícita para saludar de inmediato sin esperar a que hable la persona que llama, y luego hacer una pausa y escuchar. Conserva las instrucciones de inicio existentes. - Espera a recibir
session.instructions.appendedy verifica que suclient_event_idcoincida con el de tu comando. Si el comando se rechaza, maneja el rechazo antes de continuar. - Mantén activo el audio de entrada, incluido el silencio antes de que hable la persona que llama. En WebSocket, sigue enviando
session.input_audio.append; en WebRTC, mantén activa la pista de audio de entrada negociada. Observa la transcripción y el audio de salida para detectar el saludo.
Usa el idioma especificado por tu aplicación hasta que hable la persona que llama; no lo deduzcas de un nombre, número de teléfono o ubicación. Consulta Diseño de prompts para modelos de voz para obtener orientación sobre el diseño de prompts.
Si el saludo debe seguir las instrucciones de la aplicación, envía esas instrucciones con session.instructions.append y luego usa un mensaje breve de session.commentary.append para pedirle al asistente que comience. Por ejemplo: “Begin the conversation now, following the instructions provided.” Mantén activo el audio de entrada, incluido el silencio antes de que hable la persona que llama.
Las instrucciones solicitan un saludo; no garantizan una formulación exacta ni una reproducción sin interrupciones. La API no emite un evento que indique que la apertura terminó, y la confirmación de recepción no significa que se haya escuchado el saludo. Usa la reproducción controlada por la aplicación si el audio debe reproducir el texto literalmente. Prueba el saludo con los idiomas y las interrupciones que admite tu aplicación.
Comunicar un aviso informativo
Usa session.instructions.append para solicitar que un aviso informativo se diga con una formulación específica. session.commentary.append puede parafrasear el texto. Por ejemplo, después de session.started, envía:
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 describe en Saludar antes de que hable la persona que llama. Elige cuidadosamente el momento de comunicar el aviso: una instrucción enviada durante la conversación puede interrumpir a quien esté hablando.
Esto solicita una formulación; no garantiza que se diga exactamente así. Verifica el aviso hablado completo y su reproducción real antes de marcarlo como comunicado. session.instructions.appended solo confirma que la instrucción fue aceptada. Si se requiere una reproducción exacta del audio, reproduce una grabación verificada o un clip renderizado a través de tu aplicación y controla la salida de GPT-Live mientras se reproduce. Consulta Controlar la reproducción cuando sea necesario.
Administrar conversaciones más largas
GPT-Live administra automáticamente el contexto durante las conversaciones largas; no se necesita ningún parámetro de configuración. Las instrucciones que proporcionas al inicio de la sesión se conservan durante toda la compactación. No necesitas volver a enviarlas.
La ventana de contexto predeterminada admite 128 000 tokens, incluidas 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 el historial más antiguo de la conversación. Cuando el uso del contexto supera el 90 %, inicia un motor de voz de reemplazo dentro de la misma sesión. El motor de reemplazo recibe tus instrucciones originales y hasta 8192 tokens del historial de la conversación, con mensajes recientes y, cuando está disponible, un resumen de los mensajes más antiguos. La preparación de un resumen no cambia de inmediato el contexto del motor en ejecución.
Los detalles más antiguos de la conversación pueden resumirse u omitirse. Conserva en tu aplicación los datos importantes, las acciones confirmadas y el estado actual de la tarea, y proporciona el contexto relevante cuando sea necesario.
Almacenar una sesión y crear un fork
Establece store en true en la configuración al crear la sesión para guardar una grabación que luego puedas descargar o usar para crear un fork. El almacenamiento tiene el valor predeterminado false y debe estar habilitado para tu proyecto. Las descargas y los forks requieren una grabación almacenada completa y una política de datos que permita la persistencia. Las grabaciones vencen después de 30 días. Con la retención cero de datos, store se trata como false, y las descargas de grabaciones y los forks no están disponibles. Consulta Controles de datos de GPT-Live.
Por ejemplo, agrega este campo al objeto session en tu evento session.start de WebSocket o en tu solicitud de creación de WebRTC:
{
"store": true
}
Guarda el ID de la sesión de origen que recibes en session.started o en la respuesta de creación de WebRTC. Un fork inicia una sesión nueva con un ID nuevo a partir del estado de la sesión almacenada. No vuelve a abrir la conexión original ni reutiliza el ID de la sesión de origen.
Inicia el fork a través del transporte que usa tu aplicación:
| Transporte | 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 transport.sdp recibida a la nueva conexión entre pares. |
Un fork hereda la configuración de la sesión almacenada, sujeta a las reglas de transporte que se indican a continuación. Para un fork de WebSocket, envía session.start con un objeto session obligatorio; {} no reemplaza ningún valor. No proporciones un modelo nuevo ni repitas las instrucciones o la entrada originales. Puedes reemplazar store, la configuración de delegación de Responses y el formato de audio de la nueva conexión WebSocket. Los forks de WebRTC pueden reemplazar store, la configuración de delegación de Responses y los permisos del cliente frontend. Si omites store en un fork, se hereda el valor de la sesión de origen.
Un fork de WebSocket no hereda el formato de audio de origen: establece audio.format explícitamente o usa el formato predeterminado PCM16 a 24 kHz. También descarta los permisos heredados del canal de datos del frontend. Los forks de WebRTC negocian su formato de audio y rechazan audio.format; conservan la configuración de permisos del frontend a menos que la reemplaces.
Espera a recibir session.started antes de enviar más comandos de WebSocket. WebRTC se inicia mediante la solicitud HTTP y no debe recibir un segundo session.start en su canal de datos.
Iniciar un fork de WebSocket
Establece OPENAI_API_KEY. Los ejemplos usan el ID de la sesión de origen almacenada que guardó tu aplicación. 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 flujo de conexión de WebSocket. Consulta la referencia de forks de 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;
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" });
} else if (event.message.type === "session.closed") {
console.log("Final usage:", event.message.usage);
finalized = true;
break;
}
}
}
if (!finalized) throw new Error("Connection closed before session.closed");
} finally {
ws.close();
}
}Iniciar un fork de WebRTC
Crea una oferta SDP nueva en tu frontend y envíala a tu backend. Los siguientes ejemplos de backend usan esa oferta y el ID de la sesión de origen almacenada de tu aplicación:
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 a tu frontend, aplica transport.sdp como respuesta de la nueva conexión entre pares y conserva el nuevo session.id. Mantén la clave de API en tu backend.
Usa el nuevo ID de sesión para las conexiones de canal lateral y los controles de sesión posteriores. Mantén el estado de las tareas de la aplicación por separado: restaurar el estado de la conversación no confirma que se haya completado una acción pendiente del backend. Verifica y concilia los resultados inciertos antes de volver a intentar una acción. Si no tienes una sesión almacenada para crear un fork, inicializa una sesión nueva con el historial guardado.
Descargar una grabación
Una vez finalizada la grabación almacenada, descarga su audio con GET /v1/live/sessions/{session_id}/content. La respuesta es un WAV estéreo binario, con el audio de entrada en el canal izquierdo y el audio de salida en el canal derecho. Los ejemplos usan el ID de la sesión almacenada de tu aplicación y escriben la respuesta a medida que llega en recording.wav:
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"));
}Manejar errores y finalizar la sesión
Sigue leyendo los eventos de la sesión hasta que esta finalice. Distingue entre un comando rechazado, una conexión fallida y una sesión completada para que tu aplicación pueda recuperarse adecuadamente.
Manejar comandos rechazados
Lee los eventos error junto con las confirmaciones de recepción. Cuando está presente, error.client_event_id identifica el comando saliente 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"
}
}
Un código de error puede ser null, y un error puede no incluir un ID de evento del cliente. Maneja esos casos sin asumir que un comando se ejecutó correctamente. Ante un error de campo inmutable, conserva la configuración actual o crea una nueva sesión con la configuración deseada.
Manejar la moderación
La moderación puede afectar la sesión de dos maneras:
- Algunos eventos de moderación finalizan la sesión.
- Otros cortan el audio del asistente durante el resto de su intervención actual y emiten un evento
errorsin finalizar la sesión.
Lee los eventos error incluso mientras se reproduce el audio. No asumas que todos los errores de moderación cierran la sesión ni que una interrupción del audio significa que la conexión falló. Mantén el estado de la aplicación alineado con el ciclo de vida de la sesión y no marques un mensaje hablado interrumpido como entregado por completo. Las medidas de protección de la conversación a nivel de aplicación siguen siendo independientes de este comportamiento de moderación integrado.
Uso y cierre ordenado
session.usage.updated informa 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 }
}
Estos valores son instantáneas, no incrementos que debas sumar. El uso de tokens del backend se contabiliza por separado; conserva los datos de uso de los eventos anidados de finalización de Responses. Consulta Optimización de costos para obtener información sobre la contabilización del uso.
Para realizar un cierre ordenado:
- Completa todo el trabajo delegado de Responses que necesite tu aplicación, incluidos los resultados de funciones y las continuaciones de respuestas pendientes.
- Registra el listener de
session.closedantes de enviarsession.close. - Envía
session.closey deja de enviar trabajo nuevo a la sesión. Mantén activos la conexión WebSocket o WebRTC, el canal de datos y cualquier receptor de canal lateral conectado mientras se procesan los eventos pendientes de la sesión. - Lee los valores finales de
usage.secondsyreason, así como la instantánea de la sesión, ensession.closed. Conserva los datos de uso del trabajo delegado que ya hayas recibido a través deresponse.event. - Libera los recursos de transporte y los dispositivos de audio después de ese evento. Si la finalización falla o excede el tiempo de espera establecido por tu aplicación, informa que la finalización quedó incompleta y libera los recursos.
Enviar session.close cancela las Responses en cola y rechaza los comandos posteriores. Una respuesta activa puede finalizar, pero una que esté esperando el resultado de una función no puede continuar después de que comience el cierre. Decide por separado si completar o cancelar el trabajo que tu aplicación ejecuta mediante delegación al cliente.
El evento session.closed confirma la finalización; la sesión incluida es una instantánea de la configuración. El cierre del socket por sí solo no confirma que la operación haya finalizado correctamente, y un código de cierre del transporte posterior a un evento final válido no invalida la finalización. Cerrar WebRTC inmediatamente después de enviar el comando puede impedir la entrega del evento final.
El campo reason del evento final explica 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 servidor ascendente se perdió de forma inesperada. |
Un evento session.closed confirma la finalización incluso cuando el motivo es una pérdida de conexión o una terminación por seguridad. Sin ese evento, el uso final queda sin confirmar. Una sesión almacenada puede tardar más en finalizar mientras se guarda su grabación; elige un tiempo de espera para la aplicación que contemple el almacenamiento.
Recuperarse de una falla de conexión
Un error HTTP al crear la sesión significa que esta no llegó a session.started. Maneja los errores de inicio por separado de los errores de una sesión en ejecución. Si una conexión activa falla antes de session.closed, conserva los datos de uso más recientes que hayas observado y marca el uso final como no confirmado.
Si hay una sesión almacenada disponible, crea un fork de ella para iniciar una nueva sesión a partir de su estado guardado. De lo contrario, crea una sesión de reemplazo con el historial guardado pertinente. Concilia las acciones pendientes con tu backend antes de reintentarlas y descarta los resultados obsoletos de la sesión anterior. Restaura el estado de la aplicación explícitamente en lugar de asumir que una nueva conexión reanuda la sesión anterior o su trabajo pendiente.