コンテンツにスキップ

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

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

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

デフォルトのトランスポート層は WebRTC を使用します。音声はマイクから録音され、自動的に再生されます。

独自のメディアストリームや audio 要素を使用するには、セッション作成時に 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 も受け付けます。これにより、オファー生成前に新規作成された RTCPeerConnection を検査または置換できます。

セッション作成時に transport: 'websocket' または OpenAIRealtimeWebSocket のインスタンスを渡すことで、WebRTC の代わりに WebSocket 接続を使用できます。これは Twilio で電話エージェントを構築するなど、サーバー側のユースケースで有効です。

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 トランスポートは、これらのフック上に構築されています。

OpenAIRealtimeSIP トランスポートを使用して、Twilio などのプロバイダーからの SIP 通話をブリッジします。トランスポートは、テレフォニー・プロバイダーが発行する SIP イベントと Realtime セッションを同期させます。

  1. OpenAIRealtimeSIP.buildInitialConfig() で初期セッション構成を生成して、着信を受け入れます。これにより、SIP 招待と Realtime セッションが同一のデフォルトを共有します
  2. OpenAIRealtimeSIP トランスポートを使用する RealtimeSession をアタッチし、プロバイダーの Webhook によって発行された callId で接続します
  3. セッションイベントをリッスンして、通話分析、文字起こし、またはエスカレーションロジックを駆動します
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)の注意事項

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',
});
const session = new RealtimeSession(agent, {
// Set your own transport.
transport: cfTransport,
});

独自トランスポート機構の構築

Section titled “独自トランスポート機構の構築”

別の音声対音声 API を使用したい場合や、独自のカスタムトランスポート機構を持っている場合は、RealtimeTransportLayer インターフェースを実装し、RealtimeTransportEventTypes イベントを発火することで独自に作成できます。

Realtime API へのより直接的なアクセス

Section titled “Realtime API へのより直接的なアクセス”

OpenAI Realtime API を使用しつつ、より直接的に Realtime API にアクセスしたい場合は、次の 2 つのオプションがあります。

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

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

RealtimeSession のあらゆる機能の恩恵を受けたい場合は、session.transport を介してトランスポート層にアクセスできます。

トランスポート層は受信したあらゆるイベントを * イベントの下で発火し、sendEvent() メソッドを使用して元のイベントを送信できます。

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-4o-mini-realtime-preview',
initialSessionConfig: {
instructions: 'Speak like a pirate',
outputModalities: ['text', 'audio'],
audio: {
input: {
format: 'pcm16',
},
output: {
format: 'pcm16',
voice: 'ash',
},
},
},
});
// optionally for WebSockets
client.on('audio', (newAudio) => {});
client.sendAudio(audioBuffer);