Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
<add key="dotnet9-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9-transport/nuget/v3/index.json" />
<!-- Used for the Rich Navigation indexing task -->
<add key="richnav" value="https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-buildservices/nuget/v3/index.json" />
<!-- Used for pre-release OpenAI SDK packages; can be removed once a stable release is published -->
<add key="github-openai" value="https://nuget.pkg.github.com/openai/index.json" />
</packageSources>
<!-- Define mappings by adding package patterns beneath the target source.
https://aka.ms/nuget-package-source-mapping -->
Expand All @@ -39,6 +41,10 @@
<packageSource key="richnav">
<package pattern="*" />
</packageSource>
<packageSource key="github-openai">
<package pattern="OpenAI" />
<package pattern="OpenAI.Responses" />
</packageSource>
</packageSourceMapping>
<disabledPackageSources>
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
Expand Down
2 changes: 1 addition & 1 deletion eng/packages/General.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<PackageVersion Include="Microsoft.Extensions.VectorData.Abstractions" Version="$(MicrosoftExtensionsVectorDataAbstractionsVersion)" />
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="$(MicrosoftMLTokenizersVersion)" />
<PackageVersion Include="ModelContextProtocol.Core" Version="1.2.0" />
<PackageVersion Include="OpenAI" Version="2.10.0" />
<PackageVersion Include="OpenAI" Version="2.10.0-alpha.703" />
<PackageVersion Include="Polly" Version="8.4.2" />
<PackageVersion Include="Polly.Core" Version="8.4.2" />
<PackageVersion Include="Polly.Extensions" Version="8.4.2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
using System.Threading.Tasks;
using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
using OpenAI;
using OpenAI.Responses;

#pragma warning disable S1226 // Method parameters, caught exceptions and foreach variables' initial values should not be ignored
Expand Down Expand Up @@ -464,6 +463,7 @@ ChatResponseUpdate CreateUpdate(AIContent? content = null) =>

case FunctionCallResponseItem fcri:
anyFunctions = true;
lastMessageId = outputItemAddedUpdate.Item.Id;
lastRole = ChatRole.Assistant;
break;
}
Expand Down Expand Up @@ -735,7 +735,9 @@ private static bool IsStoredOutputDisabled(CreateResponseOptions? options, Respo
case HostedToolSearchTool:
// Workaround: The OpenAI .NET SDK doesn't yet expose a ToolSearchTool type.
// See https://github.com/openai/openai-dotnet/issues/1053
return ModelReaderWriter.Read<ResponseTool>(BinaryData.FromString("""{"type": "tool_search"}"""), ModelReaderWriterOptions.Json, OpenAIContext.Default)!;
#pragma warning disable OPENAI001 // OpenAIResponsesContext is experimental
return ModelReaderWriter.Read<ResponseTool>(BinaryData.FromString("""{"type": "tool_search"}"""), ModelReaderWriterOptions.Json, OpenAIResponsesContext.Default)!;
#pragma warning restore OPENAI001

case HostedWebSearchTool webSearchTool:
return new WebSearchTool
Expand Down Expand Up @@ -895,7 +897,9 @@ internal static ResponseTool ToNamespaceResponseTool(string name, string? descri
writer.WriteStartArray("tools"u8);
foreach (var namespacedTool in namespacedTools)
{
var toolData = ModelReaderWriter.Write(namespacedTool, ModelReaderWriterOptions.Json, OpenAIContext.Default);
#pragma warning disable OPENAI001 // OpenAIResponsesContext is experimental
var toolData = ModelReaderWriter.Write(namespacedTool, ModelReaderWriterOptions.Json, OpenAIResponsesContext.Default);
#pragma warning restore OPENAI001
using var doc = JsonDocument.Parse(toolData);
doc.RootElement.WriteTo(writer);
}
Expand All @@ -904,7 +908,9 @@ internal static ResponseTool ToNamespaceResponseTool(string name, string? descri
writer.WriteEndObject();
}

return ModelReaderWriter.Read<ResponseTool>(BinaryData.FromBytes(stream.ToArray()), ModelReaderWriterOptions.Json, OpenAIContext.Default)!;
#pragma warning disable OPENAI001 // OpenAIResponsesContext is experimental
return ModelReaderWriter.Read<ResponseTool>(BinaryData.FromBytes(stream.ToArray()), ModelReaderWriterOptions.Json, OpenAIResponsesContext.Default)!;
#pragma warning restore OPENAI001
}

/// <summary>Creates a <see cref="ChatRole"/> from a <see cref="MessageRole"/>.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5974,6 +5974,7 @@ public async Task StreamingResponseWithFunctionCallOutput_YieldsFunctionResultCo
var functionCallUpdate = updates.FirstOrDefault(u => u.Contents.OfType<FunctionCallContent>().Any());
Assert.NotNull(functionCallUpdate);
Assert.Equal(ChatRole.Assistant, functionCallUpdate.Role);
Assert.Equal("fc_001", functionCallUpdate.MessageId); // Verify MessageID is set for function calls (issue #7479)
var fcc = functionCallUpdate.Contents.OfType<FunctionCallContent>().Single();
Assert.Equal("call_123", fcc.CallId);
Assert.Equal("get_weather", fcc.Name);
Expand All @@ -5994,14 +5995,23 @@ public async Task StreamingResponseWithFunctionCallOutput_YieldsFunctionResultCo
var response = updates.ToChatResponse();
Assert.Equal("resp_001", response.ResponseId);
Assert.Equal("gpt-4o-mini", response.ModelId);
Assert.Single(response.Messages);
var message = response.Messages[0];
Assert.Equal(ChatRole.Assistant, message.Role);

// Message should contain: FunctionCallContent, FunctionResultContent, and TextContent
Assert.Single(message.Contents.OfType<FunctionCallContent>());
Assert.Single(message.Contents.OfType<FunctionResultContent>());
var textContent = Assert.Single(message.Contents.OfType<TextContent>());
// With the MessageID fix, function calls now have their own MessageId ("fc_001") and
// the text message has a different MessageId ("msg_001"), resulting in 2 separate messages.
Assert.Equal(2, response.Messages.Count);

// First message contains the function call and result items (MessageId="fc_001")
var functionMessage = response.Messages[0];
Assert.Equal(ChatRole.Assistant, functionMessage.Role);
Assert.Equal("fc_001", functionMessage.MessageId);
Assert.Single(functionMessage.Contents.OfType<FunctionCallContent>());
Assert.Single(functionMessage.Contents.OfType<FunctionResultContent>());

// Second message contains the text response (MessageId="msg_001")
var textMessage = response.Messages[1];
Assert.Equal(ChatRole.Assistant, textMessage.Role);
Assert.Equal("msg_001", textMessage.MessageId);
var textContent = Assert.Single(textMessage.Contents.OfType<TextContent>());
Assert.Equal("It's 25°C and sunny in Paris.", textContent.Text);

// Verify usage
Expand Down
Loading