Skip to content

Commit bd481dd

Browse files
committed
fix: align Azure AI Inference routing guidance
1 parent 1afa5f8 commit bd481dd

4 files changed

Lines changed: 46 additions & 3 deletions

File tree

packages/types/src/providers/openai.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,17 +706,32 @@ export const OPENAI_NATIVE_DEFAULT_TEMPERATURE = 0
706706

707707
export const OPENAI_AZURE_AI_INFERENCE_PATH = "/models/chat/completions"
708708

709+
/**
710+
* Returns true when the base URL belongs to Azure AI Inference.
711+
* These endpoints use the regular OpenAI client and expect a model identifier,
712+
* even when the Azure compatibility flag is enabled.
713+
*/
714+
export function isAzureAiInferenceBaseUrl(baseUrl?: string): boolean {
715+
try {
716+
const host = new URL(baseUrl ?? "").host
717+
return host.endsWith(".services.ai.azure.com")
718+
} catch {
719+
return false
720+
}
721+
}
722+
709723
/**
710724
* Returns true when the base URL and/or flag indicate an Azure OpenAI endpoint.
711725
* Azure AI Inference endpoints (*.services.ai.azure.com) return false — the
712726
* backend routes those through the plain OpenAI client, not AzureOpenAI.
713727
*/
714728
export function isAzureOpenAiBaseUrl(baseUrl?: string, useAzure?: boolean): boolean {
729+
if (isAzureAiInferenceBaseUrl(baseUrl)) return false
715730
if (useAzure) return true
716731

717732
try {
718733
const host = new URL(baseUrl ?? "").host
719-
return (host === "azure.com" || host.endsWith(".azure.com")) && !host.endsWith(".services.ai.azure.com")
734+
return host === "azure.com" || host.endsWith(".azure.com")
720735
} catch {
721736
return false
722737
}

src/api/providers/__tests__/openai.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,16 @@ describe("OpenAiHandler", () => {
897897
expect(azureHandler.getModel().id).toBe(azureOptions.openAiModelId)
898898
})
899899

900+
it("should keep Azure AI Inference precedence when Azure mode is enabled", () => {
901+
vi.mocked(OpenAI).mockClear()
902+
vi.mocked(AzureOpenAI).mockClear()
903+
904+
new OpenAiHandler({ ...azureOptions, openAiUseAzure: true })
905+
906+
expect(vi.mocked(OpenAI)).toHaveBeenCalled()
907+
expect(vi.mocked(AzureOpenAI)).not.toHaveBeenCalled()
908+
})
909+
900910
it("should handle streaming responses with Azure AI Inference Service", async () => {
901911
const azureHandler = new OpenAiHandler(azureOptions)
902912
const systemPrompt = "You are a helpful assistant."

src/api/providers/openai.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import axios from "axios"
55
import {
66
type ModelInfo,
77
azureOpenAiDefaultApiVersion,
8+
isAzureAiInferenceBaseUrl,
89
isAzureOpenAiBaseUrl,
910
openAiModelInfoSaneDefaults,
1011
DEEP_SEEK_DEFAULT_TEMPERATURE,
@@ -521,8 +522,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
521522
}
522523

523524
protected _isAzureAiInference(baseUrl?: string): boolean {
524-
const urlHost = this._getUrlHost(baseUrl)
525-
return urlHost.endsWith(".services.ai.azure.com")
525+
return isAzureAiInferenceBaseUrl(baseUrl)
526526
}
527527

528528
/**

webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.spec.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,24 @@ describe("OpenAICompatible Component - includeMaxTokens checkbox", () => {
201201
screen.queryByText("settings:providers.azureOpenAiDeploymentNameDescription"),
202202
).not.toBeInTheDocument()
203203
})
204+
205+
it("keeps generic guidance when Azure AI Inference uses the Azure compatibility flag", () => {
206+
render(
207+
<OpenAICompatible
208+
apiConfiguration={
209+
{
210+
openAiBaseUrl: "https://my-resource.services.ai.azure.com/models",
211+
openAiUseAzure: true,
212+
} as ProviderSettings
213+
}
214+
setApiConfigurationField={mockSetApiConfigurationField}
215+
organizationAllowList={mockOrganizationAllowList}
216+
/>,
217+
)
218+
219+
expect(screen.getByPlaceholderText("settings:placeholders.baseUrl")).toBeInTheDocument()
220+
expect(mockModelPicker).toHaveBeenLastCalledWith(expect.objectContaining({ label: undefined }))
221+
})
204222
})
205223

206224
describe("Initial State", () => {

0 commit comments

Comments
 (0)