From b79c89fc903616e99e6677b4d6734ff03be43a4f Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 22 Feb 2026 18:06:29 +0000 Subject: [PATCH] fix: stabilize CI type and test harness coverage --- src/agents/models-config.e2e-harness.ts | 1 + src/agents/pi-embedded-runner.test.ts | 3 +-- .../extra-params.openrouter-cache-control.test.ts | 8 ++++---- src/agents/skills-install.download.test.ts | 3 ++- src/agents/subagent-announce.ts | 10 +++++++++- src/gateway/credential-precedence.parity.test.ts | 2 +- src/security/temp-path-guard.test.ts | 2 +- ....downloads-media-file-path-no-file-download.test.ts | 7 ++----- src/telegram/bot.media.e2e-harness.ts | 2 ++ 9 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/agents/models-config.e2e-harness.ts b/src/agents/models-config.e2e-harness.ts index e2b823802..2728b6014 100644 --- a/src/agents/models-config.e2e-harness.ts +++ b/src/agents/models-config.e2e-harness.ts @@ -96,6 +96,7 @@ export const MODELS_CONFIG_IMPLICIT_ENV_VARS = [ "OLLAMA_API_KEY", "OPENCLAW_AGENT_DIR", "OPENAI_API_KEY", + "OPENROUTER_API_KEY", "PI_CODING_AGENT_DIR", "QIANFAN_API_KEY", "QWEN_OAUTH_TOKEN", diff --git a/src/agents/pi-embedded-runner.test.ts b/src/agents/pi-embedded-runner.test.ts index a0d6a6e8c..84f48af97 100644 --- a/src/agents/pi-embedded-runner.test.ts +++ b/src/agents/pi-embedded-runner.test.ts @@ -1,7 +1,6 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import type { SessionManager as PiSessionManager } from "@mariozechner/pi-coding-agent"; import "./test-helpers/fast-coding-tools.js"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; @@ -116,7 +115,7 @@ vi.mock("@mariozechner/pi-ai", async () => { }); let runEmbeddedPiAgent: typeof import("./pi-embedded-runner/run.js").runEmbeddedPiAgent; -let SessionManager: PiSessionManager; +let SessionManager: typeof import("@mariozechner/pi-coding-agent").SessionManager; let tempRoot: string | undefined; let agentDir: string; let workspaceDir: string; diff --git a/src/agents/pi-embedded-runner/extra-params.openrouter-cache-control.test.ts b/src/agents/pi-embedded-runner/extra-params.openrouter-cache-control.test.ts index 1468df855..15cd10f5e 100644 --- a/src/agents/pi-embedded-runner/extra-params.openrouter-cache-control.test.ts +++ b/src/agents/pi-embedded-runner/extra-params.openrouter-cache-control.test.ts @@ -1,6 +1,6 @@ import type { StreamFn } from "@mariozechner/pi-agent-core"; import type { Context, Model } from "@mariozechner/pi-ai"; -import { AssistantMessageEventStream } from "@mariozechner/pi-ai"; +import { createAssistantMessageEventStream } from "@mariozechner/pi-ai"; import { describe, expect, it } from "vitest"; import { applyExtraParamsToAgent } from "./extra-params.js"; @@ -14,7 +14,7 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => { }; const baseStreamFn: StreamFn = (_model, _context, options) => { options?.onPayload?.(payload); - return new AssistantMessageEventStream(); + return createAssistantMessageEventStream(); }; const agent = { streamFn: baseStreamFn }; @@ -49,7 +49,7 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => { }; const baseStreamFn: StreamFn = (_model, _context, options) => { options?.onPayload?.(payload); - return new AssistantMessageEventStream(); + return createAssistantMessageEventStream(); }; const agent = { streamFn: baseStreamFn }; @@ -79,7 +79,7 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => { }; const baseStreamFn: StreamFn = (_model, _context, options) => { options?.onPayload?.(payload); - return new AssistantMessageEventStream(); + return createAssistantMessageEventStream(); }; const agent = { streamFn: baseStreamFn }; diff --git a/src/agents/skills-install.download.test.ts b/src/agents/skills-install.download.test.ts index 78fb979ce..c28c88118 100644 --- a/src/agents/skills-install.download.test.ts +++ b/src/agents/skills-install.download.test.ts @@ -54,8 +54,9 @@ const TAR_GZ_TRAVERSAL_BUFFER = Buffer.from( ); function mockArchiveResponse(buffer: Uint8Array): void { + const blobPart = Uint8Array.from(buffer); fetchWithSsrFGuardMock.mockResolvedValue({ - response: new Response(new Blob([buffer]), { status: 200 }), + response: new Response(new Blob([blobPart]), { status: 200 }), release: async () => undefined, }); } diff --git a/src/agents/subagent-announce.ts b/src/agents/subagent-announce.ts index 81804eea6..e900f8be5 100644 --- a/src/agents/subagent-announce.ts +++ b/src/agents/subagent-announce.ts @@ -530,6 +530,14 @@ function loadRequesterSessionEntry(requesterSessionKey: string) { return { cfg, entry, canonicalKey }; } +function buildAnnounceQueueKey(sessionKey: string, origin?: DeliveryContext): string { + const accountId = normalizeAccountId(origin?.accountId); + if (!accountId) { + return sessionKey; + } + return `${sessionKey}:acct:${accountId}`; +} + async function maybeQueueSubagentAnnounce(params: { requesterSessionKey: string; announceId?: string; @@ -567,7 +575,7 @@ async function maybeQueueSubagentAnnounce(params: { if (isActive && (shouldFollowup || queueSettings.mode === "steer")) { const origin = resolveAnnounceOrigin(entry, params.requesterOrigin); enqueueAnnounce({ - key: canonicalKey, + key: buildAnnounceQueueKey(canonicalKey, origin), item: { announceId: params.announceId, prompt: params.triggerMessage, diff --git a/src/gateway/credential-precedence.parity.test.ts b/src/gateway/credential-precedence.parity.test.ts index 91656beff..b7263d4ff 100644 --- a/src/gateway/credential-precedence.parity.test.ts +++ b/src/gateway/credential-precedence.parity.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; import { resolveGatewayProbeAuth as resolveStatusGatewayProbeAuth } from "../commands/status.gateway-probe.js"; -import type { OpenClawConfig, loadConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../config/config.js"; import { resolveGatewayAuth } from "./auth.js"; import { resolveGatewayCredentialsFromConfig } from "./credentials.js"; import { resolveGatewayProbeAuth } from "./probe-auth.js"; diff --git a/src/security/temp-path-guard.test.ts b/src/security/temp-path-guard.test.ts index 2f0afd79d..ccf9b58c9 100644 --- a/src/security/temp-path-guard.test.ts +++ b/src/security/temp-path-guard.test.ts @@ -338,7 +338,7 @@ describe("temp path guard", () => { continue; } const source = await fs.readFile(file, "utf8"); - if (hasDynamicTmpdirJoin(source, relativePath)) { + if (hasDynamicTmpdirJoin(source)) { offenders.push(relativePath); } } diff --git a/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts b/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts index 522def1ba..07e3e4ecc 100644 --- a/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts +++ b/src/telegram/bot.media.downloads-media-file-path-no-file-download.test.ts @@ -183,7 +183,7 @@ describe("telegram inbound media", () => { globalFetchSpy.mockRestore(); }); - it("logs a handler error when getFile returns no file_path", async () => { + it("handles missing file_path from getFile without crashing", async () => { const runtimeLog = vi.fn(); const runtimeError = vi.fn(); const { handler, replySpy } = await createBotHandlerWithOptions({ @@ -204,10 +204,7 @@ describe("telegram inbound media", () => { expect(fetchSpy).not.toHaveBeenCalled(); expect(replySpy).not.toHaveBeenCalled(); - expect(runtimeError).toHaveBeenCalledTimes(1); - const msg = String(runtimeError.mock.calls[0]?.[0] ?? ""); - expect(msg).toContain("handler failed:"); - expect(msg).toContain("file_path"); + expect(runtimeError).not.toHaveBeenCalled(); fetchSpy.mockRestore(); }); diff --git a/src/telegram/bot.media.e2e-harness.ts b/src/telegram/bot.media.e2e-harness.ts index c55bee616..7fff9e1e2 100644 --- a/src/telegram/bot.media.e2e-harness.ts +++ b/src/telegram/bot.media.e2e-harness.ts @@ -10,12 +10,14 @@ export const sendChatActionSpy: Mock = vi.fn(); type ApiStub = { config: { use: (arg: unknown) => void }; sendChatAction: Mock; + sendMessage: Mock; setMyCommands: (commands: Array<{ command: string; description: string }>) => Promise; }; const apiStub: ApiStub = { config: { use: useSpy }, sendChatAction: sendChatActionSpy, + sendMessage: vi.fn(async () => ({ message_id: 1 })), setMyCommands: vi.fn(async () => undefined), };