diff --git a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml index 425435eabf4..8728a30ef61 100644 --- a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml +++ b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml @@ -1370,8 +1370,16 @@ jobs: run: | set -euo pipefail if ! command -v ffmpeg >/dev/null 2>&1; then - sudo apt-get update - sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ffmpeg + for attempt in 1 2 3; do + if sudo apt-get update -o Acquire::Retries=3; then + break + fi + if [[ "${attempt}" == "3" ]]; then + exit 1 + fi + sleep $((attempt * 5)) + done + sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ffmpeg fi ffmpeg -version | head -1 diff --git a/extensions/moonshot/moonshot.live.test.ts b/extensions/moonshot/moonshot.live.test.ts index dcd0eca70fd..b3506c80c00 100644 --- a/extensions/moonshot/moonshot.live.test.ts +++ b/extensions/moonshot/moonshot.live.test.ts @@ -6,6 +6,17 @@ const KIMI_SEARCH_KEY = process.env.KIMI_API_KEY?.trim() || process.env.MOONSHOT_API_KEY?.trim() || ""; const describeLive = isLiveTestEnabled() && KIMI_SEARCH_KEY.length > 0 ? describe : describe.skip; +function isTransientKimiSearchError(error: unknown): boolean { + if (!(error instanceof Error)) { + return false; + } + if (error.name === "AbortError") { + return true; + } + const message = error.message.toLowerCase(); + return message.includes("timeout") || message.includes("aborted"); +} + describeLive("moonshot plugin live", () => { it("runs Kimi web search through the provider tool", async () => { const provider = createKimiWebSearchProvider(); @@ -14,7 +25,23 @@ describeLive("moonshot plugin live", () => { searchConfig: { kimi: { apiKey: KIMI_SEARCH_KEY }, cacheTtlMinutes: 0, timeoutSeconds: 90 }, } as never); - const result = await tool?.execute({ query: "OpenClaw GitHub", count: 1 }); + let result: Awaited["execute"]>> | undefined; + let lastError: unknown; + for (let attempt = 0; attempt < 2; attempt += 1) { + try { + result = await tool?.execute({ query: "OpenClaw GitHub", count: 1 }); + lastError = undefined; + break; + } catch (error) { + lastError = error; + if (!isTransientKimiSearchError(error) || attempt === 1) { + throw error; + } + } + } + if (lastError) { + throw lastError; + } expect(result?.provider).toBe("kimi"); expect(typeof result?.content).toBe("string");