From 89e158fc96e617889d5303abb25e596e24003917 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Sat, 28 Feb 2026 15:57:57 +0530 Subject: [PATCH] fix: harden azure custom-provider verification coverage (#29421) (thanks @kunalk16) --- CHANGELOG.md | 1 + src/commands/onboard-custom.test.ts | 39 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e904185b7..807283867 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ Docs: https://docs.openclaw.ai ### Fixes - Config/Doctor group allowlist diagnostics: align `groupPolicy: "allowlist"` warnings with per-channel runtime semantics by excluding Google Chat sender-list checks and by warning when no-fallback channels (for example iMessage) omit `groupAllowFrom`, with regression coverage. (#28477) Thanks @tonydehnke. +- Onboarding/Custom providers: use Azure OpenAI-specific verification auth/payload shape (`api-key`, deployment-path chat completions payload) when probing Azure endpoints so valid Azure custom-provider setup no longer fails preflight. (#29421) Thanks @kunalk16. ## 2026.2.26 diff --git a/src/commands/onboard-custom.test.ts b/src/commands/onboard-custom.test.ts index abdb99bd0..e65c1e381 100644 --- a/src/commands/onboard-custom.test.ts +++ b/src/commands/onboard-custom.test.ts @@ -131,6 +131,45 @@ describe("promptCustomApiConfig", () => { expect(JSON.parse(firstCall?.body ?? "{}")).toMatchObject({ max_tokens: 1 }); }); + it("uses azure-specific headers and body for openai verification probes", async () => { + const prompter = createTestPrompter({ + text: [ + "https://my-resource.openai.azure.com", + "azure-test-key", + "gpt-4.1", + "custom", + "alias", + ], + select: ["plaintext", "openai"], + }); + const fetchMock = stubFetchSequence([{ ok: true }]); + + await runPromptCustomApi(prompter); + + const firstCall = fetchMock.mock.calls[0]; + const firstUrl = firstCall?.[0]; + const firstInit = firstCall?.[1] as + | { body?: string; headers?: Record } + | undefined; + if (typeof firstUrl !== "string") { + throw new Error("Expected first verification call URL"); + } + const parsedBody = JSON.parse(firstInit?.body ?? "{}"); + + expect(firstUrl).toContain("/openai/deployments/gpt-4.1/chat/completions"); + expect(firstUrl).toContain("api-version=2024-10-21"); + expect(firstInit?.headers?.["api-key"]).toBe("azure-test-key"); + expect(firstInit?.headers?.Authorization).toBeUndefined(); + expect(firstInit?.body).toBeDefined(); + expect(parsedBody).toMatchObject({ + messages: [{ role: "user", content: "Hi" }], + max_completion_tokens: 5, + stream: false, + }); + expect(parsedBody).not.toHaveProperty("model"); + expect(parsedBody).not.toHaveProperty("max_tokens"); + }); + it("uses expanded max_tokens for anthropic verification probes", async () => { const prompter = createTestPrompter({ text: ["https://example.com", "test-key", "detected-model", "custom", "alias"],