Skip to content

Conversation

@m-nash
Copy link
Member

@m-nash m-nash commented Oct 28, 2025

Initial prototype to support Microsoft.Extensions.Configuration and Microsoft.Extensions.DependencyInjection

We don't intend to support both ClientConnection and ClientSettings we are exploring both and will choose one.

The example below shows using ApiKey credential for public openai client and azure cli credential for azure openai client. If you are using ApiKey credential for both the WithAzureCredential or GetAzureConnection is not necessary the code for public openai works for both.

OpenAIClient appsettings.json

  "OpenAIClient": {
    "Model": "gpt-5",
    "Credential": {
      "CredentialSource": "ApiKey"
    }
  }

AzureOpenAIClient-Cli appsettings.json

  "AzureOpenAIClient-Cli": {
    "Model": "gpt-4-1106-preview",
    "Endpoint": "https://my-openai-service.openai.azure.com/openai/v1/",
    "Credential": {
      "CredentialSource": "AzureCli"
    }
  }

Sample usage with configuration only using ClientConnection

        ConfigurationManager config = new();
        config.AddJsonFile("appsettings.json", optional: false);
        config.AddEnvironmentVariables();

        ClientConnection openAIConnection = config.GetConnection("OpenAIClient");
        ClientConnection azureOpenAIConnection = config.GetAzureConnection("AzureOpenAIClient-Cli");

        ChatClient openAIChatClient = openAIConnection.CreateChatClient();
        ChatClient azureOpenAIChatClient = azureOpenAIConnection.CreateChatClient();

        Console.WriteLine(openAIChatClient.CompleteChat("Hello world!").Value.Content[0].Text);
        Console.WriteLine(azureOpenAIChatClient.CompleteChat("Hello world!").Value.Content[0].Text);

Sample usage with configuration only using new ClientSettings

        ConfigurationManager config = new();
        config.AddJsonFile("appsettings.json", optional: false);
        config.AddEnvironmentVariables();

        OpenAISettings openAISettings = config.GetClientSettings<OpenAISettings>("OpenAIClient");
        OpenAISettings azureOpenAISettings = config.GetClientSettings<OpenAISettings>("AzureOpenAIClient-Cli")
            .WithAzureCredential();

        ChatClient openAIChatClient = new(openAISettings);
        ChatClient azureOpenAIChatClient = new(azureOpenAISettings);

        Console.WriteLine(openAIChatClient.CompleteChat("Hello world!").Value.Content[0].Text);
        Console.WriteLine(azureOpenAIChatClient.CompleteChat("Hello world!").Value.Content[0].Text);

Sample usage with dependency injection

        ServiceProvider provider = Host.CreateApplicationBuilder()
            .AddKeyedOpenAIChatClient("oai", "OpenAIClient")
            .AddKeyedOpenAIChatClient("aoai", "AzureOpenAIClient-Cli")
                .WithAzureCredential()
            .Services.BuildServiceProvider();

        ChatClient openAIChatClient = provider.GetRequiredKeyedService<ChatClient>("oai");
        ChatClient azureOpenAIChatClient = provider.GetRequiredKeyedService<ChatClient>("aoai");

        Console.WriteLine(openAIChatClient.CompleteChat("Hello world!").Value.Content[0].Text);
        Console.WriteLine(azureOpenAIChatClient.CompleteChat("Hello world!").Value.Content[0].Text);

@github-actions
Copy link

github-actions bot commented Oct 28, 2025

API Change Check

APIView identified API level changes in this PR and created the following API reviews

Azure.Core
Azure.Identity
Azure.ResourceManager
System.ClientModel

}
public static partial class ConfigurationManagerExtensions
{
public static System.ClientModel.Primitives.ClientConnection GetConnection(this Microsoft.Extensions.Configuration.IConfigurationManager configuration, string sectionName) { throw null; }
Copy link
Member

Choose a reason for hiding this comment

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

since these apis are in SCM, should these be just static Create methods on ClientConnection, or maybe even ClientConnection ctor? This way we don't need to add a new type (the config extensions)

/// <param name="configuration"></param>
/// <param name="sectionName"></param>
/// <returns></returns>
public static ClientConnection GetConnection(this IConfigurationManager configuration, string sectionName)
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we dont need an optional parameter called "format" (or something like that). This would allow us to add support for all the combinations in aspire. Unless we are fine with probing all the formats.

/// <summary>
/// .
/// </summary>
public string? CredentialSource { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

Should we name this CredentialKind or is CredentialSource already established somewhere else?

Copy link
Member Author

Choose a reason for hiding this comment

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

Its established in Aspire and we would like to reuse that name / enumeration if possible.

/// <summary>
/// .
/// </summary>
public IConfigurationSection? Properties { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

should we name this ConfigurationSection?

/// <summary>
/// .
/// </summary>
public CredentialSettings? Credential { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

should we name this CredentialSettings?

@m-nash
Copy link
Member Author

m-nash commented Dec 11, 2025

/azp run net - pullrequest

@azure-pipelines
Copy link

Azure Pipelines failed to run 1 pipeline(s).

@m-nash
Copy link
Member Author

m-nash commented Dec 11, 2025

@mokarchi This is the draft PR we are working on to work out how configuration / di can work with our non azure sdks that depend on System.ClientModel and branded sdks that depend on Azure.Core and use Azure.Identity for credentials.

Given you are working on the openai PR wanted to make you aware in case you have some comments / suggestions as well.

public static System.ClientModel.ContinuationToken FromBytes(System.BinaryData bytes) { throw null; }
public virtual System.BinaryData ToBytes() { throw null; }
}
public partial class CredentialSettings
Copy link
Member

Choose a reason for hiding this comment

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

@christothes, do we need to let people configure the tenentid?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, this should be possible.

protected virtual void Wait(System.TimeSpan time, System.Threading.CancellationToken cancellationToken) { }
protected virtual System.Threading.Tasks.Task WaitAsync(System.TimeSpan time, System.Threading.CancellationToken cancellationToken) { throw null; }
}
public abstract partial class ClientSettingsBase
Copy link
Member

Choose a reason for hiding this comment

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

why do we need this base class? Why si ClientSettings not enough?

I would really like to avoid it. If we cannot, we need to come up with a better name than simply suffixing it with "Base"

protected sealed override void ProcessCore(System.ClientModel.Primitives.PipelineMessage message) { }
protected sealed override System.Threading.Tasks.ValueTask ProcessCoreAsync(System.ClientModel.Primitives.PipelineMessage message) { throw null; }
}
public partial interface IClientBuilder : Microsoft.Extensions.Hosting.IHostApplicationBuilder
Copy link
Member

Choose a reason for hiding this comment

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

do we really need it?

@mokarchi
Copy link

@mokarchi This is the draft PR we are working on to work out how configuration / di can work with our non azure sdks that depend on System.ClientModel and branded sdks that depend on Azure.Core and use Azure.Identity for credentials.

Given you are working on the openai PR wanted to make you aware in case you have some comments / suggestions as well.

Thanks for the heads-up! @m-nash
looks like a solid implementation from what I can tell in the changes

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

Labels

Azure.Core Azure.Identity Mgmt This issue is related to a management package.

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

5 participants