- Fully generated C# SDK based on official OpenAI OpenAPI specification using AutoSDK
- Same day update to support new features
- Updated and supported automatically if there are no breaking changes
- Contains a supported list of constants such as current prices, models, and other
- Source generator to define functions natively through C# interfaces
- All modern .NET features - nullability, trimming, NativeAOT, etc.
- Support .Net Framework/.Net Standard 2.0
- Support all OpenAI API endpoints including completions, chat, embeddings, images, assistants and more.
- Regularly tested for compatibility with popular custom providers like OpenRouter/DeepSeek/Ollama/LM Studio and many others
Examples and documentation can be found here: https://tryagi.github.io/OpenAI/
using var api = new OpenAiApi("API_KEY");
string response = await api.Chat.CreateChatCompletionAsync(
messages: ["Generate five random words."],
model: CreateChatCompletionRequestModel.Gpt4oMini);
Console.WriteLine(response); // "apple, banana, cherry, date, elderberry"
var enumerable = api.Chat.CreateChatCompletionAsStreamAsync(
messages: ["Generate five random words."],
model: CreateChatCompletionRequestModel.Gpt4oMini);
await foreach (string response in enumerable)
{
Console.WriteLine(response);
}
It uses three implicit conversions:
- from
string
toChatCompletionRequestUserMessage
. It will always be converted to the user message. - from
ChatCompletionResponseMessage
tostring
. It will always contain the first choice message content. - from
CreateChatCompletionStreamResponse
tostring
. It will always contain the first delta content.
You still can use the full response objects if you need more information, just replace string response
to var response
.
using OpenAI;
using CSharpToJsonSchema;
public enum Unit
{
Celsius,
Fahrenheit,
}
public class Weather
{
public string Location { get; set; } = string.Empty;
public double Temperature { get; set; }
public Unit Unit { get; set; }
public string Description { get; set; } = string.Empty;
}
[GenerateJsonSchema(Strict = true)] // false by default. You can't use parameters with default values in Strict mode.
public interface IWeatherFunctions
{
[Description("Get the current weather in a given location")]
public Task<Weather> GetCurrentWeatherAsync(
[Description("The city and state, e.g. San Francisco, CA")] string location,
Unit unit,
CancellationToken cancellationToken = default);
}
public class WeatherService : IWeatherFunctions
{
public Task<Weather> GetCurrentWeatherAsync(string location, Unit unit = Unit.Celsius, CancellationToken cancellationToken = default)
{
return Task.FromResult(new Weather
{
Location = location,
Temperature = 22.0,
Unit = unit,
Description = "Sunny",
});
}
}
using var api = new OpenAiApi("API_KEY");
var service = new WeatherService();
var tools = service.AsTools().AsOpenAiTools();
var messages = new List<ChatCompletionRequestMessage>
{
"You are a helpful weather assistant.".AsSystemMessage(),
"What is the current temperature in Dubai, UAE in Celsius?".AsUserMessage(),
};
var model = CreateChatCompletionRequestModel.Gpt4oMini;
var result = await api.Chat.CreateChatCompletionAsync(
messages,
model: model,
tools: tools);
var resultMessage = result.Choices.First().Message;
messages.Add(resultMessage.AsRequestMessage());
foreach (var call in resultMessage.ToolCalls)
{
var json = await service.CallAsync(
functionName: call.Function.Name,
argumentsAsJson: call.Function.Arguments);
messages.Add(json.AsToolMessage(call.Id));
}
var result = await api.Chat.CreateChatCompletionAsync(
messages,
model: model,
tools: tools);
var resultMessage = result.Choices.First().Message;
messages.Add(resultMessage.AsRequestMessage());
> System:
You are a helpful weather assistant.
> User:
What is the current temperature in Dubai, UAE in Celsius?
> Assistant:
call_3sptsiHzKnaxF8bs8BWxPo0B:
GetCurrentWeather({"location":"Dubai, UAE","unit":"celsius"})
> Tool(call_3sptsiHzKnaxF8bs8BWxPo0B):
{"location":"Dubai, UAE","temperature":22,"unit":"celsius","description":"Sunny"}
> Assistant:
The current temperature in Dubai, UAE is 22°C with sunny weather.
using OpenAI;
using var api = new OpenAiApi("API_KEY");
var response = await api.Chat.CreateChatCompletionAsAsync<Weather>(
messages: ["Generate random weather."],
model: CreateChatCompletionRequestModel.Gpt4oMini,
jsonSerializerOptions: new JsonSerializerOptions
{
Converters = {new JsonStringEnumConverter()},
});
// or (if you need trimmable/NativeAOT version)
var response = await api.Chat.CreateChatCompletionAsAsync(
jsonTypeInfo: SourceGeneratedContext.Default.Weather,
messages: ["Generate random weather."],
model: CreateChatCompletionRequestModel.Gpt4oMini);
// response.Value1 contains the structured output
// response.Value2 contains the CreateChatCompletionResponse object
Weather:
Location: San Francisco, CA
Temperature: 65
Unit: Fahrenheit
Description: Partly cloudy with a light breeze and occasional sunshine.
Raw Response:
{"Location":"San Francisco, CA","Temperature":65,"Unit":"Fahrenheit","Description":"Partly cloudy with a light breeze and occasional sunshine."}
Additional code for trimmable/NativeAOT version:
[JsonSourceGenerationOptions(Converters = [typeof(JsonStringEnumConverter<Unit>)])]
[JsonSerializable(typeof(Weather))]
public partial class SourceGeneratedContext : JsonSerializerContext;
using OpenAI;
using var api = CustomProviders.GitHubModels("GITHUB_TOKEN");
using var api = CustomProviders.Azure("API_KEY", "ENDPOINT");
using var api = CustomProviders.DeepInfra("API_KEY");
using var api = CustomProviders.Groq("API_KEY");
using var api = CustomProviders.XAi("API_KEY");
using var api = CustomProviders.DeepSeek("API_KEY");
using var api = CustomProviders.Fireworks("API_KEY");
using var api = CustomProviders.OpenRouter("API_KEY");
using var api = CustomProviders.Together("API_KEY");
using var api = CustomProviders.Perplexity("API_KEY");
using var api = CustomProviders.SambaNova("API_KEY");
using var api = CustomProviders.Mistral("API_KEY");
using var api = CustomProviders.Codestral("API_KEY");
using var api = CustomProviders.Cerebras("API_KEY");
using var api = CustomProviders.Ollama();
using var api = CustomProviders.LmStudio();
All tryGetXXX
methods return null
if the value is not found.
There also non-try methods that throw an exception if the value is not found.
using OpenAI;
// You can try to get the enum from string using:
var model = CreateChatCompletionRequestModelExtensions.ToEnum("gpt-4o") ?? throw new Exception("Invalid model");
// Chat
var model = CreateChatCompletionRequestModel.Gpt4oMini;
double? priceInUsd = model.TryGetPriceInUsd(
inputTokens: 500,
outputTokens: 500)
double? priceInUsd = model.TryGetFineTunePriceInUsd(
trainingTokens: 500,
inputTokens: 500,
outputTokens: 500)
int contextLength = model.TryGetContextLength() // 128_000
int outputLength = model.TryGetOutputLength() // 16_000
// Embeddings
var model = CreateEmbeddingRequestModel.TextEmbedding3Small;
int? maxInputTokens = model.TryGetMaxInputTokens() // 8191
double? priceInUsd = model.TryGetPriceInUsd(tokens: 500)
// Images
double? priceInUsd = CreateImageRequestModel.DallE3.TryGetPriceInUsd(
size: CreateImageRequestSize.x1024x1024,
quality: CreateImageRequestQuality.Hd)
// Speech to Text
double? priceInUsd = CreateTranscriptionRequestModel.Whisper1.TryGetPriceInUsd(
seconds: 60)
// Text to Speech
double? priceInUsd = CreateSpeechRequestModel.Tts1Hd.TryGetPriceInUsd(
characters: 1000)
Priority place for bugs: https://github.com/tryAGI/OpenAI/issues
Priority place for ideas and general questions: https://github.com/tryAGI/OpenAI/discussions
Discord: https://discord.gg/Ca2xhfBf3v
This project is supported by JetBrains through the Open Source Support Program.
This project is supported by CodeRabbit through the Open Source Support Program.