If you've ever tried integrating Azure OpenAI's Realtime API into a .NET application, you've likely hit a frustrating wall: your beautifully crafted AIFunctions suddenly feel useless. The Realtime API demands raw JSON schemas for tools, and most examples out there force you to manually duplicate function definitions, stripping away the elegance of strongly typed C# models.
I ran into this exact pain point. So I built openai-realtime-sample, a comprehensive repo that shows how to reuse your existing AIFunctions as Realtime tools without rewriting a single line of JSON.
🚨 The Problem
.NET developers using Microsoft.Extensions.AI
often define their functions using AIFunctionFactory.Create(...)
, complete with [Description]
attributes and enums. This works beautifully for regular chat completions.
But when switching to the Realtime API, you're expected to:
- Manually define JSON schemas for each tool
- Duplicate function shapes and descriptions
- Lose the benefits of strong typing and metadata
This leads to brittle code and a lot of unnecessary duplication.
✅ The Solution
My repo shows how to elegantly convert AIFunctions into ConversationFunctionTool
objects, making them compatible with the Realtime API. Here's the magic:
public static ConversationFunctionTool ConversationTool(this AIFunction function) =>
new(function.Name)
{
Description = function.Description,
Parameters = BinaryData.FromString(function.JsonSchema.ToString())
};
This extension method (found in AIExtensions.cs
) lets you do:
var tools = GetTools(); // AIFunction[]
var conversationTools = tools.Select(t => t.ConversationTool());
sessionOptions.Tools.AddRange(conversationTools);
And when a tool is invoked:
var tool = tools.First(t => t.Name == functionName);
var result = await tool.InvokeAsync(parsedArgs);
await session.AddItemAsync(RealtimeItem.CreateFunctionCallOutput(callId, result?.ToString() ?? ""));
🧪 Two Sample Projects
RealtimeSample.Console
A minimal, linear example with a single weather function. Perfect for copying into your own app.RealtimeSample.BlazorHybrid (.NET MAUI)
A richer, event-driven UI that visualizes RealtimeUpdate events like session start, speech input, delta streaming, and tool invocation.
💡 Key Takeaways
- No manual JSON duplication, just reuse your AIFunctions
- Enums and descriptions flow automatically into the tool schema
-
Respond to tool calls with
FunctionCallOutput
referencing the originalfunction_call_id
-
Trigger a new model turn with
StartResponseAsync
after supplying tool outputs
🛠 Requirements
- .NET 9
- Azure OpenAI Realtime deployment (via environment variables)
🔁 Extend It
Want to add more tools? Just return them from GetTools()
, your enums and descriptions will be automatically included.
This repo bridges the gap between high-level .NET abstractions and the low-level Realtime API protocol. Whether you're building a console app or a hybrid UI, this pattern gives you a clean, reusable way to integrate OpenAI tools without sacrificing type safety or maintainability.
Check out the full repo on GitHub and feel free to adapt the extension method into your own shared library.
Top comments (0)