From 7d2ef131c139598905be4f704076d658d4e010f2 Mon Sep 17 00:00:00 2001 From: cpojer Date: Tue, 17 Feb 2026 15:48:29 +0900 Subject: [PATCH] chore: Fix types in tests 42/N. --- src/auto-reply/inbound.test.ts | 2 ++ src/auto-reply/media-note.test.ts | 6 +++++- ...hes-fuzzy-selection-is-ambiguous.e2e.test.ts | 17 +++++++++++++++-- ...us-alongside-directive-only-acks.e2e.test.ts | 5 +++-- ...rent-elevated-level-as-off-after.e2e.test.ts | 3 ++- src/auto-reply/reply.heartbeat-typing.test.ts | 5 +++-- src/auto-reply/reply.media-note.test.ts | 3 ++- src/auto-reply/reply.raw-body.test.ts | 7 ++++++- ...oved-sender-toggle-elevated-mode.e2e.test.ts | 10 +++++++++- ...vated-off-groups-without-mention.e2e.test.ts | 12 ++++++++++-- ...ated-directive-unapproved-sender.e2e.test.ts | 15 ++++++++++++--- ...rror-cause-embedded-agent-throws.e2e.test.ts | 12 ++++++++++-- ...line-status-unauthorized-senders.e2e.test.ts | 10 +++++++++- ...-auth-profile-key-snippet-status.e2e.test.ts | 10 +++++++++- ...ault-model-status-not-configured.e2e.test.ts | 5 +++-- ...ck-model-picker-grouped-by-model.e2e.test.ts | 16 ++++++++++++---- .../agent-runner.misc.runreplyagent.test.ts | 5 +++-- .../reply/directive-handling.model.test.ts | 4 ++-- ...nline-actions.skip-when-config-empty.test.ts | 4 ++-- src/auto-reply/reply/memory-flush.test.ts | 3 ++- src/auto-reply/reply/reply-flow.test.ts | 5 +++-- src/auto-reply/reply/reply-utils.test.ts | 6 +++--- src/auto-reply/reply/route-reply.test.ts | 3 +++ src/auto-reply/status.test.ts | 4 +++- 24 files changed, 133 insertions(+), 39 deletions(-) diff --git a/src/auto-reply/inbound.test.ts b/src/auto-reply/inbound.test.ts index 4cae3e34c..a36deb4d1 100644 --- a/src/auto-reply/inbound.test.ts +++ b/src/auto-reply/inbound.test.ts @@ -370,6 +370,7 @@ describe("resolveGroupRequireMention", () => { GroupSpace: "145", }; const groupResolution: GroupKeyResolution = { + key: "discord:group:123", channel: "discord", id: "123", chatType: "group", @@ -394,6 +395,7 @@ describe("resolveGroupRequireMention", () => { GroupSubject: "#general", }; const groupResolution: GroupKeyResolution = { + key: "slack:group:C123", channel: "slack", id: "C123", chatType: "group", diff --git a/src/auto-reply/media-note.test.ts b/src/auto-reply/media-note.test.ts index 019b913d4..66fb41fbf 100644 --- a/src/auto-reply/media-note.test.ts +++ b/src/auto-reply/media-note.test.ts @@ -79,7 +79,11 @@ describe("buildInboundMediaNote", () => { const note = buildInboundMediaNote({ MediaPaths: ["/tmp/a.png", "/tmp/b.png"], MediaUrls: ["https://example.com/a.png", "https://example.com/b.png"], - MediaUnderstandingDecisions: [createSuccessfulImageMediaDecision()], + MediaUnderstandingDecisions: [ + createSuccessfulImageMediaDecision() as unknown as NonNullable< + Parameters[0]["MediaUnderstandingDecisions"] + >[number], + ], }); expect(note).toBe("[media attached: /tmp/b.png | https://example.com/b.png]"); }); diff --git a/src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts b/src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts index 5e8b07315..1658c4a8f 100644 --- a/src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts +++ b/src/auto-reply/reply.directive.directive-behavior.prefers-alias-matches-fuzzy-selection-is-ambiguous.e2e.test.ts @@ -3,6 +3,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { loadSessionStore } from "../config/sessions.js"; +import type { ModelDefinitionConfig } from "../config/types.models.js"; import { drainSystemEvents } from "../infra/system-events.js"; import { assertModelSelection, @@ -13,6 +14,18 @@ import { } from "./reply.directive.directive-behavior.e2e-harness.js"; import { getReplyFromConfig } from "./reply.js"; +function makeModelDefinition(id: string, name: string): ModelDefinitionConfig { + return { + id, + name, + reasoning: false, + input: ["text"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 128_000, + maxTokens: 8_192, + }; +} + describe("directive behavior", () => { installDirectiveBehaviorE2EHooks(); @@ -42,13 +55,13 @@ describe("directive behavior", () => { baseUrl: "https://api.moonshot.ai/v1", apiKey: "sk-test", api: "openai-completions", - models: [{ id: "kimi-k2-0905-preview", name: "Kimi K2" }], + models: [makeModelDefinition("kimi-k2-0905-preview", "Kimi K2")], }, lmstudio: { baseUrl: "http://127.0.0.1:1234/v1", apiKey: "lmstudio", api: "openai-responses", - models: [{ id: "kimi-k2-0905-preview", name: "Kimi K2 (Local)" }], + models: [makeModelDefinition("kimi-k2-0905-preview", "Kimi K2 (Local)")], }, }, }, diff --git a/src/auto-reply/reply.directive.directive-behavior.returns-status-alongside-directive-only-acks.e2e.test.ts b/src/auto-reply/reply.directive.directive-behavior.returns-status-alongside-directive-only-acks.e2e.test.ts index 9ae2d9d70..8ca0eb8c5 100644 --- a/src/auto-reply/reply.directive.directive-behavior.returns-status-alongside-directive-only-acks.e2e.test.ts +++ b/src/auto-reply/reply.directive.directive-behavior.returns-status-alongside-directive-only-acks.e2e.test.ts @@ -1,6 +1,7 @@ import "./reply.directive.directive-behavior.e2e-mocks.js"; import path from "node:path"; import { describe, expect, it } from "vitest"; +import type { OpenClawConfig } from "../config/config.js"; import { loadSessionStore } from "../config/sessions.js"; import { installDirectiveBehaviorE2EHooks, @@ -27,7 +28,7 @@ describe("directive behavior", () => { }, channels: { whatsapp: { allowFrom: ["*"] } }, session: { store: storePath }, - }; + } as unknown as OpenClawConfig; } async function runQueueDirective(params: { home: string; storePath: string; body: string }) { @@ -94,7 +95,7 @@ describe("directive behavior", () => { CommandAuthorized: true, }, {}, - makeRestrictedElevatedDisabledConfig(home), + makeRestrictedElevatedDisabledConfig(home) as unknown as OpenClawConfig, ); const text = extractReplyText(res); diff --git a/src/auto-reply/reply.directive.directive-behavior.shows-current-elevated-level-as-off-after.e2e.test.ts b/src/auto-reply/reply.directive.directive-behavior.shows-current-elevated-level-as-off-after.e2e.test.ts index 2d98a5e7e..2c3846636 100644 --- a/src/auto-reply/reply.directive.directive-behavior.shows-current-elevated-level-as-off-after.e2e.test.ts +++ b/src/auto-reply/reply.directive.directive-behavior.shows-current-elevated-level-as-off-after.e2e.test.ts @@ -1,5 +1,6 @@ import "./reply.directive.directive-behavior.e2e-mocks.js"; import { describe, expect, it } from "vitest"; +import type { OpenClawConfig } from "../config/config.js"; import { loadSessionStore } from "../config/sessions.js"; import { AUTHORIZED_WHATSAPP_COMMAND, @@ -65,7 +66,7 @@ describe("directive behavior", () => { CommandAuthorized: true, }, {}, - makeRestrictedElevatedDisabledConfig(home), + makeRestrictedElevatedDisabledConfig(home) as unknown as OpenClawConfig, ); const text = replyText(res); diff --git a/src/auto-reply/reply.heartbeat-typing.test.ts b/src/auto-reply/reply.heartbeat-typing.test.ts index a6c72429a..eaac90a08 100644 --- a/src/auto-reply/reply.heartbeat-typing.test.ts +++ b/src/auto-reply/reply.heartbeat-typing.test.ts @@ -1,4 +1,5 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import type { OpenClawConfig } from "../config/config.js"; import { createTempHomeHarness, makeReplyConfig } from "./reply.test-harness.js"; const runEmbeddedPiAgentMock = vi.fn(); @@ -63,7 +64,7 @@ describe("getReplyFromConfig typing (heartbeat)", () => { await getReplyFromConfig( { Body: "hi", From: "+1000", To: "+2000", Provider: "whatsapp" }, { onReplyStart, isHeartbeat: false }, - makeReplyConfig(home), + makeReplyConfig(home) as unknown as OpenClawConfig, ); expect(onReplyStart).toHaveBeenCalled(); @@ -81,7 +82,7 @@ describe("getReplyFromConfig typing (heartbeat)", () => { await getReplyFromConfig( { Body: "hi", From: "+1000", To: "+2000", Provider: "whatsapp" }, { onReplyStart, isHeartbeat: true }, - makeReplyConfig(home), + makeReplyConfig(home) as unknown as OpenClawConfig, ); expect(onReplyStart).not.toHaveBeenCalled(); diff --git a/src/auto-reply/reply.media-note.test.ts b/src/auto-reply/reply.media-note.test.ts index d864addc8..2b88aa2af 100644 --- a/src/auto-reply/reply.media-note.test.ts +++ b/src/auto-reply/reply.media-note.test.ts @@ -2,6 +2,7 @@ import path from "node:path"; import { describe, expect, it, vi } from "vitest"; import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js"; import { runEmbeddedPiAgent } from "../agents/pi-embedded.js"; +import type { OpenClawConfig } from "../config/config.js"; import { getReplyFromConfig } from "./reply.js"; vi.mock("../agents/pi-embedded.js", () => ({ @@ -48,7 +49,7 @@ function makeCfg(home: string) { }, channels: { whatsapp: { allowFrom: ["*"] } }, session: { store: path.join(home, "sessions.json") }, - }; + } as unknown as OpenClawConfig; } describe("getReplyFromConfig media note plumbing", () => { diff --git a/src/auto-reply/reply.raw-body.test.ts b/src/auto-reply/reply.raw-body.test.ts index 5b52e8029..896fdd114 100644 --- a/src/auto-reply/reply.raw-body.test.ts +++ b/src/auto-reply/reply.raw-body.test.ts @@ -1,4 +1,5 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import type { OpenClawConfig } from "../config/config.js"; import { createTempHomeHarness, makeReplyConfig } from "./reply.test-harness.js"; const agentMocks = vi.hoisted(() => ({ @@ -70,7 +71,11 @@ describe("RawBody directive parsing", () => { CommandAuthorized: true, }; - const res = await getReplyFromConfig(groupMessageCtx, {}, makeReplyConfig(home)); + const res = await getReplyFromConfig( + groupMessageCtx, + {}, + makeReplyConfig(home) as OpenClawConfig, + ); const text = Array.isArray(res) ? res[0]?.text : res?.text; expect(text).toBe("ok"); diff --git a/src/auto-reply/reply.triggers.trigger-handling.allows-approved-sender-toggle-elevated-mode.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.allows-approved-sender-toggle-elevated-mode.e2e.test.ts index c7c06ca8a..35b30e0dc 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.allows-approved-sender-toggle-elevated-mode.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.allows-approved-sender-toggle-elevated-mode.e2e.test.ts @@ -16,6 +16,14 @@ beforeAll(async () => { installTriggerHandlingE2eTestHooks(); +function requireSessionStorePath(cfg: { session?: { store?: string } }): string { + const storePath = cfg.session?.store; + if (!storePath) { + throw new Error("expected session store path"); + } + return storePath; +} + describe("trigger handling", () => { it("allows approved sender to toggle elevated mode", async () => { await withTempHome(async (home) => { @@ -46,7 +54,7 @@ describe("trigger handling", () => { const text = Array.isArray(res) ? res[0]?.text : res?.text; expect(text).toContain("tools.elevated.enabled"); - const storeRaw = await fs.readFile(cfg.session!.store, "utf-8"); + const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8"); const store = JSON.parse(storeRaw) as Record; expect(store[MAIN_SESSION_KEY]?.elevatedLevel).toBeUndefined(); }); diff --git a/src/auto-reply/reply.triggers.trigger-handling.allows-elevated-off-groups-without-mention.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.allows-elevated-off-groups-without-mention.e2e.test.ts index 8a01de419..a46c4d4da 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.allows-elevated-off-groups-without-mention.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.allows-elevated-off-groups-without-mention.e2e.test.ts @@ -16,6 +16,14 @@ beforeAll(async () => { installTriggerHandlingE2eTestHooks(); +function requireSessionStorePath(cfg: { session?: { store?: string } }): string { + const storePath = cfg.session?.store; + if (!storePath) { + throw new Error("expected session store path"); + } + return storePath; +} + describe("trigger handling", () => { it("allows elevated off in groups without mention", async () => { await withTempHome(async (home) => { @@ -38,7 +46,7 @@ describe("trigger handling", () => { const text = Array.isArray(res) ? res[0]?.text : res?.text; expect(text).toContain("Elevated mode disabled."); - const store = loadSessionStore(cfg.session!.store); + const store = loadSessionStore(requireSessionStorePath(cfg)); expect(store["agent:main:whatsapp:group:123@g.us"]?.elevatedLevel).toBe("off"); }); }); @@ -64,7 +72,7 @@ describe("trigger handling", () => { const text = Array.isArray(res) ? res[0]?.text : res?.text; expect(text).toContain("Elevated mode set to ask"); - const storeRaw = await fs.readFile(cfg.session!.store, "utf-8"); + const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8"); const store = JSON.parse(storeRaw) as Record; expect(store["agent:main:whatsapp:group:123@g.us"]?.elevatedLevel).toBe("on"); }); diff --git a/src/auto-reply/reply.triggers.trigger-handling.ignores-inline-elevated-directive-unapproved-sender.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.ignores-inline-elevated-directive-unapproved-sender.e2e.test.ts index 7bd34d678..4f5006a76 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.ignores-inline-elevated-directive-unapproved-sender.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.ignores-inline-elevated-directive-unapproved-sender.e2e.test.ts @@ -1,6 +1,7 @@ import fs from "node:fs/promises"; import { join } from "node:path"; import { beforeAll, describe, expect, it } from "vitest"; +import type { OpenClawConfig } from "../config/config.js"; import { getRunEmbeddedPiAgentMock, installTriggerHandlingE2eTestHooks, @@ -17,6 +18,14 @@ beforeAll(async () => { installTriggerHandlingE2eTestHooks(); +function requireSessionStorePath(cfg: { session?: { store?: string } }): string { + const storePath = cfg.session?.store; + if (!storePath) { + throw new Error("expected session store path"); + } + return storePath; +} + describe("trigger handling", () => { it("ignores inline elevated directive for unapproved sender", async () => { await withTempHome(async (home) => { @@ -56,7 +65,7 @@ describe("trigger handling", () => { }, tools: { elevated: { allowFrom: { discord: ["steipete"] } } }, session: { store: join(home, "sessions.json") }, - }; + } as OpenClawConfig; const res = await getReplyFromConfig( { @@ -75,7 +84,7 @@ describe("trigger handling", () => { const text = Array.isArray(res) ? res[0]?.text : res?.text; expect(text).toContain("Elevated mode set to ask"); - const storeRaw = await fs.readFile(cfg.session.store, "utf-8"); + const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8"); const store = JSON.parse(storeRaw) as Record; expect(store[MAIN_SESSION_KEY]?.elevatedLevel).toBe("on"); }); @@ -95,7 +104,7 @@ describe("trigger handling", () => { }, }, session: { store: join(home, "sessions.json") }, - }; + } as OpenClawConfig; const res = await getReplyFromConfig( { diff --git a/src/auto-reply/reply.triggers.trigger-handling.includes-error-cause-embedded-agent-throws.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.includes-error-cause-embedded-agent-throws.e2e.test.ts index cef2590bf..cb54f1d32 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.includes-error-cause-embedded-agent-throws.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.includes-error-cause-embedded-agent-throws.e2e.test.ts @@ -34,9 +34,17 @@ function mockEmbeddedOkPayload() { return runEmbeddedPiAgentMock; } +function requireSessionStorePath(cfg: { session?: { store?: string } }): string { + const storePath = cfg.session?.store; + if (!storePath) { + throw new Error("expected session store path"); + } + return storePath; +} + async function writeStoredModelOverride(cfg: ReturnType): Promise { await fs.writeFile( - cfg.session!.store, + requireSessionStorePath(cfg), JSON.stringify({ [MAIN_SESSION_KEY]: { sessionId: "main", @@ -154,7 +162,7 @@ describe("trigger handling", () => { ); const text = Array.isArray(res) ? res[0]?.text : res?.text; expect(text).toContain("Group activation set to always"); - const store = JSON.parse(await fs.readFile(cfg.session!.store, "utf-8")) as Record< + const store = JSON.parse(await fs.readFile(requireSessionStorePath(cfg), "utf-8")) as Record< string, { groupActivation?: string } >; diff --git a/src/auto-reply/reply.triggers.trigger-handling.keeps-inline-status-unauthorized-senders.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.keeps-inline-status-unauthorized-senders.e2e.test.ts index 44665656e..99306b3f6 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.keeps-inline-status-unauthorized-senders.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.keeps-inline-status-unauthorized-senders.e2e.test.ts @@ -40,6 +40,14 @@ function makeUnauthorizedWhatsAppCfg(home: string) { }; } +function requireSessionStorePath(cfg: { session?: { store?: string } }): string { + const storePath = cfg.session?.store; + if (!storePath) { + throw new Error("expected session store path"); + } + return storePath; +} + async function runInlineUnauthorizedCommand(params: { home: string; command: "/status" | "/help"; @@ -143,7 +151,7 @@ describe("trigger handling", () => { const text = Array.isArray(res) ? res[0]?.text : res?.text; expect(text).toContain("Send policy set to off"); - const storeRaw = await fs.readFile(cfg.session!.store, "utf-8"); + const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8"); const store = JSON.parse(storeRaw) as Record; expect(store[MAIN_SESSION_KEY]?.sendPolicy).toBe("deny"); }); diff --git a/src/auto-reply/reply.triggers.trigger-handling.reports-active-auth-profile-key-snippet-status.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.reports-active-auth-profile-key-snippet-status.e2e.test.ts index d94615f63..be8d82339 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.reports-active-auth-profile-key-snippet-status.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.reports-active-auth-profile-key-snippet-status.e2e.test.ts @@ -18,6 +18,14 @@ beforeAll(async () => { installTriggerHandlingE2eTestHooks(); +function requireSessionStorePath(cfg: { session?: { store?: string } }): string { + const storePath = cfg.session?.store; + if (!storePath) { + throw new Error("expected session store path"); + } + return storePath; +} + describe("trigger handling", () => { it("reports active auth profile and key snippet in status", async () => { await withTempHome(async (home) => { @@ -50,7 +58,7 @@ describe("trigger handling", () => { Provider: "whatsapp", } as Parameters[1]); await fs.writeFile( - cfg.session!.store, + requireSessionStorePath(cfg), JSON.stringify( { [sessionKey]: { diff --git a/src/auto-reply/reply.triggers.trigger-handling.shows-endpoint-default-model-status-not-configured.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.shows-endpoint-default-model-status-not-configured.e2e.test.ts index efdddb634..c0220f4a5 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.shows-endpoint-default-model-status-not-configured.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.shows-endpoint-default-model-status-not-configured.e2e.test.ts @@ -1,5 +1,6 @@ import { beforeAll, describe, expect, it } from "vitest"; import { normalizeTestText } from "../../test/helpers/normalize-text.js"; +import type { OpenClawConfig } from "../config/config.js"; import { getRunEmbeddedPiAgentMock, installTriggerHandlingE2eTestHooks, @@ -47,7 +48,7 @@ describe("trigger handling", () => { }, }, }, - }; + } as unknown as OpenClawConfig; const res = await getReplyFromConfig(modelStatusCtx, {}, cfg); const text = Array.isArray(res) ? res[0]?.text : res?.text; @@ -78,7 +79,7 @@ describe("trigger handling", () => { it("restarts when enabled", async () => { await withTempHome(async (home) => { const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock(); - const cfg = { ...makeCfg(home), commands: { restart: true } }; + const cfg = { ...makeCfg(home), commands: { restart: true } } as OpenClawConfig; const res = await getReplyFromConfig( { Body: "/restart", diff --git a/src/auto-reply/reply.triggers.trigger-handling.shows-quick-model-picker-grouped-by-model.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.shows-quick-model-picker-grouped-by-model.e2e.test.ts index 79681d960..3cf248fe8 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.shows-quick-model-picker-grouped-by-model.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.shows-quick-model-picker-grouped-by-model.e2e.test.ts @@ -16,6 +16,14 @@ installTriggerHandlingE2eTestHooks(); const DEFAULT_SESSION_KEY = "telegram:slash:111"; +function requireSessionStorePath(cfg: { session?: { store?: string } }): string { + const storePath = cfg.session?.store; + if (!storePath) { + throw new Error("expected session store path"); + } + return storePath; +} + function makeTelegramModelCommand(body: string, sessionKey = DEFAULT_SESSION_KEY) { return { Body: body, @@ -78,7 +86,7 @@ describe("trigger handling", () => { expect(normalized).toContain("Model set to openrouter/anthropic/claude-opus-4-5"); - const store = loadSessionStore(cfg.session!.store); + const store = loadSessionStore(requireSessionStorePath(cfg)); expect(store[sessionKey]?.providerOverride).toBe("openrouter"); expect(store[sessionKey]?.modelOverride).toBe("anthropic/claude-opus-4-5"); }); @@ -92,7 +100,7 @@ describe("trigger handling", () => { expect(normalized).toContain("Browse: /models or /models "); expect(normalized).toContain("Switch: /model "); - const store = loadSessionStore(cfg.session!.store); + const store = loadSessionStore(requireSessionStorePath(cfg)); expect(store[sessionKey]?.providerOverride).toBeUndefined(); expect(store[sessionKey]?.modelOverride).toBeUndefined(); }); @@ -107,7 +115,7 @@ describe("trigger handling", () => { expect(normalized).toContain("Model reset to default (anthropic/claude-opus-4-5)"); - const store = loadSessionStore(cfg.session!.store); + const store = loadSessionStore(requireSessionStorePath(cfg)); expect(store[sessionKey]?.providerOverride).toBeUndefined(); expect(store[sessionKey]?.modelOverride).toBeUndefined(); }); @@ -119,7 +127,7 @@ describe("trigger handling", () => { expect(normalized).toContain("Model set to openai/gpt-5.2"); - const store = loadSessionStore(cfg.session!.store); + const store = loadSessionStore(requireSessionStorePath(cfg)); expect(store[sessionKey]?.providerOverride).toBe("openai"); expect(store[sessionKey]?.modelOverride).toBe("gpt-5.2"); }); diff --git a/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts b/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts index ab16815cf..191fd5766 100644 --- a/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts +++ b/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts @@ -642,10 +642,11 @@ describe("runReplyAgent claude-cli routing", () => { } it("uses claude-cli runner for claude-cli provider", async () => { - const randomSpy = vi.spyOn(crypto, "randomUUID").mockReturnValue("run-1"); + const runId = "00000000-0000-0000-0000-000000000001"; + const randomSpy = vi.spyOn(crypto, "randomUUID").mockReturnValue(runId); const lifecyclePhases: string[] = []; const unsubscribe = onAgentEvent((evt) => { - if (evt.runId !== "run-1") { + if (evt.runId !== runId) { return; } if (evt.stream !== "lifecycle") { diff --git a/src/auto-reply/reply/directive-handling.model.test.ts b/src/auto-reply/reply/directive-handling.model.test.ts index 97a8847ae..0b842fc0c 100644 --- a/src/auto-reply/reply/directive-handling.model.test.ts +++ b/src/auto-reply/reply/directive-handling.model.test.ts @@ -91,8 +91,8 @@ describe("/model chat UX", () => { describe("handleDirectiveOnly model persist behavior (fixes #1435)", () => { const allowedModelKeys = new Set(["anthropic/claude-opus-4-5", "openai/gpt-4o"]); const allowedModelCatalog = [ - { provider: "anthropic", id: "claude-opus-4-5" }, - { provider: "openai", id: "gpt-4o" }, + { provider: "anthropic", id: "claude-opus-4-5", name: "Claude Opus 4.5" }, + { provider: "openai", id: "gpt-4o", name: "GPT-4o" }, ]; const sessionKey = "agent:main:dm:1"; const storePath = "/tmp/sessions.json"; diff --git a/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts b/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts index e55d63e6c..c04140f63 100644 --- a/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts +++ b/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts @@ -66,12 +66,12 @@ describe("handleInlineActions", () => { elevatedEnabled: false, elevatedAllowed: false, elevatedFailures: [], - defaultActivation: () => ({ enabled: true, message: "" }), + defaultActivation: () => "always", resolvedThinkLevel: undefined, resolvedVerboseLevel: undefined, resolvedReasoningLevel: "off", resolvedElevatedLevel: "off", - resolveDefaultThinkingLevel: () => "off", + resolveDefaultThinkingLevel: async () => "off", provider: "openai", model: "gpt-4o-mini", contextTokens: 0, diff --git a/src/auto-reply/reply/memory-flush.test.ts b/src/auto-reply/reply/memory-flush.test.ts index 362b1b10a..e5905e677 100644 --- a/src/auto-reply/reply/memory-flush.test.ts +++ b/src/auto-reply/reply/memory-flush.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from "vitest"; +import type { OpenClawConfig } from "../../config/config.js"; import { resolveMemoryFlushPromptForRun } from "./memory-flush.js"; describe("resolveMemoryFlushPromptForRun", () => { @@ -9,7 +10,7 @@ describe("resolveMemoryFlushPromptForRun", () => { timeFormat: "12", }, }, - }; + } as OpenClawConfig; it("replaces YYYY-MM-DD using user timezone and appends current time", () => { const prompt = resolveMemoryFlushPromptForRun({ diff --git a/src/auto-reply/reply/reply-flow.test.ts b/src/auto-reply/reply/reply-flow.test.ts index 232b4dbdb..73c16fa0a 100644 --- a/src/auto-reply/reply/reply-flow.test.ts +++ b/src/auto-reply/reply/reply-flow.test.ts @@ -612,7 +612,7 @@ let previousRuntimeError: typeof defaultRuntime.error; beforeAll(() => { previousRuntimeError = defaultRuntime.error; - defaultRuntime.error = undefined; + defaultRuntime.error = (() => {}) as typeof defaultRuntime.error; }); afterAll(() => { @@ -1160,7 +1160,8 @@ describe("createReplyDispatcher", () => { }); it("fires onIdle when the queue drains", async () => { - const deliver = vi.fn(async () => await new Promise((resolve) => setTimeout(resolve, 5))); + const deliver: Parameters[0]["deliver"] = async () => + await new Promise((resolve) => setTimeout(resolve, 5)); const onIdle = vi.fn(); const dispatcher = createReplyDispatcher({ deliver, onIdle }); diff --git a/src/auto-reply/reply/reply-utils.test.ts b/src/auto-reply/reply/reply-utils.test.ts index 94f68652f..aeb9e8d66 100644 --- a/src/auto-reply/reply/reply-utils.test.ts +++ b/src/auto-reply/reply/reply-utils.test.ts @@ -369,9 +369,9 @@ describe("createTypingSignaler", () => { }); await signaler.signalTextDelta("hello"); - typing.startTypingLoop.mockClear(); - typing.startTypingOnText.mockClear(); - typing.refreshTypingTtl.mockClear(); + (typing.startTypingLoop as ReturnType).mockClear(); + (typing.startTypingOnText as ReturnType).mockClear(); + (typing.refreshTypingTtl as ReturnType).mockClear(); await signaler.signalToolStart(); expect(typing.refreshTypingTtl).toHaveBeenCalled(); diff --git a/src/auto-reply/reply/route-reply.test.ts b/src/auto-reply/reply/route-reply.test.ts index c4df75dd4..7712de8c7 100644 --- a/src/auto-reply/reply/route-reply.test.ts +++ b/src/auto-reply/reply/route-reply.test.ts @@ -64,6 +64,9 @@ const { routeReply } = await import("./route-reply.js"); const createRegistry = (channels: PluginRegistry["channels"]): PluginRegistry => ({ plugins: [], tools: [], + hooks: [], + typedHooks: [], + commands: [], channels, providers: [], gatewayHandlers: {}, diff --git a/src/auto-reply/status.test.ts b/src/auto-reply/status.test.ts index f8bf9da24..6e65d3b12 100644 --- a/src/auto-reply/status.test.ts +++ b/src/auto-reply/status.test.ts @@ -132,7 +132,9 @@ describe("buildStatusMessage", () => { sessionKey: "agent:main:main", queue: { mode: "none" }, mediaDecisions: [ - createSuccessfulImageMediaDecision(), + createSuccessfulImageMediaDecision() as unknown as NonNullable< + Parameters[0]["mediaDecisions"] + >[number], { capability: "audio", outcome: "skipped",