リアルタイムトランスポート
セッションが実行される場所と、元のメディアやイベントをどの程度制御する必要があるかに基づいて、トランスポートを選択してください。
| シナリオ | 推奨トランスポート | 理由 |
|---|---|---|
| ブラウザーの音声対音声アプリ | OpenAIRealtimeWebRTC | 最も手間の少ない方法です。SDK がマイク入力のキャプチャ、再生、WebRTC 接続を管理します。 |
| サーバーサイドの音声ループまたはカスタムオーディオパイプライン | OpenAIRealtimeWebSocket | すでに音声のキャプチャ/再生を制御しており、イベントへ直接アクセスしたい場合に適しています。 |
| SIP またはテレフォニーブリッジ | OpenAIRealtimeSIP | callId により、既存の SIP 起点の Realtime 通話に RealtimeSession をアタッチします。 |
| Cloudflare Workers / workerd | Cloudflare 拡張トランスポート | 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 });}より低レベルのカスタマイズでは、OpenAIRealtimeWebRTC は changePeerConnection も受け付けます。これにより、オファーが生成される前に、新しく作成された RTCPeerConnection を確認したり置き換えたりできます。
WebSocket はサーバーのデフォルト選択肢
Section titled “WebSocket はサーバーのデフォルト選択肢”WebRTC の代わりに WebSocket 接続を使用するには、セッション作成時に transport: 'websocket' または OpenAIRealtimeWebSocket のインスタンスを渡します。これは、サーバーサイドのユースケース、テレフォニーブリッジ、カスタムオーディオパイプラインに適しています。
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-2',});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 オーディオバイトを処理してください。
高度な連携では、OpenAIRealtimeWebSocket は独自のソケット実装を指定できるように createWebSocket() を受け付けます。また、そのカスタムコネクターがソケットを接続済み状態に遷移させる責任を持つ場合に使う skipOpenEventListeners も受け付けます。@openai/agents-extensions の Cloudflare トランスポートは、これらのフックを基盤に構築されています。
SIP は通話プロバイダーとテレフォニーブリッジ向け
Section titled “SIP は通話プロバイダーとテレフォニーブリッジ向け”RealtimeSession を既存の SIP 起点の Realtime 通話にアタッチしたい場合は、OpenAIRealtimeSIP を使用します。これは SIP 対応の薄いトランスポートです。音声は SIP 通話自体によって処理され、SDK セッションは callId で接続します。
- 着信を受け付けるには、
OpenAIRealtimeSIP.buildInitialConfig()で初期セッション設定を生成します。これにより、SIP 招待と後続の SDK セッションが同じデフォルトから開始されます。 OpenAIRealtimeSIPトランスポートを使用するRealtimeSessionをアタッチし、プロバイダー Webhook で発行されたcallIdで接続します。- プロバイダー固有のメディア転送やイベントブリッジが必要な場合は、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-2', 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
Section titled “Cloudflare Workers と workerd”Cloudflare Workers などの workerd ランタイムは、グローバルな WebSocket コンストラクターを使ってアウトバウンド WebSocket を開くことができません。拡張パッケージの Cloudflare トランスポートを使用してください。内部で fetch() ベースのアップグレードを実行します。
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-2',});
const session = new RealtimeSession(agent, { // Set your own transport. transport: cfTransport,});完全なセットアップについては、Cloudflare 上の Realtime Agent を参照してください。
Twilio の電話通話
Section titled “Twilio の電話通話”元の WebSocket または @openai/agents-extensions の専用 Twilio トランスポートを使用して、RealtimeSession を Twilio に接続できます。SDK に Twilio Media Streams の割り込みタイミングと音声転送を処理させたい場合は、専用トランスポートがデフォルトとしてより適しています。
完全なセットアップについては、Twilio 上の Realtime Agent を参照してください。
独自トランスポートの持ち込み
Section titled “独自トランスポートの持ち込み”別の音声対音声 API を使用したい場合や、独自のカスタムトランスポート機構がある場合は、RealtimeTransportLayer インターフェイスを実装し、RealtimeTransportEventTypes イベントを自分で発行できます。
必要に応じた元の Realtime イベントへのアクセス
Section titled “必要に応じた元の Realtime イベントへのアクセス”基盤となる Realtime API により直接アクセスしたい場合、選択肢は 2 つあります。
オプション 1 - トランスポートレイヤーへのアクセス
Section titled “オプション 1 - トランスポートレイヤーへのアクセス”引き続き RealtimeSession のすべての機能のメリットを得たい場合は、session.transport を通じて使用中のトランスポートレイヤーにアクセスできます。
トランスポートレイヤーは、受信したすべてのイベントを * イベントとして発行し、sendEvent() で元のイベントを送信できます。これは、session.update、response.create、response.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-2',});
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 responsesession.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-2', initialSessionConfig: { instructions: 'Speak like a pirate', outputModalities: ['audio'], audio: { input: { format: 'pcm16', }, output: { format: 'pcm16', voice: 'ash', }, }, },});
// optionally for WebSocketsclient.on('audio', (newAudio) => {});
client.sendAudio(audioBuffer);