Universal.Operative.Sdk.Realtime.OpenAI
1.0.0
dotnet add package Universal.Operative.Sdk.Realtime.OpenAI --version 1.0.0
NuGet\Install-Package Universal.Operative.Sdk.Realtime.OpenAI -Version 1.0.0
<PackageReference Include="Universal.Operative.Sdk.Realtime.OpenAI" Version="1.0.0" />
<PackageVersion Include="Universal.Operative.Sdk.Realtime.OpenAI" Version="1.0.0" />
<PackageReference Include="Universal.Operative.Sdk.Realtime.OpenAI" />
paket add Universal.Operative.Sdk.Realtime.OpenAI --version 1.0.0
#r "nuget: Universal.Operative.Sdk.Realtime.OpenAI, 1.0.0"
#:package Universal.Operative.Sdk.Realtime.OpenAI@1.0.0
#addin nuget:?package=Universal.Operative.Sdk.Realtime.OpenAI&version=1.0.0
#tool nuget:?package=Universal.Operative.Sdk.Realtime.OpenAI&version=1.0.0
About
Universal.Operative.Sdk.Realtime.OpenAI adapts the OpenAI Realtime API to Universal.Operative.Sdk.Realtime's provider-neutral IModel/IRealtimeSession/SessionEvent model. Ported from the Ong.Bot/Operative.Marin prototype.
Two connection paths in this release: Model.ConnectAsync (server-mediated WebSocket — audio relays through your process) and Model.ConnectForCallAsync (SIP passthrough — audio flows directly between the caller and OpenAI, never touching your process). Browser-direct WebRTC (an ephemeral-key handshake so a browser tab talks to OpenAI without your server in the audio path) isn't implemented yet.
How to Use
Installation
dotnet add package Universal.Operative.Sdk
dotnet add package Universal.Operative.Sdk.Realtime
dotnet add package Universal.Operative.Sdk.Realtime.OpenAI
Quick start
using Universal.Operative.Sdk.Realtime;
using Universal.Operative.Sdk.Realtime.OpenAI;
var model = new Model(apiKey, modelId: "gpt-realtime", defaultVoice: "marin");
IRealtimeSession session = await model.ConnectAsync(new RealtimeSessionOptions
{
SystemPrompt = [new TextBlock("You are a helpful voice assistant.")],
Tools = [myTool],
});
IOperative operative = OperativeBuilder.Create(session).AddTool(myTool).Build();
await foreach (SessionOutputEvent e in operative.RunAsync())
{
switch (e)
{
case SessionReadyEvent: Console.WriteLine("connected"); break;
case TranscriptDeltaEvent t: Console.WriteLine($"{t.Role}: {t.Text}"); break;
case AudioOutputDeltaEvent a: /* play a.Audio (24kHz PCM16) */ break;
case InterruptedEvent: /* stop playback immediately */ break;
}
}
await operative.SendAsync(new AppendAudioInputEvent { Audio = micChunk });
Fidelity notes
- Capabilities:
AudioInProcess | ToolCalling | Transcripts— audio flows through this same WebSocket, and there's no native session resumption (SessionCapabilities.NativeResumption/ClientAssistedResumptionare both unset). - Tool results: the full
ToolResultcontent (all blocks, not just text) is flattened into OpenAI's single-stringfunction_call_output— text blocks contribute their text verbatim, anything else is JSON-serialized rather than silently dropped. - Tool choice:
RealtimeSessionOptions.ToolChoiceis sent as OpenAI's owntool_choiceat connect time (same shape as Chat Completions/Responses — a bare string forauto/required/none, a structured object to force one specific tool). - Raw passthrough: OpenAI's Realtime API has substantially more event types than are mapped to canonical events here (item lifecycle events, rate-limit updates, built-in MCP tool events, text-modality deltas). Anything not explicitly mapped arrives as a
RawPassthroughEventrather than being dropped. - Mid-session reconfiguration: OpenAI's
session.update(changing instructions/voice/tools/tool-choice after connecting) has no canonicalSessionInputEventyet — unconfirmed whether Gemini or Nova Sonic support anything equivalent, so it isn't promoted. This adapter recognizesRawSendEventfor it two ways: pass a constructedSessionUpdateEvent(fromUniversal.OpenAI.Realtime.Client) asPayloadfor full control, or just setRawJsonto a{"type":"session.update",...}string — the adapter deserializes that one specific shape directly (no polymorphism involved, so this only recognizes that one allowlisted type; anything else needs the typedPayload). Any other unhandled input event still throwsNotSupportedException.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Universal.OpenAI.Client (>= 4.4.2)
- Universal.OpenAI.Realtime.Client (>= 1.0.3)
- Universal.Operative.Sdk (>= 5.0.0)
- Universal.Operative.Sdk.Realtime (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 41 | 8/12/2026 |
OpenAI Realtime adapter for Universal.Operative.Sdk.Realtime. Two connection paths: Model.ConnectAsync (server-mediated WebSocket) and Model.ConnectForCallAsync (SIP passthrough, audio flows directly between the caller and OpenAI). Browser-direct WebRTC isn't implemented. RealtimeSessionOptions.ToolChoice is sent as OpenAI's own tool_choice at connect time; RawSendEvent carries mid-session session.update (e.g. changing tool_choice).