Skip to content

Commit d2b4e05

Browse files
committed
feat(openai): restore realtime subprotocol auth templates
1 parent 41d736f commit d2b4e05

5 files changed

Lines changed: 74 additions & 11 deletions

File tree

src/libs/tryAGI.OpenAI/Generated/tryAGI.OpenAI.Realtime.OpenAiRealtimeClient.g.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ private void ApplyStoredAuthorization(
105105
if (_subprotocolAuthorizationValues.ContainsKey("apiKey"))
106106
{
107107
var __apiKey = _subprotocolAuthorizationValues["apiKey"];
108-
var __subProtocol = "openai-insecure-api-key.{apiKey}";
108+
var __subProtocol = "realtime";
109+
__subProtocol = __subProtocol.Replace("{apiKey}", __apiKey);
110+
_clientWebSocket.Options.AddSubProtocol(__subProtocol);
111+
__subProtocol = "openai-insecure-api-key.{apiKey}";
109112
__subProtocol = __subProtocol.Replace("{apiKey}", __apiKey);
110113
_clientWebSocket.Options.AddSubProtocol(__subProtocol);
111114
return;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Net.WebSockets;
2+
3+
namespace tryAGI.OpenAI.Realtime;
4+
5+
public sealed partial class OpenAiRealtimeClient
6+
{
7+
partial void Initialized(ClientWebSocket client)
8+
{
9+
client.Options.SetRequestHeader("OpenAI-Beta", "realtime=v1");
10+
}
11+
}

src/libs/tryAGI.OpenAI/asyncapi.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,9 @@
370370
},
371371
"subprotocol": {
372372
"type": "apiKey",
373-
"description": "Browser-compatible auth via WebSocket subprotocols. When ConnectAsync is called with useSubprotocolAuth: true, the client advertises `openai-insecure-api-key.<apiKey>`, avoiding the need to set an Authorization header (which browsers disallow on the JS WebSocket constructor).\n\nOpenAI also expects the `realtime` subprotocol on the connection; include it via the `additionalSubProtocols` parameter on ConnectAsync.\n\nNOTE: single template until tryAGI/AutoSDK codegen bug (duplicate __subProtocol locals with >1 template) is fixed.",
373+
"description": "Browser-compatible auth via WebSocket subprotocols. When ConnectAsync is called with useSubprotocolAuth: true, the client advertises the `realtime` subprotocol plus `openai-insecure-api-key.<apiKey>`, avoiding the need to set an Authorization header (which browsers disallow on the JS WebSocket constructor).",
374374
"x-subprotocol-auth": [
375+
"realtime",
375376
"openai-insecure-api-key.{apiKey}"
376377
]
377378
}

src/libs/tryAGI.OpenAI/build-asyncapi.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -187,17 +187,13 @@ def main() -> int:
187187
"description": (
188188
"Browser-compatible auth via WebSocket subprotocols. "
189189
"When ConnectAsync is called with useSubprotocolAuth: true, "
190-
"the client advertises `openai-insecure-api-key.<apiKey>`, "
191-
"avoiding the need to set an Authorization header (which "
192-
"browsers disallow on the JS WebSocket constructor).\n\n"
193-
"OpenAI also expects the `realtime` subprotocol on the "
194-
"connection; include it via the `additionalSubProtocols` "
195-
"parameter on ConnectAsync.\n\n"
196-
"NOTE: single template until tryAGI/AutoSDK codegen bug "
197-
"(duplicate __subProtocol locals with >1 template) is "
198-
"fixed."
190+
"the client advertises the `realtime` subprotocol plus "
191+
"`openai-insecure-api-key.<apiKey>`, avoiding the need "
192+
"to set an Authorization header (which browsers disallow "
193+
"on the JS WebSocket constructor)."
199194
),
200195
"x-subprotocol-auth": [
196+
"realtime",
201197
"openai-insecure-api-key.{apiKey}",
202198
],
203199
},
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
order: 75
3+
title: Realtime
4+
slug: realtime
5+
6+
Connect to the Realtime API with the generated WebSocket client and wait for the initial session event.
7+
*/
8+
9+
using tryAGI.OpenAI.Realtime;
10+
11+
namespace tryAGI.OpenAI.IntegrationTests;
12+
13+
public partial class Tests
14+
{
15+
[TestMethod]
16+
public async Task Example_Realtime()
17+
{
18+
var apiKey =
19+
Environment.GetEnvironmentVariable("OPENAI_API_KEY") is { Length: > 0 } apiKeyValue
20+
? apiKeyValue
21+
: throw new AssertInconclusiveException("OPENAI_API_KEY environment variable is not found.");
22+
var model =
23+
Environment.GetEnvironmentVariable("OPENAI_REALTIME_MODEL") is { Length: > 0 } modelValue
24+
? modelValue
25+
: "gpt-4o-realtime-preview";
26+
27+
using var client = new OpenAiRealtimeClient(apiKey);
28+
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
29+
var cancellationToken = cancellationTokenSource.Token;
30+
31+
await client.ConnectAsync(model: model, cancellationToken: cancellationToken);
32+
client.IsConnected.Should().BeTrue();
33+
34+
await foreach (var serverEvent in client.ReceiveUpdatesAsync(cancellationToken))
35+
{
36+
if (serverEvent.IsSessionCreated)
37+
{
38+
serverEvent.SessionCreated.Should().NotBeNull();
39+
Console.WriteLine(serverEvent.SessionCreated!.EventId);
40+
return;
41+
}
42+
43+
if (serverEvent.IsError)
44+
{
45+
throw new AssertFailedException(
46+
$"Realtime connection returned an error: {serverEvent.Error!.Error.Message}");
47+
}
48+
}
49+
50+
throw new AssertFailedException("Realtime connection did not produce a session.created event before timing out.");
51+
}
52+
}

0 commit comments

Comments
 (0)