diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIAssistantChatClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIAssistantChatClient.cs
index c3aab83da61..f3717f1ee41 100644
--- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIAssistantChatClient.cs
+++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIAssistantChatClient.cs
@@ -44,6 +44,9 @@ internal sealed partial class OpenAIAssistantChatClient : IChatClient
/// The thread ID to use if none is supplied in .
private readonly string? _defaultThreadId;
+ /// List of tools associated with the assistant.
+ private IReadOnlyList? _assistantTools;
+
/// Initializes a new instance of the class for the specified .
public OpenAIAssistantChatClient(AssistantClient assistantClient, string assistantId, string? defaultThreadId)
{
@@ -83,7 +86,7 @@ public async IAsyncEnumerable GetStreamingResponseAsync(
_ = Throw.IfNull(messages);
// Extract necessary state from messages and options.
- (RunCreationOptions runOptions, List? toolResults) = CreateRunOptions(messages, options);
+ (RunCreationOptions runOptions, List? toolResults) = await CreateRunOptionsAsync(messages, options, cancellationToken).ConfigureAwait(false);
// Get the thread ID.
string? threadId = options?.ConversationId ?? _defaultThreadId;
@@ -238,8 +241,8 @@ void IDisposable.Dispose()
/// Creates the to use for the request and extracts any function result contents
/// that need to be submitted as tool results.
///
- private (RunCreationOptions RunOptions, List? ToolResults) CreateRunOptions(
- IEnumerable messages, ChatOptions? options)
+ private async ValueTask<(RunCreationOptions RunOptions, List? ToolResults)> CreateRunOptionsAsync(
+ IEnumerable messages, ChatOptions? options, CancellationToken cancellationToken)
{
// Create the options instance to populate, either a fresh or using one the caller provides.
RunCreationOptions runOptions =
@@ -257,6 +260,24 @@ void IDisposable.Dispose()
if (options.Tools is { Count: > 0 } tools)
{
+ // If the caller has provided any tool overrides, we'll assume they don't want to use the assistant's tools.
+ // But if they haven't, the only way we can provide our tools is via an override, whereas we'd really like to
+ // just add them. To handle that, we'll get all of the assistant's tools and add them to the override list
+ // along with our tools.
+ if (runOptions.ToolsOverride.Count == 0)
+ {
+ if (_assistantTools is null)
+ {
+ var assistant = await _client.GetAssistantAsync(_assistantId, cancellationToken).ConfigureAwait(false);
+ _assistantTools = assistant.Value.Tools;
+ }
+
+ foreach (var tool in _assistantTools)
+ {
+ runOptions.ToolsOverride.Add(tool);
+ }
+ }
+
// The caller can provide tools in the supplied ThreadAndRunOptions. Augment it with any supplied via ChatOptions.Tools.
foreach (AITool tool in tools)
{
@@ -290,7 +311,6 @@ void IDisposable.Dispose()
runOptions.ToolConstraint = ToolConstraint.None;
break;
- case null:
case AutoChatToolMode:
runOptions.ToolConstraint = ToolConstraint.Auto;
break;