Skip to content

Commit 9fdecdb

Browse files
feat(realtime): make websocket URL configurable (#238)
1 parent edf4c6b commit 9fdecdb

File tree

5 files changed

+32
-4
lines changed

5 files changed

+32
-4
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openai/agents-realtime': minor
3+
---
4+
5+
Expose configurable URL in OpenAIRealtimeWebSocket constructor and RealtimeSession.connect.

packages/agents-realtime/src/openaiRealtimeWebsocket.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ export type OpenAIRealtimeWebSocketOptions = {
4747
* @see https://platform.openai.com/docs/guides/realtime#creating-an-ephemeral-token
4848
*/
4949
useInsecureApiKey?: boolean;
50+
/**
51+
* The URL to use for the WebSocket connection.
52+
*/
53+
url?: string;
5054
} & OpenAIRealtimeBaseOptions;
5155

5256
/**
@@ -59,7 +63,7 @@ export class OpenAIRealtimeWebSocket
5963
implements RealtimeTransportLayer
6064
{
6165
#apiKey: string | undefined;
62-
#url: string;
66+
#url: string | undefined;
6367
#state: WebSocketState = {
6468
status: 'disconnected',
6569
websocket: undefined,
@@ -80,7 +84,7 @@ export class OpenAIRealtimeWebSocket
8084

8185
constructor(options: OpenAIRealtimeWebSocketOptions = {}) {
8286
super(options);
83-
this.#url = `wss://api.openai.com/v1/realtime?model=${this.currentModel}`;
87+
this.#url = options.url;
8488
this.#useInsecureApiKey = options.useInsecureApiKey ?? false;
8589
}
8690

@@ -169,7 +173,7 @@ export class OpenAIRealtimeWebSocket
169173
},
170174
};
171175

172-
const ws = new WebSocket(this.#url, websocketArguments as any);
176+
const ws = new WebSocket(this.#url!, websocketArguments as any);
173177
this.#state = {
174178
status: 'connecting',
175179
websocket: ws,
@@ -260,9 +264,11 @@ export class OpenAIRealtimeWebSocket
260264
const model = options.model ?? this.currentModel;
261265
this.currentModel = model;
262266
this.#apiKey = await this._getApiKey(options);
263-
this.#url =
267+
const url =
264268
options.url ??
269+
this.#url ??
265270
`wss://api.openai.com/v1/realtime?model=${this.currentModel}`;
271+
this.#url = url;
266272

267273
const sessionConfig: Partial<RealtimeSessionConfig> = {
268274
...(options.initialSessionConfig || {}),

packages/agents-realtime/src/realtimeSession.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ export class RealtimeSession<
672672
await this.#transport.connect({
673673
apiKey: options.apiKey ?? this.options.apiKey,
674674
model: this.options.model,
675+
url: options.url,
675676
initialSessionConfig: await this.#getSessionConfig(this.options.config),
676677
});
677678

packages/agents-realtime/test/openaiRealtimeWebsocket.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ describe('OpenAIRealtimeWebSocket', () => {
5858
expect(statuses).toEqual(['connecting', 'connected']);
5959
});
6060

61+
it('uses custom url from constructor', async () => {
62+
const ws = new OpenAIRealtimeWebSocket({ url: 'ws://test' });
63+
const p = ws.connect({ apiKey: 'ek_test', model: 'm' });
64+
await vi.runAllTimersAsync();
65+
await p;
66+
expect(lastFakeSocket!.url).toBe('ws://test');
67+
});
68+
6169
it('handles audio delta, speech started and created/done events', async () => {
6270
const ws = new OpenAIRealtimeWebSocket();
6371
const audioSpy = vi.fn();

packages/agents-realtime/test/realtimeSession.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ describe('RealtimeSession', () => {
113113
expect(transport.closeCalls).toBe(1);
114114
});
115115

116+
it('forwards url in connect options to transport', async () => {
117+
const t = new FakeTransport();
118+
const agent = new RealtimeAgent({ name: 'A', handoffs: [] });
119+
const s = new RealtimeSession(agent, { transport: t });
120+
await s.connect({ apiKey: 'test', url: 'ws://example' });
121+
expect(t.connectCalls[0]?.url).toBe('ws://example');
122+
});
123+
116124
it('updateHistory accepts callback', () => {
117125
const item = createMessage('1', 'hi');
118126
session.updateHistory([item]);

0 commit comments

Comments
 (0)