Skip to content

Commit f0fb6f7

Browse files
committed
fix ProjectResponsesClient endpoint bug
1 parent 0c625c4 commit f0fb6f7

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

sdk/ai/Azure.AI.Projects.OpenAI/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Release History
22

3+
## 1.0.0-beta.2 (Unreleased)
4+
5+
### Bugs fixed
6+
7+
- Addressed a problem where not supplying an options instance to the `ProjectResponsesClient` constructor resulted in fallback to the `https://api.openai.com/v1` endpoint
8+
39
## 1.0.0-beta.1 (2025-11-14)
410

511
This is the first release of the `Azure.AI.Projects.OpenAI` library, a new extension package for the official `OpenAI` .NET library that facilitates and simplifies use of Microsoft Foundry extensions to OpenAI APIs.

sdk/ai/Azure.AI.Projects.OpenAI/src/Custom/OpenAI/ProjectOpenAIClient.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public ProjectOpenAIClient(AuthenticationPolicy authenticationPolicy, ProjectOpe
4949
{
5050
Argument.AssertNotNull(authenticationPolicy, nameof(authenticationPolicy));
5151
Argument.AssertNotNull(options, nameof(options));
52-
Argument.AssertNotNull(options.Endpoint, nameof(options.Endpoint));
52+
Argument.AssertNotNull(options.Endpoint, $"{nameof(options)}.{nameof(options.Endpoint)}");
5353

5454
_options = options;
5555
}
@@ -157,6 +157,7 @@ internal static ProjectOpenAIClientOptions GetMergedOptions(Uri projectEndpoint,
157157
throw new InvalidOperationException(
158158
$"Cannot supply both a constructor '{nameof(projectEndpoint)}' and {nameof(options)}.{nameof(options.Endpoint)}.");
159159
}
160+
options ??= new();
160161
options?.Endpoint ??= new Uri(rawTargetOpenAIEndpoint);
161162
return options;
162163
}

sdk/ai/Azure.AI.Projects.OpenAI/tests/ResponsesSmokeTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33

44
using System;
5+
using System.ClientModel;
56
using System.ClientModel.Primitives;
67
using System.Linq;
78
using Microsoft.ClientModel.TestFramework;
@@ -166,4 +167,43 @@ public void TestResponseCreationOptionsExtensions()
166167
Assert.That(options.StructuredInputs.Keys, Has.Count.EqualTo(2));
167168
Assert.That(options.StructuredInputs["direct_value_2"].ToString(), Is.EqualTo("42"));
168169
}
170+
171+
[Test]
172+
public void ResponsesEndpointsSetCorrectly()
173+
{
174+
Uri mockProjectEndpoint = new("https://microsoft.com/mock/endpoint");
175+
Uri mockOpenAIEndpoint = new($"{mockProjectEndpoint.AbsoluteUri}/openai");
176+
AuthenticationTokenProvider mockCredential = new MockCredential();
177+
AuthenticationPolicy mockAuthPolicy = new BearerTokenPolicy(mockCredential, "https://ai.azure.com/.default");
178+
179+
ProjectOpenAIClientOptions GetOptions(Uri endpoint = null) => new() { Endpoint = endpoint };
180+
181+
// Not specifying options should use the constructed /openai endpoint from the project Uri
182+
ProjectOpenAIClient client = new(mockProjectEndpoint, new MockCredential());
183+
Assert.That(client.Endpoint?.AbsoluteUri, Is.EqualTo(mockOpenAIEndpoint));
184+
client = new(new Uri(mockProjectEndpoint.AbsoluteUri + "/"), mockCredential);
185+
Assert.That(client.Endpoint?.AbsoluteUri, Is.EqualTo(mockOpenAIEndpoint));
186+
187+
// Providing no endpoint anywhere should throw
188+
Assert.Throws<ArgumentNullException>(() => client = new(mockAuthPolicy, GetOptions()));
189+
190+
// Supplying in options should use the literal value with no construction
191+
client = new(mockAuthPolicy, GetOptions(mockProjectEndpoint));
192+
Assert.That(client.Endpoint?.AbsoluteUri, Is.EqualTo(mockProjectEndpoint.AbsoluteUri));
193+
194+
// Supplying in both should be OK if they match correctly
195+
client = new(mockProjectEndpoint, mockCredential, GetOptions(mockOpenAIEndpoint));
196+
Assert.That(client.Endpoint?.AbsoluteUri, Is.EqualTo(mockOpenAIEndpoint));
197+
198+
// Supplying in both should throw if they don't match
199+
Assert.Throws<InvalidOperationException>(() => client = new(mockProjectEndpoint, mockCredential, GetOptions(mockProjectEndpoint)));
200+
201+
// Clients retrieved from ProjectOpenAIClient should handle construction
202+
ProjectOpenAIClient openAIClient = new(mockProjectEndpoint, mockCredential);
203+
Assert.That(openAIClient.Responses.Endpoint, Is.EqualTo(mockOpenAIEndpoint));
204+
Assert.That(openAIClient.GetOpenAIResponseClient("model").Endpoint, Is.EqualTo(mockOpenAIEndpoint));
205+
Assert.That(openAIClient.GetProjectResponsesClient().Endpoint, Is.EqualTo(mockOpenAIEndpoint));
206+
Assert.That(openAIClient.GetProjectResponsesClientForModel("model").Endpoint, Is.EqualTo(mockOpenAIEndpoint));
207+
Assert.That(openAIClient.GetProjectResponsesClientForAgent(new AgentReference("agent")).Endpoint, Is.EqualTo(mockOpenAIEndpoint));
208+
}
169209
}

0 commit comments

Comments
 (0)