mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-07 10:34:44 +00:00
test(live): tolerate ARM provider drift
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
import { normalizeTranscriptForMatch } from "openclaw/plugin-sdk/provider-test-contracts";
|
||||
import { isLiveTestEnabled } from "openclaw/plugin-sdk/test-env";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { hasTrustedFfmpegForLiveVoiceNote } from "../../test/helpers/live-voice-note.js";
|
||||
import plugin from "./index.js";
|
||||
import { createGeminiWebSearchProvider } from "./src/gemini-web-search-provider.js";
|
||||
|
||||
@@ -75,6 +76,10 @@ describeLive("google plugin live", () => {
|
||||
}, 120_000);
|
||||
|
||||
it("transcodes speech to Opus for voice-note targets", async () => {
|
||||
if (!hasTrustedFfmpegForLiveVoiceNote("google")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { speechProviders } = await registerGooglePlugin();
|
||||
const provider = requireRegisteredProvider(speechProviders, "google");
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from "openclaw/plugin-sdk/plugin-test-runtime";
|
||||
import { isLiveTestEnabled } from "openclaw/plugin-sdk/test-env";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { hasTrustedFfmpegForLiveVoiceNote } from "../../test/helpers/live-voice-note.js";
|
||||
import plugin from "./index.js";
|
||||
import { buildMinimaxSpeechProvider } from "./speech-provider.js";
|
||||
import { createMiniMaxWebSearchProvider } from "./src/minimax-web-search-provider.js";
|
||||
@@ -70,6 +71,10 @@ describeTtsLive("minimax tts live", () => {
|
||||
}, 120_000);
|
||||
|
||||
it("synthesizes MiniMax TTS as an Opus voice note", async () => {
|
||||
if (!hasTrustedFfmpegForLiveVoiceNote("minimax")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const provider = buildMinimaxSpeechProvider();
|
||||
|
||||
const voiceNote = await provider.synthesize({
|
||||
|
||||
@@ -19,6 +19,17 @@ function isTransientKimiSearchError(error: unknown): boolean {
|
||||
return message.includes("timeout") || message.includes("aborted");
|
||||
}
|
||||
|
||||
function isKimiAuthDrift(error: unknown): boolean {
|
||||
if (!(error instanceof Error)) {
|
||||
return false;
|
||||
}
|
||||
const message = error.message.toLowerCase();
|
||||
return (
|
||||
message.includes("kimi api error (401)") &&
|
||||
(message.includes("incorrect api key") || message.includes("incorrect_api_key"))
|
||||
);
|
||||
}
|
||||
|
||||
describeLive("moonshot plugin live", () => {
|
||||
it("runs Kimi web search through the provider tool", async () => {
|
||||
const provider = createKimiWebSearchProvider();
|
||||
@@ -40,6 +51,10 @@ describeLive("moonshot plugin live", () => {
|
||||
break;
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
if (isKimiAuthDrift(error)) {
|
||||
console.warn("[moonshot:live] skip Kimi web search: auth drift");
|
||||
return;
|
||||
}
|
||||
if (!isTransientKimiSearchError(error) || attempt === 1) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { applyExtraParamsToAgent } from "./embedded-agent-runner.js";
|
||||
import { isLiveTestEnabled } from "./live-test-helpers.js";
|
||||
import { isLiveBillingDrift } from "./live-test-provider-drift.js";
|
||||
import { isLiveAuthDrift, isLiveBillingDrift } from "./live-test-provider-drift.js";
|
||||
|
||||
const OPENAI_KEY = process.env.OPENAI_API_KEY ?? "";
|
||||
const ANTHROPIC_KEY = process.env.ANTHROPIC_API_KEY ?? "";
|
||||
@@ -143,9 +143,15 @@ describeAnthropicLive("embedded agent extra params (anthropic live)", () => {
|
||||
usage?: { service_tier?: string };
|
||||
};
|
||||
const errorMessage = json.error?.message ?? `HTTP ${res.status}`;
|
||||
if (!res.ok && isLiveBillingDrift(errorMessage)) {
|
||||
console.warn(`[anthropic:live] skip service_tier ${serviceTier}: billing drift`);
|
||||
return null;
|
||||
if (!res.ok) {
|
||||
if (isLiveBillingDrift(errorMessage)) {
|
||||
console.warn(`[anthropic:live] skip service_tier ${serviceTier}: billing drift`);
|
||||
return null;
|
||||
}
|
||||
if (isLiveAuthDrift(errorMessage)) {
|
||||
console.warn(`[anthropic:live] skip service_tier ${serviceTier}: auth drift`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
expect(res.ok, errorMessage).toBe(true);
|
||||
return json;
|
||||
|
||||
@@ -18,6 +18,7 @@ describe("live test provider drift", () => {
|
||||
expect(
|
||||
isLiveAuthDrift('401 {"error":{"message":"The API key you provided is invalid."}}'),
|
||||
).toBe(true);
|
||||
expect(isLiveAuthDrift("invalid x-api-key")).toBe(true);
|
||||
});
|
||||
|
||||
it("classifies API-key rate-limit drift", () => {
|
||||
|
||||
@@ -47,7 +47,13 @@ export function liveProviderErrorText(error: unknown): string {
|
||||
|
||||
/** Returns whether an error is expected live auth/account drift. */
|
||||
export function isLiveAuthDrift(error: unknown): boolean {
|
||||
return isAuthErrorMessage(liveProviderErrorText(error));
|
||||
const raw = liveProviderErrorText(error);
|
||||
const message = normalizeLowercaseStringOrEmpty(raw);
|
||||
return (
|
||||
isAuthErrorMessage(raw) ||
|
||||
message.includes("invalid x-api-key") ||
|
||||
message.includes("incorrect x-api-key")
|
||||
);
|
||||
}
|
||||
|
||||
/** Returns whether an error is expected live billing/quota drift. */
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
isServerErrorMessage,
|
||||
} from "../../plugin-sdk/test-env.js";
|
||||
import { isLiveTestEnabled } from "../live-test-helpers.js";
|
||||
import { isLiveAuthDrift } from "../live-test-provider-drift.js";
|
||||
import { createImageTool, testing } from "./image-tool.js";
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY?.trim() ?? "";
|
||||
@@ -115,6 +116,7 @@ function isSkippableLiveError(error: unknown): boolean {
|
||||
const message = formatLiveError(error);
|
||||
return (
|
||||
isBillingErrorMessage(message) ||
|
||||
isLiveAuthDrift(message) ||
|
||||
isOverloadedErrorMessage(message) ||
|
||||
isServerErrorMessage(message) ||
|
||||
/timed out|operation was aborted/i.test(message)
|
||||
|
||||
15
test/helpers/live-voice-note.ts
Normal file
15
test/helpers/live-voice-note.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { resolveFfmpegBin } from "openclaw/plugin-sdk/media-runtime";
|
||||
|
||||
export function hasTrustedFfmpegForLiveVoiceNote(label: string): boolean {
|
||||
try {
|
||||
resolveFfmpegBin();
|
||||
return true;
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
if (message.includes("ffmpeg not found in trusted system directories")) {
|
||||
console.warn(`[${label}:live] skip voice-note transcode: ffmpeg unavailable`);
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user