リアルタイムトランスポート
セッションの実行場所と、元のメディアやイベントをどの程度制御する必要があるかに基づいて、トランスポートを選択します。
| シナリオ | 推奨トランスポート | 理由 |
|---|---|---|
| ブラウザーの音声対音声アプリ | OpenAIRealtimeWebRTC | 最も手間が少ない方法です。SDK がマイク入力、再生、WebRTC 接続を管理します。 |
| サーバー側の音声ループまたはカスタム音声パイプライン | OpenAIRealtimeWebSocket | 音声のキャプチャと再生をすでに制御しており、イベントに直接アクセスしたい場合に適しています。 |
| SIP またはテレフォニーブリッジ | OpenAIRealtimeSIP | callId を使用して、RealtimeSession を既存の SIP 起点の Realtime 通話に接続します。 |
| Cloudflare Workers / workerd | Cloudflare 拡張トランスポート | workerd では、グローバルな WebSocket コンストラクターを使用して外向きの WebSocket 接続を開けません。 |
| Twilio のプロバイダー固有の電話フロー | Twilio 拡張トランスポート | Twilio の音声転送と割り込み動作を処理します。 |
デフォルトのトランスポート層
Section titled “デフォルトのトランスポート層”ブラウザーでのデフォルトの選択肢:WebRTC
Section titled “ブラウザーでのデフォルトの選択肢:WebRTC”デフォルトのブラウザートランスポートは WebRTC を使用します。音声はマイクからキャプチャされ、自動的に再生されます。そのため、クイックスタートでは、一時トークンと session.connect(...) だけで接続できます。
この方法では、session.connect() は処理を完了する前に、初期セッション設定が session.updated で確認応答されるまで待機しようとします。そのため、音声の送受信が始まる前に指示とツールが適用されます。確認応答が届かない場合に備えて、タイムアウトによるフォールバックも用意されています。
独自のメディアストリームまたは音声要素を使用するには、セッションの作成時に 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() { // Keep a handle on the stream you pass in. The transport does not stop a caller-supplied // stream on close(), so your application owns it and is responsible for ending it. const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, });
const transport = new OpenAIRealtimeWebRTC({ mediaStream, audioElement: document.createElement('audio'), });
const customSession = new RealtimeSession(agent, { transport });
// Later, once the application is actually done with the microphone, release it. Leaving this // out keeps the microphone indicator on even after the session closes. // mediaStream.getTracks().forEach((track) => track.stop());}より低レベルのカスタマイズ向けに、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.1',});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.1', 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.1',});
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 に接続できます。Twilio Media Streams の割り込みタイミングと音声転送を SDK に処理させる場合は、専用トランスポートをデフォルトとして使用することをお勧めします。
完全なセットアップについては、Twilio 上の Realtime Agentを参照してください。
独自トランスポートの利用
Section titled “独自トランスポートの利用”別の音声対音声 API を使用する場合や、独自のカスタムトランスポート機構がある場合は、RealtimeTransportLayer インターフェースを実装し、RealtimeTransportEventTypes イベントを自分で発行できます。
必要に応じた元の Realtime イベントへのアクセス
Section titled “必要に応じた元の Realtime イベントへのアクセス”基盤となる Realtime API により直接的にアクセスする場合は、2 つの選択肢があります。
オプション 1 - トランスポート層へのアクセス
Section titled “オプション 1 - トランスポート層へのアクセス”RealtimeSession のすべての機能を引き続き活用する場合は、session.transport を通じてトランスポート層にアクセスできます。
トランスポート層は、受信したすべてのイベントを * イベントとして発行し、sendEvent() を使用して元のイベントを送信できます。* リスナーは、解析された元の JSON ペイロードの構造化クローンを受け取ります。これには、現在の SDK スキーマで認識されていないフィールドも含まれます。名前付きイベントおよび派生イベントのリスナーは、引き続き検証・正規化されたイベントオブジェクトを受け取ります。これは、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.1',});
session.transport.on('*', (event) => { // Event received from the underlying Realtime transport});
// Send any valid client event, for example, to trigger 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.1', initialSessionConfig: { instructions: 'Speak like a pirate', outputModalities: ['audio'], audio: { input: { format: 'pcm16', }, output: { format: 'pcm16', voice: 'ash', }, }, },});
// Listen for audio when you manage playback yourselfclient.on('audio', (newAudio) => {});
client.sendAudio(audioBuffer);