Skip to content

Conversation

mokarchi
Copy link

@mokarchi mokarchi commented Sep 18, 2025

This PR implements enhanced dependency injection support for the OpenAI .NET library, addressing the feature request for built-in extension methods for IServiceCollection. The implementation follows .NET ecosystem standards similar to Azure SDKs, making it easier to integrate OpenAI clients into ASP.NET Core, Blazor, and other .NET applications.

Key Features Added

Extension Methods for IServiceCollection

The library now provides convenient extension methods for registering OpenAI clients:

using OpenAI.Extensions.DependencyInjection;

// Register individual clients with API key
builder.Services.AddOpenAIChat("gpt-4o", "your-api-key");
builder.Services.AddOpenAIEmbeddings("text-embedding-3-small");

// Register the main OpenAI client factory
builder.Services.AddOpenAI("your-api-key");
builder.Services.AddOpenAIChat("gpt-4o"); // Uses the registered OpenAIClient

Configuration Integration

Full support for IConfiguration binding with appsettings.json:

{
  "OpenAI": {
    "ApiKey": "your-api-key",
    "DefaultChatModel": "gpt-4o",
    "DefaultEmbeddingModel": "text-embedding-3-small",
    "Endpoint": "https://api.openai.com/v1",
    "OrganizationId": "your-org-id"
  }
}
// Register services from configuration
builder.Services.AddOpenAIFromConfiguration(builder.Configuration);

// Add specific clients using default models from configuration
builder.Services.AddChatClientFromConfiguration();
builder.Services.AddEmbeddingClientFromConfiguration();

// Or add all common clients at once
builder.Services.AddAllOpenAIClientsFromConfiguration();

Environment Variable Support

Automatic fallback to the OPENAI_API_KEY environment variable for development scenarios:

// This will use the OPENAI_API_KEY environment variable if no API key is provided
builder.Services.AddOpenAIChat("gpt-4o");

Implementation Details

Available Extension Methods

  • Core Registration: AddOpenAI(), AddOpenAIChat(), AddOpenAIEmbeddings(), AddOpenAIAudio(), AddOpenAIImages(), AddOpenAIModeration()
  • Configuration-Based: AddOpenAIFromConfiguration(), AddChatClientFromConfiguration(), etc.
  • Bulk Registration: AddAllOpenAIClientsFromConfiguration()

Enhanced Configuration Options

The new OpenAIServiceOptions class extends OpenAIClientOptions with DI-specific settings:

  • Default model configurations for each client type
  • API key configuration with environment variable fallback
  • All existing OpenAIClientOptions properties (Endpoint, OrganizationId, ProjectId, etc.)

Thread-Safe Singleton Registration

All clients are registered as singletons by default, following the existing recommendation in the README. This maximizes resource efficiency and HTTP connection reuse while maintaining thread safety.

Backward Compatibility

This implementation is fully backward compatible. Existing manual registration patterns continue to work unchanged:

// Existing manual registration still works
builder.Services.AddSingleton<ChatClient>(serviceProvider =>
{
    var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
    return new ChatClient("gpt-4o", apiKey);
});

This commit introduces new features for dependency injection in the OpenAI .NET library, allowing for easier registration and configuration of clients within ASP.NET Core applications. Key changes include:

- New extension methods for registering OpenAI clients with support for `appsettings.json` and environment variables.
- Introduction of the `OpenAIServiceOptions` class for simplified configuration.
- Updates to README.md with detailed usage instructions and examples.
- Modifications to project files to include necessary package references.
- Comprehensive unit tests to validate the new features and ensure proper functionality.
@stephentoub
Copy link
Contributor

Should this instead be left to Aspire, e.g. https://www.nuget.org/packages/Aspire.OpenAI ?

cc: @eerhardt

@KrzysztofCwalina
Copy link
Collaborator

I also think configuration like this needs to be aligned with what we already have in both Aspire, .NET, and Azure. In fact, I had a sync up with @eerhardt a couple of days ago to design a consistent solution.

cc @m-nash

@mokarchi
Copy link
Author

@stephentoub @KrzysztofCwalina, I was wondering about the current status of this PR. Should I wait or make any changes?

@KrzysztofCwalina
Copy link
Collaborator

@stephentoub @KrzysztofCwalina, I was wondering about the current status of this PR. Should I wait or make any changes?

@m-nash @eerhardt, @jsquire, how would you want to handle this PR? It seems like you are working features similar to it.

@mokarchi
Copy link
Author

mokarchi commented Oct 1, 2025

@eerhardt Could you review this, please?

@jsquire
Copy link
Collaborator

jsquire commented Oct 1, 2025

Hi @mokarchi. Thank you for your contribution and your interest in improving the OpenAI developer experience. Apologies for the feedback delay, but there was some coordination needed on other workstreams. As Krzysztof mentioned, we are in the process of designing an experience where clients natively integrate with the .NET configuration, options, and DI systems. Part of that work entails defining the common patterns across the OpenAI clients for DI registration, construction, and configuration and ensuring that they align closely with the .NET ecosystem.

Because we don't yet have a fully codified design, we're not able to provide the detailed feedback that would be needed to help your contribution align. As a result, we're unable to move forward at this time. We have a couple of options that you can consider for next steps:

  • We can close this PR out and leave the implementation to the team once a design is settled.
  • We can close this PR out and coordinate on a new implementation together once the design is settled.
  • We can park this PR for now and then work together to align the implementation to the design once it is available.

Please let us know how you'd like to proceed.

//cc: @m-nash for awareness.

Copy link
Collaborator

@jsquire jsquire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking for now to prevent accidental merge.

@mokarchi
Copy link
Author

mokarchi commented Oct 1, 2025

Thank you for the update, @jsquire.
I'd like to go with the third option: parking this PR for now and working together to align the implementation once the design is available. I'm happy to iterate on this contribution to ensure it fits seamlessly with the broader patterns you're defining.

@jsquire
Copy link
Collaborator

jsquire commented Oct 1, 2025

Thank you, @mokarchi. We appreciate your flexibility and understanding.

@jsquire jsquire requested a review from m-nash October 1, 2025 20:21
@m-nash
Copy link
Collaborator

m-nash commented Oct 1, 2025

Thank you for the update, @jsquire. I'd like to go with the third option: parking this PR for now and working together to align the implementation once the design is available. I'm happy to iterate on this contribution to ensure it fits seamlessly with the broader patterns you're defining.

Late to the party, but yeah this feels like the best path forward. Once the design is ready to share we can collaborate on the implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants