diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d185ea9a..84f7a3294 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Models/MiniMax auth header defaults: set `authHeader: true` for both onboarding-generated MiniMax API providers and implicit built-in MiniMax (`minimax`, `minimax-portal`) provider templates so first requests no longer fail with MiniMax `401 authentication_error` due to missing `Authorization` header. Landed from contributor PRs #27622 by @riccoyuanft and #27631 by @kevinWangSheng. (#27600, #15303) - Pi image-token usage: stop re-injecting history image blocks each turn, process image references from the current prompt only, and prune already-answered user-image blocks in stored history to prevent runaway token growth. (#27602) - BlueBubbles/SSRF: auto-allowlist the configured `serverUrl` hostname for attachment fetches so localhost/private-IP BlueBubbles setups are no longer false-blocked by default SSRF checks. Landed from contributor PR #27648 by @lailoo. (#27599) Thanks @taylorhou for reporting. - Security/Gateway node pairing: pin paired-device `platform`/`deviceFamily` metadata across reconnects and bind those fields into device-auth signatures, so reconnect metadata spoofing cannot expand node command allowlists without explicit repair pairing. This ships in the next npm release (`2026.2.26`). Thanks @76embiid21 for reporting. diff --git a/src/agents/models-config.providers.nvidia.test.ts b/src/agents/models-config.providers.nvidia.test.ts index 17025cb86..02086283c 100644 --- a/src/agents/models-config.providers.nvidia.test.ts +++ b/src/agents/models-config.providers.nvidia.test.ts @@ -1,4 +1,5 @@ import { mkdtempSync } from "node:fs"; +import { writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; @@ -54,9 +55,38 @@ describe("MiniMax implicit provider (#15275)", () => { const providers = await resolveImplicitProviders({ agentDir }); expect(providers?.minimax).toBeDefined(); expect(providers?.minimax?.api).toBe("anthropic-messages"); + expect(providers?.minimax?.authHeader).toBe(true); expect(providers?.minimax?.baseUrl).toBe("https://api.minimax.io/anthropic"); }); }); + + it("should set authHeader for minimax portal provider", async () => { + const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-")); + await writeFile( + join(agentDir, "auth-profiles.json"), + JSON.stringify( + { + version: 1, + profiles: { + "minimax-portal:default": { + type: "oauth", + provider: "minimax-portal", + oauth: { + access: "token", + expires: Date.now() + 60_000, + }, + }, + }, + }, + null, + 2, + ), + "utf8", + ); + + const providers = await resolveImplicitProviders({ agentDir }); + expect(providers?.["minimax-portal"]?.authHeader).toBe(true); + }); }); describe("vLLM provider", () => { diff --git a/src/agents/models-config.providers.ts b/src/agents/models-config.providers.ts index ef7d41c06..b4b5d8102 100644 --- a/src/agents/models-config.providers.ts +++ b/src/agents/models-config.providers.ts @@ -480,6 +480,7 @@ function buildMinimaxProvider(): ProviderConfig { return { baseUrl: MINIMAX_PORTAL_BASE_URL, api: "anthropic-messages", + authHeader: true, models: [ buildMinimaxTextModel({ id: MINIMAX_DEFAULT_MODEL_ID, @@ -515,6 +516,7 @@ function buildMinimaxPortalProvider(): ProviderConfig { return { baseUrl: MINIMAX_PORTAL_BASE_URL, api: "anthropic-messages", + authHeader: true, models: [ buildMinimaxTextModel({ id: MINIMAX_DEFAULT_MODEL_ID, diff --git a/src/commands/onboard-auth.config-minimax.ts b/src/commands/onboard-auth.config-minimax.ts index 6314a641d..90a3c5888 100644 --- a/src/commands/onboard-auth.config-minimax.ts +++ b/src/commands/onboard-auth.config-minimax.ts @@ -181,6 +181,7 @@ function applyMinimaxApiProviderConfigWithBaseUrl( ...existingProviderRest, baseUrl: params.baseUrl, api: "anthropic-messages", + authHeader: true, ...(normalizedApiKey?.trim() ? { apiKey: normalizedApiKey } : {}), models: mergedModels.length > 0 ? mergedModels : [apiModel], }; diff --git a/src/commands/onboard-auth.test.ts b/src/commands/onboard-auth.test.ts index e8671fa1a..5b671cbed 100644 --- a/src/commands/onboard-auth.test.ts +++ b/src/commands/onboard-auth.test.ts @@ -365,6 +365,7 @@ describe("applyMinimaxApiConfig", () => { expect(cfg.models?.providers?.minimax).toMatchObject({ baseUrl: "https://api.minimax.io/anthropic", api: "anthropic-messages", + authHeader: true, }); }); @@ -404,6 +405,7 @@ describe("applyMinimaxApiConfig", () => { ); expect(cfg.models?.providers?.minimax?.baseUrl).toBe("https://api.minimax.io/anthropic"); expect(cfg.models?.providers?.minimax?.api).toBe("anthropic-messages"); + expect(cfg.models?.providers?.minimax?.authHeader).toBe(true); expect(cfg.models?.providers?.minimax?.apiKey).toBe("old-key"); expect(cfg.models?.providers?.minimax?.models.map((m) => m.id)).toEqual([ "old-model", diff --git a/src/telegram/lane-delivery.ts b/src/telegram/lane-delivery.ts index 60dbcdf5a..80fbe180c 100644 --- a/src/telegram/lane-delivery.ts +++ b/src/telegram/lane-delivery.ts @@ -109,11 +109,15 @@ export function createLaneTextDeliverer(params: CreateLaneTextDelivererParams) { text: string; skipRegressive: "always" | "existingOnly"; hadPreviewMessage: boolean; - }): boolean => - Boolean(args.currentPreviewText) && - args.currentPreviewText.startsWith(args.text) && - args.text.length < args.currentPreviewText.length && - (args.skipRegressive === "always" || args.hadPreviewMessage); + }): boolean => { + const currentPreviewText = args.currentPreviewText; + return ( + currentPreviewText !== undefined && + currentPreviewText.startsWith(args.text) && + args.text.length < currentPreviewText.length && + (args.skipRegressive === "always" || args.hadPreviewMessage) + ); + }; const tryEditPreviewMessage = async (args: { laneName: LaneName;