リアルタイムトランスポート
セッションがどこで実行されるか、またどの程度まで元のメディアやイベント制御が必要かに応じて、トランスポートを選択してください。
| シナリオ | 推奨トランスポート | 理由 |
|---|---|---|
| ブラウザーの speech-to-speech アプリ | OpenAIRealtimeWebRTC | 最も手軽な方法です。 SDK がマイク入力、再生、WebRTC 接続を管理します |
| サーバーサイドの音声ループまたはカスタム音声パイプライン | OpenAIRealtimeWebSocket | すでに音声の録音 / 再生を制御しており、イベントへ直接アクセスしたい場合に適しています |
| SIP または電話ブリッジ | OpenAIRealtimeSIP | callId により、既存の SIP 開始 Realtime 通話に RealtimeSession を接続します |
| Cloudflare Workers / workerd | Cloudflare 拡張トランスポート | workerd では、グローバルな WebSocket コンストラクターで外向き WebSocket を開けません |
| Twilio 上のプロバイダー固有の電話フロー | Twilio 拡張トランスポート | Twilio の音声転送と割り込み動作を SDK が処理します |
デフォルトのトランスポート層
Section titled “デフォルトのトランスポート層”WebRTC はブラウザー向けのデフォルトの選択肢
Section titled “WebRTC はブラウザー向けのデフォルトの選択肢”デフォルトのブラウザートランスポートは WebRTC を使用します。音声はマイクから自動的に取得され、自動的に再生されるため、クイックスタート ではエフェメラルトークンと session.connect(...) だけで接続できます。
この経路では、session.connect() は初期セッション設定が session.updated で確認されるまで待機しようとしてから resolve するため、音声の送受信が始まる前に 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 も受け付けます。これにより、offer が生成される前に、新しく作成された RTCPeerConnection を確認または置き換えできます。
WebSocket はサーバー向けのデフォルトの選択肢
Section titled “WebSocket はサーバー向けのデフォルトの選択肢”WebRTC の代わりに WebSocket 接続を使用するには、セッション作成時に transport: 'websocket' または OpenAIRealtimeWebSocket のインスタンスを渡します。これはサーバーサイドのユースケース、電話ブリッジ、カスタム音声パイプラインに適しています。
WebSocket 経路では、session.connect() はソケットが開き、初期設定が送信されると resolve します。対応する 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-1.5',});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 は通話プロバイダーと電話ブリッジ向け”既存の SIP 開始 Realtime 通話に RealtimeSession を接続したい場合は、OpenAIRealtimeSIP を使用してください。これは SIP 対応の薄いトランスポートです。音声は SIP 通話自体で処理され、SDK セッションは callId で接続されます。
OpenAIRealtimeSIP.buildInitialConfig()を使って初期セッション設定を生成し、着信を受け付けます。これにより、SIP 招待と後続の SDK セッションが同じデフォルト設定から開始されますOpenAIRealtimeSIPトランスポートを使うRealtimeSessionを接続し、プロバイダー webhook が発行したcallIdで connect します- プロバイダー固有のメディア転送やイベントブリッジが必要な場合は、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-1.5', 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() ベースの 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 を参照してください。
Twilio 電話通話
Section titled “Twilio 電話通話”RealtimeSession は、生の WebSocket または @openai/agents-extensions の専用 Twilio トランスポートのいずれかを使って Twilio に接続できます。Twilio Media Streams に対して SDK に割り込みタイミングや音声転送を処理させたい場合は、専用トランスポートをデフォルトの選択肢として使うのが適しています。
完全なセットアップについては、Twilio 上の Realtime Agent を参照してください。
独自トランスポートの導入
Section titled “独自トランスポートの導入”別の speech-to-speech API を使用したい場合や、独自のカスタムトランスポート機構がある場合は、RealtimeTransportLayer インターフェースを実装し、RealtimeTransportEventTypes イベントを自分で emit できます。
必要に応じた元の Realtime イベントへのアクセス
Section titled “必要に応じた元の Realtime イベントへのアクセス”基盤となる Realtime API により直接アクセスしたい場合は、2 つの方法があります。
方法 1 - トランスポート層へのアクセス
Section titled “方法 1 - トランスポート層へのアクセス”RealtimeSession のすべての機能の恩恵を受けつつ利用したい場合は、session.transport を通じてトランスポート層にアクセスできます。
トランスポート層は、受信したすべてのイベントを * イベントで emit し、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-1.5',});
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-1.5', 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);