fix: scope whatsapp transcript echo fix

This commit is contained in:
Radek Sienkiewicz
2026-05-09 15:48:39 +02:00
parent 41369153cf
commit b5d2936d52
5 changed files with 20 additions and 38 deletions

View File

@@ -9,6 +9,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Feishu: auto-thread `message(action="send")` replies inside the topic when the active session is group_topic or group_topic_sender, and propagate `replyInThread` through text, card, and media outbound adapters so topic-scoped sessions no longer post at the group root. Fixes #74903. (#77151) Thanks @ai-hpc.
- WhatsApp: pass routing context into voice-note transcript echo preflight so echoed transcripts can deliver to the originating chat. Fixes #79778. (#79788) Thanks @hclsys.
## 2026.5.9

View File

@@ -3,9 +3,7 @@ import {
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
// gemini-2.5-flash is the stable GA model; preview models share the Tier 1 free RPD=250
// ceiling even on paid accounts, causing quota exhaustion under normal usage (#79670).
export const GOOGLE_GEMINI_DEFAULT_MODEL = "google/gemini-2.5-flash";
export const GOOGLE_GEMINI_DEFAULT_MODEL = "google/gemini-3.1-pro-preview";
export function applyGoogleGeminiModelDefault(cfg: OpenClawConfig): {
next: OpenClawConfig;

View File

@@ -4,7 +4,6 @@ import {
registerProviderPlugin,
requireRegisteredProvider,
} from "openclaw/plugin-sdk/plugin-test-runtime";
import { MINIMAX_OAUTH_MARKER } from "openclaw/plugin-sdk/provider-auth";
import { describe, expect, it, vi } from "vitest";
import { registerMinimaxProviders } from "./provider-registration.js";
import { createMiniMaxWebSearchProvider } from "./src/minimax-web-search-provider.js";
@@ -326,33 +325,6 @@ describe("minimax provider hooks", () => {
expect(result?.windows).toEqual([{ label: "5h", usedPercent: 2, resetAt: undefined }]);
});
it("portal catalog resolves OAuth token via resolveProviderAuth with oauthMarker", async () => {
const { providers } = await registerProviderPlugin({
plugin: minimaxProviderPlugin,
id: "minimax",
name: "MiniMax Provider",
});
const portalProvider = requireRegisteredProvider(providers, "minimax-portal");
const resolveProviderAuth = vi.fn(() => ({
apiKey: MINIMAX_OAUTH_MARKER,
mode: "oauth" as const,
source: "profile" as const,
}));
const result = await portalProvider.catalog?.run({
config: {},
resolveProviderAuth,
resolveProviderApiKey: () => ({ apiKey: undefined }),
} as never);
expect(resolveProviderAuth).toHaveBeenCalledWith("minimax-portal", {
oauthMarker: MINIMAX_OAUTH_MARKER,
});
expect(result).not.toBeNull();
if (result && "provider" in result) {
expect(result.provider.apiKey).toBe(MINIMAX_OAUTH_MARKER);
}
});
it("writes api and authHeader into the MiniMax portal OAuth config patch", async () => {
const { providers } = await registerProviderPlugin({
plugin: minimaxProviderPlugin,

View File

@@ -6,7 +6,11 @@ import type {
ProviderAuthResult,
ProviderCatalogContext,
} from "openclaw/plugin-sdk/plugin-entry";
import { MINIMAX_OAUTH_MARKER } from "openclaw/plugin-sdk/provider-auth";
import {
MINIMAX_OAUTH_MARKER,
ensureAuthProfileStore,
listProfilesForProvider,
} from "openclaw/plugin-sdk/provider-auth";
import { buildOauthProviderAuthResult } from "openclaw/plugin-sdk/provider-auth";
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth-api-key";
import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared";
@@ -96,13 +100,13 @@ function resolveApiCatalog(ctx: ProviderCatalogContext) {
function resolvePortalCatalog(ctx: ProviderCatalogContext) {
const explicitProvider = ctx.config.models?.providers?.[PORTAL_PROVIDER_ID];
const explicitApiKey = normalizeOptionalString(explicitProvider?.apiKey);
// resolveProviderAuth handles OAuth profiles via oauthMarker, returning the
// sentinel so the request layer can swap in the live access token (#79731).
const { apiKey: profileApiKey } = ctx.resolveProviderAuth(PORTAL_PROVIDER_ID, {
oauthMarker: MINIMAX_OAUTH_MARKER,
const envApiKey = ctx.resolveProviderApiKey(PORTAL_PROVIDER_ID).apiKey;
const authStore = ensureAuthProfileStore(ctx.agentDir, {
allowKeychainPrompt: false,
});
const apiKey = explicitApiKey ?? profileApiKey;
const hasProfiles = listProfilesForProvider(authStore, PORTAL_PROVIDER_ID).length > 0;
const explicitApiKey = normalizeOptionalString(explicitProvider?.apiKey);
const apiKey = envApiKey ?? explicitApiKey ?? (hasProfiles ? MINIMAX_OAUTH_MARKER : undefined);
if (!apiKey) {
return null;
}

View File

@@ -219,8 +219,15 @@ describe("processMessage audio preflight transcription", () => {
expect(transcribeFirstAudioMock).toHaveBeenCalledWith(
expect.objectContaining({
ctx: expect.objectContaining({
AccountId: "default",
From: "+15550000002",
MediaPaths: ["/tmp/voice.ogg"],
MediaTypes: ["audio/ogg; codecs=opus"],
OriginatingChannel: "whatsapp",
OriginatingTo: "+15550000002",
Provider: "whatsapp",
Surface: "whatsapp",
To: "+15550000001",
}),
}),
);