From a388fbb6c3129f48a67f9f3db788c83f1d545bb7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 24 Feb 2026 03:47:32 +0000 Subject: [PATCH] fix: harden custom-provider verification probes (#24743) (thanks @Glucksberg) --- CHANGELOG.md | 1 + src/commands/onboard-custom.test.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e04213836..036017f16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Onboarding/Custom providers: raise verification probe token budgets for OpenAI and Anthropic compatibility checks to avoid false negatives on strict provider defaults. (#24743) Thanks @Glucksberg. - WhatsApp/DM routing: only update main-session last-route state when DM traffic is bound to the main session, preserving isolated `dmScope` routing. (#24949) Thanks @kevinWangSheng. - Providers/OpenRouter: when thinking is explicitly off, avoid injecting `reasoning.effort` so reasoning-required models can use provider defaults instead of failing request validation. (#24863) Thanks @DevSecTim. - Status/Pairing recovery: show explicit pairing-approval command hints (including requestId when safe) when gateway probe failures report pairing-required closures. (#24771) Thanks @markmusson. diff --git a/src/commands/onboard-custom.test.ts b/src/commands/onboard-custom.test.ts index c1bf8aa0d..c79c30daf 100644 --- a/src/commands/onboard-custom.test.ts +++ b/src/commands/onboard-custom.test.ts @@ -116,6 +116,35 @@ describe("promptCustomApiConfig", () => { expectOpenAiCompatResult({ prompter, textCalls: 5, selectCalls: 1, result }); }); + it("uses expanded max_tokens for openai verification probes", async () => { + const prompter = createTestPrompter({ + text: ["https://example.com/v1", "test-key", "detected-model", "custom", "alias"], + select: ["openai"], + }); + const fetchMock = stubFetchSequence([{ ok: true }]); + + await runPromptCustomApi(prompter); + + const firstCall = fetchMock.mock.calls[0]?.[1] as { body?: string } | undefined; + expect(firstCall?.body).toBeDefined(); + expect(JSON.parse(firstCall?.body ?? "{}")).toMatchObject({ max_tokens: 1024 }); + }); + + it("uses expanded max_tokens for anthropic verification probes", async () => { + const prompter = createTestPrompter({ + text: ["https://example.com", "test-key", "detected-model", "custom", "alias"], + select: ["unknown"], + }); + const fetchMock = stubFetchSequence([{ ok: false, status: 404 }, { ok: true }]); + + await runPromptCustomApi(prompter); + + expect(fetchMock).toHaveBeenCalledTimes(2); + const secondCall = fetchMock.mock.calls[1]?.[1] as { body?: string } | undefined; + expect(secondCall?.body).toBeDefined(); + expect(JSON.parse(secondCall?.body ?? "{}")).toMatchObject({ max_tokens: 1024 }); + }); + it("re-prompts base url when unknown detection fails", async () => { const prompter = createTestPrompter({ text: [