コンテンツにスキップ

リアルタイムトランスポート

セッションをどこで実行するか、およびどの程度まで元のメディアやイベントを制御したいかに応じて、トランスポートを選択します。

シナリオ推奨トランスポート理由
ブラウザの speech-to-speech アプリOpenAIRealtimeWebRTC最も導入しやすい経路です。SDK がマイク入力、再生、WebRTC 接続を管理します。
サーバーサイドの音声ループまたはカスタム音声パイプラインOpenAIRealtimeWebSocketすでに音声の録音/再生を制御していて、イベントへ直接アクセスしたい場合に適しています。
SIP または電話ブリッジOpenAIRealtimeSIPcallId により、SIP 起点の既存 Realtime 通話に RealtimeSession を接続します。
Cloudflare Workers / workerdCloudflare 拡張トランスポートworkerd ではグローバル WebSocket コンストラクターで外向き WebSocket を開けません。
Twilio でのプロバイダー固有の電話フローTwilio 拡張トランスポートTwilio の音声転送と割り込み挙動を処理します。

デフォルトのトランスポート層

Section titled “デフォルトのトランスポート層”

WebRTC はブラウザでのデフォルト選択肢

Section titled “WebRTC はブラウザでのデフォルト選択肢”

デフォルトのブラウザトランスポートは WebRTC を使用します。音声はマイクから自動で取得され、自動で再生されます。そのため クイックスタート では、一時トークンと session.connect(...) だけで接続できます。

この経路では、session.connect() は解決前に初期セッション設定が session.updated で確認されるまで待機を試みるため、音声が流れ始める前に instructions と tools が適用されます。確認イベントが届かない場合でも、タイムアウトのフォールバックがあります。

独自のメディアストリームまたはオーディオ要素を使うには、セッション作成時に OpenAIRealtimeWebRTC インスタンスを指定します。

import { RealtimeAgent, RealtimeSession, OpenAIRealtimeWebRTC } from '@openai/agents/realtime';
const agent = new RealtimeAgent({
name: 'Greeter',
instructions: 'Greet the user with cheer and answer questions.',
});
async function main() {
const transport = new OpenAIRealtimeWebRTC({
mediaStream: await navigator.mediaDevices.getUserMedia({ audio: true }),
audioElement: document.createElement('audio'),
});
const customSession = new RealtimeSession(agent, { transport });
}

より低レベルなカスタマイズとして、OpenAIRealtimeWebRTCchangePeerConnection も受け付けます。これにより、offer 生成前に新規作成された RTCPeerConnection を検査または置き換えできます。

WebSocket はサーバーでのデフォルト選択肢

Section titled “WebSocket はサーバーでのデフォルト選択肢”

セッション作成時に transport: 'websocket' または OpenAIRealtimeWebSocket インスタンスを渡すと、WebRTC の代わりに WebSocket 接続を使用します。これはサーバーサイドのユースケース、電話ブリッジ、カスタム音声パイプラインに適しています。

WebSocket 経路では、session.connect() はソケットが開き初期設定が送信された時点で解決されます。対応する session.updated イベントはわずかに遅れて届く場合があるため、connect() が完了した時点でその更新がすでに反映済みとは限りません。

import { RealtimeAgent, RealtimeSession } from '@openai/agents/realtime';
const agent = new RealtimeAgent({
name: 'Greeter',
instructions: 'Greet the user with cheer and answer questions.',
});
const myRecordedArrayBuffer = new ArrayBuffer(0);
const wsSession = new RealtimeSession(agent, {
transport: 'websocket',
model: 'gpt-realtime',
});
await wsSession.connect({ apiKey: process.env.OPENAI_API_KEY! });
wsSession.on('audio', (event) => {
// event.data is a chunk of PCM16 audio
});
wsSession.sendAudio(myRecordedArrayBuffer);

元の PCM16 音声バイトの処理には、任意の録音/再生ライブラリを使用してください。

高度な統合向けに、OpenAIRealtimeWebSocketcreateWebSocket() を受け付けるため独自のソケット実装を指定できます。また、カスタムコネクター側でソケットを接続状態へ遷移させる場合は skipOpenEventListeners を使えます。@openai/agents-extensions の Cloudflare トランスポートはこれらのフックを基盤にしています。

SIP は通話プロバイダーと電話ブリッジ向け

Section titled “SIP は通話プロバイダーと電話ブリッジ向け”

既存の SIP 起点 Realtime 通話に RealtimeSession を接続したい場合は OpenAIRealtimeSIP を使用します。これは薄い SIP 対応トランスポートです。音声は SIP 通話自体で処理され、SDK セッションは callId で接続します。

  1. OpenAIRealtimeSIP.buildInitialConfig() で初期セッション設定を生成して着信を受け付けます。これにより SIP 招待と後続の SDK セッションが同じデフォルト設定で開始されます。
  2. OpenAIRealtimeSIP トランスポートを使う RealtimeSession を接続し、プロバイダー webhook が発行した callId で接続します。
  3. プロバイダー固有のメディア転送やイベントブリッジが必要な場合は、Twilio 拡張などの統合トランスポートを使用します。
import OpenAI from 'openai';
import {
OpenAIRealtimeSIP,
RealtimeAgent,
RealtimeSession,
type RealtimeSessionOptions,
} from '@openai/agents/realtime';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY!,
webhookSecret: process.env.OPENAI_WEBHOOK_SECRET!,
});
const agent = new RealtimeAgent({
name: 'Receptionist',
instructions:
'Welcome the caller, answer scheduling questions, and hand off if the caller requests a human.',
});
const sessionOptions: Partial<RealtimeSessionOptions> = {
model: 'gpt-realtime',
config: {
audio: {
input: {
turnDetection: { type: 'semantic_vad', interruptResponse: true },
},
},
},
};
export async function acceptIncomingCall(callId: string): Promise<void> {
const initialConfig = await OpenAIRealtimeSIP.buildInitialConfig(
agent,
sessionOptions,
);
await openai.realtime.calls.accept(callId, initialConfig);
}
export async function attachRealtimeSession(
callId: string,
): Promise<RealtimeSession> {
const session = new RealtimeSession(agent, {
transport: new OpenAIRealtimeSIP(),
...sessionOptions,
});
session.on('history_added', (item) => {
console.log('Realtime update:', item.type);
});
await session.connect({
apiKey: process.env.OPENAI_API_KEY!,
callId,
});
return session;
}

Cloudflare Workers や他の workerd ランタイムでは、グローバル WebSocket コンストラクターを使って外向き WebSocket を開くことはできません。拡張パッケージの Cloudflare トランスポートを使用してください。内部で fetch() ベースの upgrade を実行します。

import { CloudflareRealtimeTransportLayer } from '@openai/agents-extensions';
import { RealtimeAgent, RealtimeSession } from '@openai/agents/realtime';
const agent = new RealtimeAgent({
name: 'My Agent',
});
// Create a transport that connects to OpenAI Realtime via Cloudflare/workerd's fetch-based upgrade.
const cfTransport = new CloudflareRealtimeTransportLayer({
url: 'wss://api.openai.com/v1/realtime?model=gpt-realtime',
});
const session = new RealtimeSession(agent, {
// Set your own transport.
transport: cfTransport,
});

完全な設定は Cloudflare 上の Realtime Agent を参照してください。

RealtimeSession は、生の WebSocket か @openai/agents-extensions の専用 Twilio トランスポートのいずれかで Twilio に接続できます。Twilio Media Streams 向けの割り込みタイミングと音声転送を SDK に処理させたい場合、専用トランスポートがより適したデフォルトです。

完全な設定は Twilio 上の Realtime Agent を参照してください。

別の speech-to-speech API を使いたい場合や独自のカスタムトランスポート機構がある場合は、RealtimeTransportLayer インターフェースを実装し、RealtimeTransportEventTypes イベントを自分で発行できます。

必要時の元 Realtime イベントへのアクセス

Section titled “必要時の元 Realtime イベントへのアクセス”

基盤となる Realtime API により直接アクセスしたい場合、方法は 2 つあります。

オプション 1 - トランスポート層へのアクセス

Section titled “オプション 1 - トランスポート層へのアクセス”

RealtimeSession の機能を活かしたまま使いたい場合は、session.transport からトランスポート層にアクセスできます。

トランスポート層は受信したすべてのイベントを * イベントとして発行し、sendEvent() で元イベントを送信できます。これは session.updateresponse.createresponse.cancel など低レベル操作のためのエスケープハッチです。

import { RealtimeAgent, RealtimeSession } from '@openai/agents/realtime';
const agent = new RealtimeAgent({
name: 'Greeter',
instructions: 'Greet the user with cheer and answer questions.',
});
const session = new RealtimeSession(agent, {
model: 'gpt-realtime',
});
session.transport.on('*', (event) => {
// JSON parsed version of the event received on the connection
});
// Send any valid event as JSON. For example triggering a new response
session.transport.sendEvent({
type: 'response.create',
// ...
});

オプション 2 - トランスポート層のみの利用

Section titled “オプション 2 - トランスポート層のみの利用”

自動ツール実行、ガードレール、またはローカル履歴管理が不要な場合は、接続と割り込みのみを管理する「薄い」クライアントとしてトランスポート層だけを利用することもできます。

import { OpenAIRealtimeWebRTC } from '@openai/agents/realtime';
const client = new OpenAIRealtimeWebRTC();
const audioBuffer = new ArrayBuffer(0);
await client.connect({
apiKey: '<api key>',
model: 'gpt-realtime',
initialSessionConfig: {
instructions: 'Speak like a pirate',
outputModalities: ['audio'],
audio: {
input: {
format: 'pcm16',
},
output: {
format: 'pcm16',
voice: 'ash',
},
},
},
});
// optionally for WebSockets
client.on('audio', (newAudio) => {});
client.sendAudio(audioBuffer);