chore(tooling): enforce indexed access in core tests (#105375)

* test(tooling): enforce indexed access in core tests

* test(tui): constrain theme environment overrides

* test(doctor): enforce indexed access in migration fixtures
This commit is contained in:
Peter Steinberger
2026-07-12 14:29:52 +01:00
committed by GitHub
parent 161525d43c
commit 1b313dc4d4
381 changed files with 7830 additions and 2856 deletions
@@ -1,4 +1,6 @@
// Google shared conversion tests cover runtime-to-Google payload conversion.
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import type { Context, Tool } from "../types.js";
import { convertMessages, convertTools } from "./google-shared.js";
@@ -173,10 +175,10 @@ describe("google-shared convertMessages", () => {
const contents = convertMessagesForTest(model, context);
expect(contents).toHaveLength(2);
expect(contents[0].role).toBe("user");
expect(contents[1].role).toBe("user");
expect(contents[0].parts).toHaveLength(1);
expect(contents[1].parts).toHaveLength(1);
expect(expectDefined(contents[0], "contents[0] test invariant").role).toBe("user");
expect(expectDefined(contents[1], "contents[1] test invariant").role).toBe("user");
expect(expectDefined(contents[0], "contents[0] test invariant").parts).toHaveLength(1);
expect(expectDefined(contents[1], "contents[1] test invariant").parts).toHaveLength(1);
}
it("keeps thinking blocks when provider/model match", () => {
@@ -195,8 +197,8 @@ describe("google-shared convertMessages", () => {
const contents = convertMessagesForTest(model, context);
expect(contents).toHaveLength(1);
expect(contents[0].role).toBe("model");
const part = asRecord(contents[0].parts?.[0]);
expect(expectDefined(contents[0], "contents[0] test invariant").role).toBe("model");
const part = asRecord(expectDefined(contents[0], "contents[0] test invariant").parts?.[0]);
expect(part.thought).toBe(true);
expect(part.thoughtSignature).toBe("c2ln");
});
@@ -254,8 +256,8 @@ describe("google-shared convertMessages", () => {
const contents = convertMessagesForTest(model, context);
expectConvertedRoles(contents, ["user", "model", "model"]);
expect(contents[1].parts).toHaveLength(1);
expect(contents[2].parts).toHaveLength(1);
expect(expectDefined(contents[1], "contents[1] test invariant").parts).toHaveLength(1);
expect(expectDefined(contents[2], "contents[2] test invariant").parts).toHaveLength(1);
});
it("handles user message after tool result without model response in between", () => {
@@ -291,16 +293,16 @@ describe("google-shared convertMessages", () => {
const contents = convertMessagesForTest(model, context);
expect(contents).toHaveLength(4);
expect(contents[0].role).toBe("user");
expect(contents[1].role).toBe("model");
expect(contents[2].role).toBe("user");
expect(contents[3].role).toBe("user");
const toolResponsePart = contents[2].parts?.find(
expect(expectDefined(contents[0], "contents[0] test invariant").role).toBe("user");
expect(expectDefined(contents[1], "contents[1] test invariant").role).toBe("model");
expect(expectDefined(contents[2], "contents[2] test invariant").role).toBe("user");
expect(expectDefined(contents[3], "contents[3] test invariant").role).toBe("user");
const toolResponsePart = expectDefined(contents[2], "contents[2] test invariant").parts?.find(
(part) => typeof part === "object" && part !== null && "functionResponse" in part,
);
const toolResponse = asRecord(toolResponsePart);
expect(requireRecordProperty(toolResponse, "functionResponse").name).toBe("myTool");
expect(contents[3].role).toBe("user");
expect(expectDefined(contents[3], "contents[3] test invariant").role).toBe("user");
});
it("ensures function call comes after user turn, not after model turn", () => {
@@ -325,7 +327,7 @@ describe("google-shared convertMessages", () => {
const contents = convertMessagesForTest(model, context);
expectConvertedRoles(contents, ["user", "model", "model", "user"]);
const toolCallPart = contents[2].parts?.find(
const toolCallPart = expectDefined(contents[2], "contents[2] test invariant").parts?.find(
(part) => typeof part === "object" && part !== null && "functionCall" in part,
);
const toolCall = asRecord(toolCallPart);
@@ -1,4 +1,5 @@
import type { Part } from "@google/genai";
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import type { Context, Model } from "../types.js";
import { convertMessages } from "./google-shared.js";
@@ -79,7 +80,9 @@ describe("google-shared convertMessages — parallel tool results with an image
const contents = convertMessagesForTest(model, context);
expect(contents.map((content) => content.role)).toEqual(["user", "model", "user", "user"]);
expect(functionResponseNames(contents[2].parts)).toEqual(resultOrder);
expect(
functionResponseNames(expectDefined(contents[2], "contents[2] test invariant").parts),
).toEqual(resultOrder);
expect(contents[3]).toEqual({
role: "user",
parts: [
@@ -1,6 +1,7 @@
// Gateway Protocol tests cover native protocol levels.guard behavior.
import fs from "node:fs/promises";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { describe, it } from "vitest";
import { ProtocolSchemas } from "./schema/protocol-schemas.js";
import {
@@ -47,7 +48,7 @@ function extractInteger(
`${relativePath}: missing ${label}; keep native Gateway protocol levels in sync with packages/gateway-protocol/src/version.ts.`,
);
}
return Number.parseInt(match[1], 10);
return Number.parseInt(expectDefined(match[1], "match[1] test invariant"), 10);
}
/** Compares native min/max values to the TypeScript version constants. */
@@ -1,4 +1,5 @@
// Markdown Core tests cover frontmatter behavior.
import { expectDefined } from "@openclaw/normalization-core";
import JSON5 from "json5";
import { describe, expect, it } from "vitest";
import { parseFrontmatterBlock, stripFrontmatterBlock } from "./frontmatter.js";
@@ -33,7 +34,7 @@ metadata:
const result = parseFrontmatterBlock(content);
expect(result.metadata).toBe('{"openclaw":{"emoji":"disk","events":["command:new"]}}');
const parsed = JSON5.parse(result.metadata);
const parsed = JSON5.parse(expectDefined(result.metadata, "result.metadata test invariant"));
expect(parsed.openclaw?.emoji).toBe("disk");
});
@@ -3,6 +3,7 @@ import fsSync from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import {
buildFileEntry,
@@ -251,7 +252,9 @@ describe("memory host SDK package internals", () => {
remapChunkLines(chunks, lineMap);
expect(chunks[0].startLine).toBe(4);
expect(chunks[chunks.length - 1].endLine).toBe(13);
expect(expectDefined(chunks[0], "chunks[0] test invariant").startLine).toBe(4);
expect(
expectDefined(chunks[chunks.length - 1], "chunks[chunks.length - 1] test invariant").endLine,
).toBe(13);
});
});
+5 -1
View File
@@ -1,6 +1,7 @@
/** Tests ACP session manager resolution, turn execution, state transitions, and cleanup. */
import { setTimeout as scheduleNativeTimeout } from "node:timers";
import { setTimeout as sleep } from "node:timers/promises";
import { expectDefined } from "@openclaw/normalization-core";
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
import { describe, expect, it, vi } from "vitest";
import {
@@ -1345,7 +1346,10 @@ describe("AcpSessionManager", () => {
sessionKey,
});
expect(runtimeState.prepareFreshSession.mock.invocationCallOrder[0]).toBeLessThan(
runtimeState.ensureSession.mock.invocationCallOrder[0],
expectDefined(
runtimeState.ensureSession.mock.invocationCallOrder[0],
"runtimeState.ensureSession.mock.invocationCallOrder[0] test invariant",
),
);
});
+14 -4
View File
@@ -1,4 +1,5 @@
/** Tests configured channel-to-ACP binding resolution and generated session keys. */
import { expectDefined } from "@openclaw/normalization-core";
import { beforeAll, beforeEach, describe, expect, it } from "vitest";
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
import type { ChannelConfiguredBindingProvider, ChannelPlugin } from "../channels/plugins/types.js";
@@ -52,6 +53,10 @@ const discordBindings: ChannelConfiguredBindingProvider = {
},
};
function matchGroup(match: RegExpExecArray, index: number, context: string): string {
return expectDefined(match[index], context);
}
function parseTelegramTopicConversationForTest(params: {
conversationId: string;
parentConversationId?: string;
@@ -67,7 +72,8 @@ function parseTelegramTopicConversationForTest(params: {
}
const canonicalTopicMatch = /^(-[^:]+):topic:([^:]+)$/.exec(conversationId);
if (canonicalTopicMatch) {
const [, chatId, topicId] = canonicalTopicMatch;
const chatId = matchGroup(canonicalTopicMatch, 1, "Telegram topic chat id");
const topicId = matchGroup(canonicalTopicMatch, 2, "Telegram topic id");
return {
canonicalConversationId: `${chatId}:topic:${topicId}`,
chatId,
@@ -146,7 +152,9 @@ function parseFeishuConversationIdForTest(params: {
const topicSenderMatch = /^(.+):topic:([^:]+):sender:([^:]+)$/.exec(conversationId);
if (topicSenderMatch) {
const [, chatId, topicId, senderOpenId] = topicSenderMatch;
const chatId = matchGroup(topicSenderMatch, 1, "Feishu topic-sender chat id");
const topicId = matchGroup(topicSenderMatch, 2, "Feishu topic-sender topic id");
const senderOpenId = matchGroup(topicSenderMatch, 3, "Feishu topic-sender open id");
return {
canonicalConversationId: `${chatId}:topic:${topicId}:sender:${senderOpenId}`,
chatId,
@@ -158,7 +166,8 @@ function parseFeishuConversationIdForTest(params: {
const topicMatch = /^(.+):topic:([^:]+)$/.exec(conversationId);
if (topicMatch) {
const [, chatId, topicId] = topicMatch;
const chatId = matchGroup(topicMatch, 1, "Feishu topic chat id");
const topicId = matchGroup(topicMatch, 2, "Feishu topic id");
return {
canonicalConversationId: `${chatId}:topic:${topicId}`,
chatId,
@@ -169,7 +178,8 @@ function parseFeishuConversationIdForTest(params: {
const senderMatch = /^(.+):sender:([^:]+)$/.exec(conversationId);
if (senderMatch) {
const [, chatId, senderOpenId] = senderMatch;
const chatId = matchGroup(senderMatch, 1, "Feishu sender chat id");
const senderOpenId = matchGroup(senderMatch, 2, "Feishu sender open id");
return {
canonicalConversationId: `${chatId}:sender:${senderOpenId}`,
chatId,
+3 -2
View File
@@ -1,6 +1,7 @@
/** Tests prompt cancellation scoping across concurrent ACP sessions and Gateway runs. */
import type { CancelNotification, PromptRequest, PromptResponse } from "@agentclientprotocol/sdk";
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
/** Tests prompt cancellation scoping across concurrent ACP sessions and Gateway runs. */
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it, vi } from "vitest";
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
import type { GatewayClient } from "../gateway/client.js";
@@ -97,7 +98,7 @@ async function startPendingPrompt(
});
return {
promptPromise,
runId: harness.sentRunIds[before],
runId: expectDefined(harness.sentRunIds[before], "harness.sentRunIds[before] test invariant"),
};
}
+3 -2
View File
@@ -1,4 +1,3 @@
/** Tests ACP translator initialize/session lifecycle and prompt bridge behavior. */
import type {
CloseSessionRequest,
InitializeRequest,
@@ -9,6 +8,8 @@ import type {
} from "@agentclientprotocol/sdk";
import { PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
/** Tests ACP translator initialize/session lifecycle and prompt bridge behavior. */
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it, vi } from "vitest";
import type { GatewayClient } from "../gateway/client.js";
import type { GatewaySessionRow } from "../gateway/session-utils.js";
@@ -132,7 +133,7 @@ async function startPendingPrompt(params: {
});
return {
promptPromise,
runId: params.sentRunIds[before],
runId: expectDefined(params.sentRunIds[before], "params.sentRunIds[before] test invariant"),
};
}
+8 -2
View File
@@ -1,6 +1,7 @@
/** Tests ACP translator permission relay for Gateway exec approvals. */
import type { CancelNotification } from "@agentclientprotocol/sdk";
import { createInMemorySessionStore } from "@openclaw/acp-core/session";
/** Tests ACP translator permission relay for Gateway exec approvals. */
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it, vi } from "vitest";
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
import type { GatewayClient } from "../gateway/client.js";
@@ -302,7 +303,12 @@ describe("ACP translator permission relay", () => {
expect(requestPermission).not.toHaveBeenCalled();
expect(approvalResolveCalls(request)).toHaveLength(0);
await agent.handleGatewayEvent(createApprovalEvent({ runId: runIds[1], approvalId }));
await agent.handleGatewayEvent(
createApprovalEvent({
runId: expectDefined(runIds[1], "runIds[1] test invariant"),
approvalId,
}),
);
await vi.waitFor(() => {
expect(requestPermission).toHaveBeenCalledTimes(1);
+28 -7
View File
@@ -2,6 +2,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { AcpInitializeSessionInput } from "../acp/control-plane/manager.types.js";
import type { SessionEntry } from "../config/sessions/types.js";
@@ -882,9 +883,18 @@ describe("spawnAcpDirect", () => {
const agentCallIndex = hoisted.callGatewayMock.mock.calls.findIndex(
(call: unknown[]) => (call[0] as { method?: string }).method === "agent",
);
const patchCallOrder = hoisted.callGatewayMock.mock.invocationCallOrder[patchCallIndex];
const initializeCallOrder = hoisted.initializeSessionMock.mock.invocationCallOrder[0];
const agentCallOrder = hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex];
const patchCallOrder = expectDefined(
hoisted.callGatewayMock.mock.invocationCallOrder[patchCallIndex],
"hoisted.callGatewayMock.mock.invocationCallOrder[patchCallIndex] test invariant",
);
const initializeCallOrder = expectDefined(
hoisted.initializeSessionMock.mock.invocationCallOrder[0],
"hoisted.initializeSessionMock.mock.invocationCallOrder[0] test invariant",
);
const agentCallOrder = expectDefined(
hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex],
"hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex] test invariant",
);
expect(typeof patchCallOrder).toBe("number");
expect(typeof initializeCallOrder).toBe("number");
expect(typeof agentCallOrder).toBe("number");
@@ -2620,8 +2630,14 @@ describe("spawnAcpDirect", () => {
const agentCallIndex = hoisted.callGatewayMock.mock.calls.findIndex(
(call: unknown[]) => (call[0] as { method?: string }).method === "agent",
);
const relayCallOrder = hoisted.startAcpSpawnParentStreamRelayMock.mock.invocationCallOrder[0];
const agentCallOrder = hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex];
const relayCallOrder = expectDefined(
hoisted.startAcpSpawnParentStreamRelayMock.mock.invocationCallOrder[0],
"hoisted.startAcpSpawnParentStreamRelayMock.mock.invocationCallOrder[0] test invariant",
);
const agentCallOrder = expectDefined(
hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex],
"hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex] test invariant",
);
expect(agentCall?.params?.deliver).toBe(false);
expect(typeof relayCallOrder).toBe("number");
expect(typeof agentCallOrder).toBe("number");
@@ -3065,10 +3081,15 @@ describe("spawnAcpDirect", () => {
const agentCallIndex = hoisted.callGatewayMock.mock.calls.findIndex(
(call: unknown[]) => (call[0] as { method?: string }).method === "agent",
);
const agentCallOrder = hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex];
const agentCallOrder = expectDefined(
hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex],
"hoisted.callGatewayMock.mock.invocationCallOrder[agentCallIndex] test invariant",
);
expect(typeof agentCallOrder).toBe("number");
expect(typeof notifyOrder[0]).toBe("number");
expect(notifyOrder[0] > agentCallOrder).toBe(true);
expect(expectDefined(notifyOrder[0], "notifyOrder[0] test invariant") > agentCallOrder).toBe(
true,
);
});
it("binds Telegram forum-topic ACP sessions to the current topic", async () => {
+3 -2
View File
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
import http from "node:http";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, describe, expect, it, vi } from "vitest";
import { cleanupTempDirs, makeTempDir } from "../../test/helpers/temp-dir.js";
import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js";
@@ -1894,7 +1895,7 @@ process.on("SIGINT", shutdown);`,
},
});
const toolsA = await materializeBundleMcpToolsForRun({ runtime: runtimeA });
const resultA = await toolsA.tools[0].execute(
const resultA = await expectDefined(toolsA.tools[0], "toolsA.tools[0] test invariant").execute(
"call-configured-probe-a",
{},
undefined,
@@ -1920,7 +1921,7 @@ process.on("SIGINT", shutdown);`,
},
});
const toolsB = await materializeBundleMcpToolsForRun({ runtime: runtimeB });
const resultB = await toolsB.tools[0].execute(
const resultB = await expectDefined(toolsB.tools[0], "toolsB.tools[0] test invariant").execute(
"call-configured-probe-b",
{},
undefined,
@@ -1,5 +1,7 @@
/** Tests materializing MCP catalog tools into agent tool definitions and results. */
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { expectDefined } from "@openclaw/normalization-core";
import { validateToolArguments } from "openclaw/plugin-sdk/llm";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { getPluginToolMeta } from "../plugins/tools.js";
@@ -170,7 +172,10 @@ describe("createBundleMcpToolRuntime", () => {
const materialized = await materializeBundleMcpToolsForRun({ runtime: sessionRuntime });
materialized.restrictAppTools?.(materialized.tools);
const result = await materialized.tools[0].execute("call-1", {}, undefined, undefined);
const result = await expectDefined(
materialized.tools[0],
"materialized.tools[0] test invariant",
).execute("call-1", {}, undefined, undefined);
expect(result.content).toEqual([{ type: "image", data: "aW1hZ2U=", mimeType: "image/png" }]);
expect(result.details).toMatchObject({
mcpAppPreview: { mcpApp: { viewId: "cv_app" } },
@@ -186,8 +191,12 @@ describe("createBundleMcpToolRuntime", () => {
});
expect(runtime.tools.map((tool) => tool.name)).toEqual(["bundleProbe__bundle_probe"]);
expect(runtime.tools[0].executionMode).toBe("sequential");
expect(getPluginToolMeta(runtime.tools[0])).toMatchObject({
expect(expectDefined(runtime.tools[0], "runtime.tools[0] test invariant").executionMode).toBe(
"sequential",
);
expect(
getPluginToolMeta(expectDefined(runtime.tools[0], "runtime.tools[0] test invariant")),
).toMatchObject({
pluginId: "bundle-mcp",
mcp: {
serverName: "bundleProbe",
@@ -196,7 +205,12 @@ describe("createBundleMcpToolRuntime", () => {
operation: "tool",
},
});
const result = await runtime.tools[0].execute("call-bundle-probe", {}, undefined, undefined);
const result = await expectDefined(runtime.tools[0], "runtime.tools[0] test invariant").execute(
"call-bundle-probe",
{},
undefined,
undefined,
);
expectTextContentBlock(result.content[0], "FROM-BUNDLE");
expect(result.details).toEqual({
mcpServer: "bundleProbe",
@@ -211,7 +225,9 @@ describe("createBundleMcpToolRuntime", () => {
}),
});
expect(runtime.tools[0].executionMode).toBe("parallel");
expect(expectDefined(runtime.tools[0], "runtime.tools[0] test invariant").executionMode).toBe(
"parallel",
);
});
it("keeps structuredContent visible when MCP tools also return text content", async () => {
@@ -228,7 +244,12 @@ describe("createBundleMcpToolRuntime", () => {
}),
});
const result = await runtime.tools[0].execute("call-bundle-probe", {}, undefined, undefined);
const result = await expectDefined(runtime.tools[0], "runtime.tools[0] test invariant").execute(
"call-bundle-probe",
{},
undefined,
undefined,
);
expectTextContentBlock(
result.content[0],
@@ -288,7 +309,12 @@ describe("createBundleMcpToolRuntime", () => {
}),
});
const result = await runtime.tools[0].execute("call-bundle-probe", {}, undefined, undefined);
const result = await expectDefined(runtime.tools[0], "runtime.tools[0] test invariant").execute(
"call-bundle-probe",
{},
undefined,
undefined,
);
expect(result.content).toEqual([
{ type: "text", text: "intro" },
@@ -312,7 +338,12 @@ describe("createBundleMcpToolRuntime", () => {
}),
});
const result = await runtime.tools[0].execute("call-bundle-probe", {}, undefined, undefined);
const result = await expectDefined(runtime.tools[0], "runtime.tools[0] test invariant").execute(
"call-bundle-probe",
{},
undefined,
undefined,
);
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({ type: "text", text: JSON.stringify({ type: "image" }) });
@@ -483,9 +514,14 @@ describe("createBundleMcpToolRuntime", () => {
"knowledge__resources_list",
"knowledge__resources_read",
]);
await expect(tools[0].execute("inventory-only", {}, undefined, undefined)).rejects.toThrow(
"bundle-mcp catalog projection cannot execute tools",
);
await expect(
expectDefined(tools[0], "tools[0] test invariant").execute(
"inventory-only",
{},
undefined,
undefined,
),
).rejects.toThrow("bundle-mcp catalog projection cannot execute tools");
});
it("materializes configured MCP tools through the session runtime boundary", async () => {
@@ -517,13 +553,21 @@ describe("createBundleMcpToolRuntime", () => {
});
expect(created).toHaveLength(1);
expect(created[0].sessionId).toMatch(/^bundle-mcp:/);
expect(created[0].workspaceDir).toBe("/workspace");
expect(created[0].cfg?.mcp?.servers?.configuredProbe?.command).toBe("node");
expect(created[0].cfg?.mcp?.servers?.configuredProbe?.args).toEqual(["configured-probe.mjs"]);
expect(expectDefined(created[0], "created[0] test invariant").sessionId).toMatch(
/^bundle-mcp:/,
);
expect(expectDefined(created[0], "created[0] test invariant").workspaceDir).toBe("/workspace");
expect(
expectDefined(created[0], "created[0] test invariant").cfg?.mcp?.servers?.configuredProbe
?.command,
).toBe("node");
expect(
expectDefined(created[0], "created[0] test invariant").cfg?.mcp?.servers?.configuredProbe
?.args,
).toEqual(["configured-probe.mjs"]);
expect(runtime.tools.map((tool) => tool.name)).toEqual(["configuredProbe__bundle_probe"]);
const result = await runtime.tools[0].execute(
const result = await expectDefined(runtime.tools[0], "runtime.tools[0] test invariant").execute(
"call-configured-probe",
{},
undefined,
@@ -634,7 +678,7 @@ describe("createBundleMcpToolRuntime", () => {
},
});
expect(
validateToolArguments(runtime.tools[0], {
validateToolArguments(expectDefined(runtime.tools[0], "runtime.tools[0] test invariant"), {
type: "toolCall",
id: "call-page",
name: "notion__API-post-page",
@@ -1,4 +1,6 @@
/** Tests live model switching behavior in active agent command sessions. */
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { SessionEntry } from "../config/sessions.js";
import { INTERNAL_RUNTIME_CONTEXT_BEGIN, INTERNAL_RUNTIME_CONTEXT_END } from "./internal-events.js";
@@ -651,9 +653,13 @@ vi.mock("./model-selection.js", () => {
if (!alias) {
continue;
}
const [provider, ...modelParts] = ref.split("/");
const [rawProvider, ...modelParts] = ref.split("/");
const provider = expectDefined(rawProvider, `provider in model ref ${ref}`);
const model = modelParts.join("/");
byAlias.set(alias.toLowerCase(), { alias, ref: { provider, model } });
byAlias.set(alias.toLowerCase(), {
alias,
ref: { provider, model },
});
byKey.set(`${provider}/${model}`, [alias]);
}
return { byAlias, byKey };
@@ -4053,9 +4059,10 @@ describe("agentCommand LiveSessionModelSwitchError retry", () => {
state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => {
state.persistSessionEntryMock.mockClear();
const result = await params.run("openai", "claude");
const currentEntry = (state.sessionStoreMock as Record<string, SessionEntry>)[
"agent:main:main"
];
const currentEntry = expectDefined(
(state.sessionStoreMock as Record<string, SessionEntry>)["agent:main:main"],
'(state.sessionStoreMock as Record<string, SessionEntry>)[ "agent:main... test invariant',
);
currentEntry.modelSelectionLocked = true;
state.isModelSelectionLockedMock.mockReturnValue(true);
return {
@@ -5,6 +5,7 @@
*/
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentTool } from "openclaw/plugin-sdk/agent-core";
import { Type } from "typebox";
import { describe, expect, it, vi } from "vitest";
@@ -104,7 +105,7 @@ describe("agent tool definition adapter", () => {
const [definition] = toToolDefinitions([tool]);
const missingWorkdir = path.join(os.tmpdir(), `openclaw-missing-denied-cwd-${Date.now()}`);
const existing = await definition.execute(
const existing = await expectDefined(definition, "definition test invariant").execute(
"call-denied-existing-cwd",
{
command: "echo denied",
@@ -114,7 +115,7 @@ describe("agent tool definition adapter", () => {
undefined,
extensionContext,
);
const missing = await definition.execute(
const missing = await expectDefined(definition, "definition test invariant").execute(
"call-denied-missing-cwd",
{
command: "echo denied",
@@ -150,7 +151,7 @@ describe("agent tool definition adapter", () => {
});
const [definition] = toToolDefinitions([tool]);
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-denied-backend-cwd",
{
command: "echo denied",
@@ -175,7 +176,7 @@ describe("agent tool definition adapter", () => {
});
const [definition] = toToolDefinitions([tool]);
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-malformed-exec-params",
"not-an-object",
undefined,
@@ -205,7 +206,7 @@ describe("agent tool definition adapter", () => {
});
const [definition] = toToolDefinitions([tool]);
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-malformed-backend-sandbox-exec-params",
"not-an-object",
undefined,
@@ -229,7 +230,7 @@ describe("agent tool definition adapter", () => {
});
const [definition] = toToolDefinitions([tool]);
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-malformed-elevated-exec-params",
{},
undefined,
@@ -259,7 +260,7 @@ describe("agent tool definition adapter", () => {
});
const [definition] = toToolDefinitions([tool]);
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-malformed-backend-sandbox-exec-params",
{
workdir: "/remote/workspace/generated",
@@ -3,6 +3,8 @@
* Ensures gateway approval requests use non-blocking semantics and preserve
* plugin hook decisions.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot } from "../config/config.js";
import { setEmbeddedMode } from "../infra/embedded-mode.js";
@@ -185,7 +187,10 @@ describe("runBeforeToolCallHook — embedded mode approvals", () => {
await vi.waitFor(() => {
expect(broker.listPending()).toHaveLength(1);
});
const approval = broker.listPending()[0];
const approval = expectDefined(
broker.listPending()[0],
"broker.listPending()[0] test invariant",
);
expect(approval?.request.toolName).toBe("skill_workshop");
expect(broker.resolve(approval?.id, "allow-once")).toBe(true);
@@ -6,6 +6,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { SessionEntry } from "../config/sessions.js";
import { replaceSessionEntry } from "../config/sessions/session-accessor.js";
@@ -339,7 +340,7 @@ describe("before_tool_call hook deduplication (#15502)", () => {
agentId: "main",
sessionKey: "main",
});
const [def] = toToolDefinitions([wrapped]);
const def = expectDefined(toToolDefinitions([wrapped])[0], "wrapped web-fetch definition");
const extensionContext = {} as Parameters<typeof def.execute>[4];
await def.execute(
"call-dedup",
@@ -980,7 +981,7 @@ describe("before_tool_call hook deduplication (#15502)", () => {
sessionKey: "main",
});
const withAbort = wrapToolWithAbortSignal(wrapped, abortController.signal);
const [def] = toToolDefinitions([withAbort]);
const def = expectDefined(toToolDefinitions([withAbort])[0], "abort-wrapped Bash definition");
const extensionContext = {} as Parameters<typeof def.execute>[4];
await def.execute(
@@ -1010,12 +1011,15 @@ describe("before_tool_call hook deduplication (#15502)", () => {
text: `Fetched with status ${(result.details as { status: number }).status}`,
}),
);
const tool = wrapToolWithBeforeToolCallHook(
normalizeToolParameters(sourceTool, { modelProvider: "openai" }),
{
sessionId: "session-terminal-presentation",
onToolOutcome,
},
const tool = expectDefined(
wrapToolWithBeforeToolCallHook(
normalizeToolParameters(sourceTool, { modelProvider: "openai" }),
{
sessionId: "session-terminal-presentation",
onToolOutcome,
},
),
"wrapToolWithBeforeToolCallHook( normalizeToolParameters(sourceTool, {... test invariant",
);
await tool.execute("call-terminal-presentation", {
url: "https://example.com",
@@ -1116,13 +1120,16 @@ describe("before_tool_call hook deduplication (#15502)", () => {
it("passes hook context for unwrapped tool definitions", async () => {
const execute = vi.fn().mockResolvedValue({ content: [], details: { ok: true } });
const baseTool = { name: "exec", execute, description: "exec", parameters: {} } as any;
const [def] = toToolDefinitions([baseTool], {
agentId: "code-agent",
sessionKey: "agent:code-agent:main",
sessionId: "session-code",
runId: "run-code",
channelId: "channel-code",
});
const def = expectDefined(
toToolDefinitions([baseTool], {
agentId: "code-agent",
sessionKey: "agent:code-agent:main",
sessionId: "session-code",
runId: "run-code",
channelId: "channel-code",
})[0],
"unwrapped exec definition",
);
const extensionContext = {} as Parameters<typeof def.execute>[4];
await def.execute(
@@ -1178,7 +1185,7 @@ describe("before_tool_call hook integration for client tools", () => {
runBeforeToolCallImpl: async () => ({ params: { extra: true } }),
});
const onClientToolCall = vi.fn();
const [tool] = toClientToolDefinitions(
const clientTools = toClientToolDefinitions(
[
{
type: "function",
@@ -1192,6 +1199,7 @@ describe("before_tool_call hook integration for client tools", () => {
onClientToolCall,
{ agentId: "main", sessionKey: "main" },
);
const tool = expectDefined(clientTools[0], "client tool definition");
const extensionContext = {} as Parameters<typeof tool.execute>[4];
await tool.execute("client-call-1", { value: "ok" }, undefined, undefined, extensionContext);
@@ -1360,7 +1368,7 @@ describe("before_tool_call hook integration for client tools", () => {
value: { gate: "client" },
});
const [tool] = toClientToolDefinitions(
const clientTools = toClientToolDefinitions(
[
{
type: "function",
@@ -1379,6 +1387,7 @@ describe("before_tool_call hook integration for client tools", () => {
config: config as never,
},
);
const tool = expectDefined(clientTools[0], "client tool definition");
const extensionContext = {} as Parameters<typeof tool.execute>[4];
await tool.execute("client-call-policy", {}, undefined, undefined, extensionContext);
@@ -2,6 +2,7 @@
* Tests cron-aware deferred follow-up guidance in exec/process descriptions.
* Protects the model-facing text selected after tool filtering.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import { getPluginToolMeta, setPluginToolMeta } from "../plugins/tools.js";
import { applyDeferredFollowupToolDescriptions } from "./agent-tools.deferred-followup.js";
@@ -59,7 +60,10 @@ describe("createOpenClawCodingTools deferred follow-up guidance", () => {
const [updated] = applyDeferredFollowupToolDescriptions([processTool]);
expect(updated).not.toBe(processTool);
expect(getPluginToolMeta(updated)).toEqual({ pluginId: "example", optional: false });
expect(getPluginToolMeta(expectDefined(updated, "updated test invariant"))).toEqual({
pluginId: "example",
optional: false,
});
expect(getChannelAgentToolMeta(updated as never)).toEqual({
channelId: "example-channel",
});
+9 -5
View File
@@ -1,4 +1,5 @@
import { normalizeToolParameterSchema } from "@openclaw/ai/internal/openai";
import { expectDefined } from "@openclaw/normalization-core";
/**
* Tests provider-compatible tool schema normalization.
* Protects caching, ref inlining, OpenAPI keyword cleanup, and no-parameter
@@ -1085,13 +1086,16 @@ describe("normalizeToolParameters", () => {
required?: string[];
properties?: Record<string, Record<string, unknown>>;
};
const properties = expectDefined(parameters.properties, "normalized schema properties");
const count = expectDefined(properties.count, "normalized count property");
const query = expectDefined(properties.query, "normalized query property");
expect(parameters.required).toEqual(["count"]);
expect(parameters.properties?.count.minimum).toBeUndefined();
expect(parameters.properties?.count.maximum).toBeUndefined();
expect(parameters.properties?.count.type).toBe("integer");
expect(parameters.properties?.query.minLength).toBeUndefined();
expect(parameters.properties?.query.type).toBe("string");
expect(count.minimum).toBeUndefined();
expect(count.maximum).toBeUndefined();
expect(count.type).toBe("integer");
expect(query.minLength).toBeUndefined();
expect(query.type).toBe("string");
});
it("omits empty array items when model compat requires it", () => {
@@ -3,6 +3,7 @@
* Covers request construction, SSE parsing, aborts, tool calls, usage, and
* provider transport hooks.
*/
import { expectDefined } from "@openclaw/normalization-core";
import type { Model } from "openclaw/plugin-sdk/llm";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { attachModelProviderRequestTransport } from "./provider-request-config.js";
@@ -3159,9 +3160,10 @@ describe("anthropic transport stream", () => {
],
},
]);
const [[url, fetchOptions]] = guardedFetchMock.mock.calls as unknown as Array<
[string, { method?: string }]
>;
const [url, fetchOptions] = expectDefined(
(guardedFetchMock.mock.calls as unknown as Array<[string, { method?: string }]>)[0],
"(guardedFetchMock.mock.calls as unknown as Array<[string, { method?: string }]>)[0] test invariant",
);
expect(url).toBe("https://api.minimax.io/anthropic/v1/messages");
expect(fetchOptions.method).toBe("POST");
},
@@ -3,6 +3,7 @@
* Protects the recovery path that adopts a winner's fresh token instead of
* failing over after concurrent refresh races.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import {
makeSeededRandom,
@@ -107,7 +108,10 @@ describe("isRefreshTokenReusedError", () => {
"already been used to generate a new access token",
];
for (let i = 0; i < 500; i += 1) {
const marker = randomlyCased(markers[i % markers.length], rng);
const marker = randomlyCased(
expectDefined(markers[i % markers.length], "markers[i % markers.length] test invariant"),
rng,
);
const prefix = randomJunk(rng, 64);
const suffix = randomJunk(rng, 64);
const msg = `${prefix}${marker}${suffix}`;
@@ -3,6 +3,8 @@
* Covers runtime-only provenance, cloned store isolation, and stale credential
* replacement decisions.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it, vi } from "vitest";
import { MAX_DATE_TIMESTAMP_MS } from "../../shared/number-coercion.js";
import {
@@ -50,8 +52,11 @@ describe("overlayRuntimeExternalOAuthProfiles", () => {
expect(overlaidCodexProfile.access).toBe("access-1");
expect(store.profiles["openai:default"]?.type).toBe("api_key");
overlaid.profiles["openai:default"].provider = "mutated";
overlaid.order!.openai.push("mutated");
expectDefined(
overlaid.profiles["openai:default"],
'overlaid.profiles["openai:default"] test invariant',
).provider = "mutated";
expectDefined(overlaid.order?.openai, "OpenAI profile order").push("mutated");
expect(store.profiles["openai:default"]?.provider).toBe("openai");
expect(store.order?.openai).toEqual(["openai:default"]);
@@ -5,6 +5,7 @@
*/
import fs from "node:fs/promises";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { resetFileLockStateForTest } from "../../infra/file-lock.js";
import { captureEnv } from "../../test-utils/env.js";
@@ -139,12 +140,15 @@ describe("OAuth credential adoption is identity-gated", () => {
// Sub-agent store must NOT have been overwritten with main's foreign cred.
const subRaw = readAuthProfileStoreForTest(subAgentDir);
expectPersistedOpenAICodexProfile(subRaw.profiles[profileId], {
access: "sub-own-access",
refresh: "sub-own-refresh",
accountId: "acct-sub",
expires: subExpiry,
});
expectPersistedOpenAICodexProfile(
expectDefined(subRaw.profiles[profileId], "subRaw.profiles[profileId] test invariant"),
{
access: "sub-own-access",
refresh: "sub-own-refresh",
accountId: "acct-sub",
expires: subExpiry,
},
);
expect(JSON.stringify(subRaw)).not.toContain("main-foreign-access");
});
@@ -212,12 +216,15 @@ describe("OAuth credential adoption is identity-gated", () => {
// Main must still hold its foreign cred, untouched (mirror would also
// refuse because of identity mismatch).
const mainRaw = readAuthProfileStoreForTest(mainAgentDir);
expectPersistedOpenAICodexProfile(mainRaw.profiles[profileId], {
access: "main-foreign-access",
refresh: "main-foreign-refresh",
accountId: "acct-other",
expires: freshExpiry,
});
expectPersistedOpenAICodexProfile(
expectDefined(mainRaw.profiles[profileId], "mainRaw.profiles[profileId] test invariant"),
{
access: "main-foreign-access",
refresh: "main-foreign-refresh",
accountId: "acct-other",
expires: freshExpiry,
},
);
});
it("catch-block main-inherit refuses across accountId mismatch and surfaces the original error", async () => {
@@ -288,11 +295,14 @@ describe("OAuth credential adoption is identity-gated", () => {
// Sub-agent store must still have its own stale cred \u2014 no leak.
const subRaw = readAuthProfileStoreForTest(subAgentDir);
expectPersistedOpenAICodexProfile(subRaw.profiles[profileId], {
access: "sub-stale",
refresh: "sub-refresh-token",
accountId: "acct-sub",
});
expectPersistedOpenAICodexProfile(
expectDefined(subRaw.profiles[profileId], "subRaw.profiles[profileId] test invariant"),
{
access: "sub-stale",
refresh: "sub-refresh-token",
accountId: "acct-sub",
},
);
expect(JSON.stringify(subRaw)).not.toContain("main-foreign-refreshed");
});
});
@@ -5,6 +5,7 @@
*/
import fs from "node:fs/promises";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { resetFileLockStateForTest } from "../../infra/file-lock.js";
import { captureEnv } from "../../test-utils/env.js";
@@ -136,12 +137,15 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
// Main store should now carry refreshed metadata, so a peer agent
// starting fresh can resolve the runtime credential without token races.
const mainRaw = readAuthProfileStoreForTest(mainAgentDir);
expectPersistedOpenAICodexProfile(mainRaw.profiles[profileId], {
access: "sub-refreshed-access",
refresh: "sub-refreshed-refresh",
expires: freshExpiry,
accountId,
});
expectPersistedOpenAICodexProfile(
expectDefined(mainRaw.profiles[profileId], "mainRaw.profiles[profileId] test invariant"),
{
access: "sub-refreshed-access",
refresh: "sub-refreshed-refresh",
expires: freshExpiry,
accountId,
},
);
});
it("does not mirror when refresh was performed from the main agent itself", async () => {
@@ -176,11 +180,14 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
expect(result?.apiKey).toBe("main-refreshed-access");
const mainRaw = readAuthProfileStoreForTest(mainAgentDir);
expectPersistedOpenAICodexProfile(mainRaw.profiles[profileId], {
access: "main-refreshed-access",
refresh: "main-refreshed-refresh",
expires: freshExpiry,
});
expectPersistedOpenAICodexProfile(
expectDefined(mainRaw.profiles[profileId], "mainRaw.profiles[profileId] test invariant"),
{
access: "main-refreshed-access",
refresh: "main-refreshed-refresh",
expires: freshExpiry,
},
);
expect(refreshProviderOAuthCredentialWithPluginMock).toHaveBeenCalledTimes(1);
});
@@ -346,20 +353,26 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
expect(refreshProviderOAuthCredentialWithPluginMock).toHaveBeenCalledTimes(1);
const subRaw = readAuthProfileStoreForTest(subAgentDir);
expectPersistedOpenAICodexProfile(subRaw.profiles[profileId], {
access: "local-stale-access",
refresh: "local-stale-refresh",
expires: now - 120_000,
accountId,
});
expectPersistedOpenAICodexProfile(
expectDefined(subRaw.profiles[profileId], "subRaw.profiles[profileId] test invariant"),
{
access: "local-stale-access",
refresh: "local-stale-refresh",
expires: now - 120_000,
accountId,
},
);
const mainRaw = readAuthProfileStoreForTest(mainAgentDir);
expectPersistedOpenAICodexProfile(mainRaw.profiles[profileId], {
access: "main-owner-refreshed-access",
refresh: "main-owner-refreshed-refresh",
expires: freshExpiry,
accountId,
});
expectPersistedOpenAICodexProfile(
expectDefined(mainRaw.profiles[profileId], "mainRaw.profiles[profileId] test invariant"),
{
access: "main-owner-refreshed-access",
refresh: "main-owner-refreshed-refresh",
expires: freshExpiry,
accountId,
},
);
});
it("inherits main-agent credentials via the catch-block fallback when refresh throws after main becomes fresh", async () => {
@@ -425,11 +438,14 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
// Sub-agent's store keeps its local expired credential; inherited OAuth is read-through.
const subRaw = readAuthProfileStoreForTest(subAgentDir);
expectPersistedOpenAICodexProfile(subRaw.profiles[profileId], {
access: "cached-access-token",
refresh: "refresh-token",
accountId: "acct-shared",
});
expectPersistedOpenAICodexProfile(
expectDefined(subRaw.profiles[profileId], "subRaw.profiles[profileId] test invariant"),
{
access: "cached-access-token",
refresh: "refresh-token",
accountId: "acct-shared",
},
);
});
it("does not satisfy forced refresh from unchanged main-agent credentials after refresh fails", async () => {
@@ -6,6 +6,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { FILE_LOCK_TIMEOUT_ERROR_CODE, resetFileLockStateForTest } from "../../infra/file-lock.js";
import { closeOpenClawAgentDatabasesForTest } from "../../state/openclaw-agent-db.js";
@@ -382,11 +383,14 @@ describe("resolveApiKeyForProfile openai refresh fallback", () => {
});
const persisted = await readPersistedStore(agentDir);
expectPersistedOpenAICodexProfile(persisted.profiles[profileId], {
access: "rotated-access-token",
refresh: "rotated-refresh-token",
accountId: "acct-rotated",
});
expectPersistedOpenAICodexProfile(
expectDefined(persisted.profiles[profileId], "persisted.profiles[profileId] test invariant"),
{
access: "rotated-access-token",
refresh: "rotated-refresh-token",
accountId: "acct-rotated",
},
);
});
it("refreshes imported Codex credentials into the canonical auth store without writing back to .codex", async () => {
@@ -435,11 +439,14 @@ describe("resolveApiKeyForProfile openai refresh fallback", () => {
email: undefined,
});
const persisted = await readPersistedStore(agentDir);
expectPersistedOpenAICodexProfile(persisted.profiles[profileId], {
access: "rotated-cli-access-token",
refresh: "rotated-cli-refresh-token",
accountId: "acct-rotated",
});
expectPersistedOpenAICodexProfile(
expectDefined(persisted.profiles[profileId], "persisted.profiles[profileId] test invariant"),
{
access: "rotated-cli-access-token",
refresh: "rotated-cli-refresh-token",
accountId: "acct-rotated",
},
);
});
it("ignores mismatched fresh Codex CLI credentials when canonical local auth is bound to another account", async () => {
@@ -492,11 +499,14 @@ describe("resolveApiKeyForProfile openai refresh fallback", () => {
});
const persisted = await readPersistedStore(agentDir);
expectPersistedOpenAICodexProfile(persisted.profiles[profileId], {
access: "fresh-local-access-token",
refresh: "fresh-local-refresh-token",
accountId: "acct-local",
});
expectPersistedOpenAICodexProfile(
expectDefined(persisted.profiles[profileId], "persisted.profiles[profileId] test invariant"),
{
access: "fresh-local-access-token",
refresh: "fresh-local-refresh-token",
accountId: "acct-local",
},
);
const persistedProfile = requireOAuthProfile(persisted, profileId);
expect(persistedProfile.accountId).toBe("acct-local");
});
@@ -554,10 +564,13 @@ describe("resolveApiKeyForProfile openai refresh fallback", () => {
});
const persisted = await readPersistedStore(agentDir);
expectPersistedOpenAICodexProfile(persisted.profiles[profileId], {
access: "fresh-access-token",
refresh: "fresh-refresh-token",
});
expectPersistedOpenAICodexProfile(
expectDefined(persisted.profiles[profileId], "persisted.profiles[profileId] test invariant"),
{
access: "fresh-access-token",
refresh: "fresh-refresh-token",
},
);
});
it("does not use same-account Codex CLI credentials after forced local refresh fails", async () => {
@@ -1149,10 +1162,13 @@ describe("resolveApiKeyForProfile openai refresh fallback", () => {
expect(getOAuthApiKeyMock).toHaveBeenCalledTimes(2);
const persisted = await readPersistedStore(agentDir);
expectPersistedOpenAICodexProfile(persisted.profiles[profileId], {
access: "retried-access-token",
refresh: "retried-refresh-token",
});
expectPersistedOpenAICodexProfile(
expectDefined(persisted.profiles[profileId], "persisted.profiles[profileId] test invariant"),
{
access: "retried-access-token",
refresh: "retried-refresh-token",
},
);
});
it("keeps throwing for non-codex providers on the same refresh error", async () => {
@@ -2,6 +2,8 @@
* Regression coverage for process-local auth profile snapshots.
* Verifies snapshots are cloned and isolated across agent-specific stores.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it, vi } from "vitest";
import {
clearRuntimeAuthProfileStoreSnapshots,
@@ -58,15 +60,23 @@ describe("runtime auth profile snapshots", () => {
try {
const stored = createStore("access-1");
setRuntimeAuthProfileStoreSnapshot(stored, agentDir);
stored.profiles["openai:default"].provider = "mutated";
stored.order!["openai"].push("mutated");
expectDefined(
stored.profiles["openai:default"],
'stored.profiles["openai:default"] test invariant',
).provider = "mutated";
expectDefined(stored.order?.openai, "stored OpenAI profile order").push("mutated");
const first = getRuntimeAuthProfileStoreSnapshot(agentDir);
expectOpenAICodexSnapshotCredential(first, { access: "access-1" });
expect(first?.order?.["openai"]).toEqual(["openai:default"]);
first!.profiles["openai:default"].provider = "mutated-again";
first!.usageStats!["openai:default"].lastUsed = 99;
const firstSnapshot = expectDefined(first, "first auth profile snapshot");
expectDefined(firstSnapshot.profiles["openai:default"], "first OpenAI profile").provider =
"mutated-again";
expectDefined(
firstSnapshot.usageStats?.["openai:default"],
"first OpenAI usage stats",
).lastUsed = 99;
const second = getRuntimeAuthProfileStoreSnapshot(agentDir);
expectOpenAICodexSnapshotCredential(second, { access: "access-1" });
+2 -1
View File
@@ -4,6 +4,7 @@
* auto-review, and follow-up execution paths.
*/
import crypto from "node:crypto";
import { expectDefined } from "@openclaw/normalization-core";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ExecAllowlistEntry } from "../infra/exec-approvals.types.js";
import { MAX_SAFE_TIMEOUT_DELAY_MS } from "../utils/timer-delay.js";
@@ -288,7 +289,7 @@ const resolveNodeIdFromListMock = vi.hoisted(() =>
vi.fn((nodes: Array<{ nodeId: string; displayName?: string }>, query?: string) => {
if (!query) {
if (nodes.length === 1) {
return nodes[0].nodeId;
return expectDefined(nodes[0], "nodes[0] test invariant").nodeId;
}
throw new Error("node required");
}
+10 -2
View File
@@ -3,6 +3,8 @@
* Covers target resolution, cursor mode tracking, exit outcome classification,
* system events, and process lifecycle behavior.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { GatewayActiveWorkInspectors } from "../infra/gateway-active-work.js";
import type { RunExit } from "../process/supervisor/types.js";
@@ -872,7 +874,10 @@ describe("runExecProcess POSIX command wrapper", () => {
void ignoredRun;
expect(supervisorMock.spawn).toHaveBeenCalledTimes(1);
const spawnCall = supervisorMock.spawn.mock.calls[0][0];
const spawnCall = expectDefined(
supervisorMock.spawn.mock.calls[0],
"supervisorMock.spawn.mock.calls[0] test invariant",
)[0];
const commandStr = spawnCall.argv.join(" ");
expect(commandStr).toContain(
@@ -916,7 +921,10 @@ describe("runExecProcess POSIX command wrapper", () => {
void ignoredRun;
expect(supervisorMock.spawn).toHaveBeenCalledTimes(1);
const spawnCall = supervisorMock.spawn.mock.calls[0][0];
const spawnCall = expectDefined(
supervisorMock.spawn.mock.calls[0],
"supervisorMock.spawn.mock.calls[0] test invariant",
)[0];
const commandStr = spawnCall.argv.join(" ");
expect(commandStr).not.toContain("export PATH=");
@@ -3,6 +3,7 @@
* Verifies plugin-provided env values are filtered and forwarded to the chosen
* exec host without leaking unsafe overrides.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { OPENCLAW_CLI_ENV_VALUE } from "../infra/openclaw-exec-env.js";
import type { ExecuteNodeHostCommandParams } from "./bash-tools.exec-host-node.types.js";
@@ -403,7 +404,7 @@ describe("exec resolve_exec_env hook wiring", () => {
sessionKey: "agent:main:telegram:chat-1",
});
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-invalid-wrapped-cwd-before-hooks",
{
command: "echo ok",
@@ -449,7 +450,7 @@ describe("exec resolve_exec_env hook wiring", () => {
sessionKey: "agent:main:telegram:chat-1",
});
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-backend-cwd-vetoed-before-validation",
{
command: "echo ok",
@@ -498,7 +499,7 @@ describe("exec resolve_exec_env hook wiring", () => {
sessionKey: "agent:main:telegram:chat-1",
});
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-backend-invalid-cwd-before-env",
{
command: "echo ok",
@@ -552,7 +553,7 @@ describe("exec resolve_exec_env hook wiring", () => {
channelId: "ctx-channel",
});
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-backend-deferred-env-context",
{
command: "echo ok",
@@ -604,7 +605,7 @@ describe("exec resolve_exec_env hook wiring", () => {
channelId: "chat-1",
});
const result = await definition.execute(
const result = await expectDefined(definition, "definition test invariant").execute(
"call-invalid-lazy-cwd-before-hooks",
{
command: "echo ok",
@@ -667,7 +668,7 @@ describe("exec resolve_exec_env hook wiring", () => {
channelId: "chat-1",
});
await definition.execute(
await expectDefined(definition, "definition test invariant").execute(
"call-before",
{
command: "echo ok",
@@ -715,7 +716,7 @@ describe("exec resolve_exec_env hook wiring", () => {
channelId: "chat-1",
});
await definition.execute(
await expectDefined(definition, "definition test invariant").execute(
"call-lazy",
{
command: "echo ok",
@@ -761,7 +762,7 @@ describe("exec resolve_exec_env hook wiring", () => {
sessionKey: "agent:main:telegram:chat-1",
});
await definition.execute(
await expectDefined(definition, "definition test invariant").execute(
"call-host-rewrite",
{
command: "echo ok",
@@ -814,7 +815,7 @@ describe("exec resolve_exec_env hook wiring", () => {
sessionKey: "agent:main:telegram:chat-1",
});
await definition.execute(
await expectDefined(definition, "definition test invariant").execute(
"call-host-rewrite-with-remote-cwd",
{
command: "echo ok",
@@ -861,7 +862,7 @@ describe("exec resolve_exec_env hook wiring", () => {
sessionKey: "agent:main:telegram:chat-1",
});
await definition.execute(
await expectDefined(definition, "definition test invariant").execute(
"call-host-sanitize",
{
command: "echo ok",
@@ -927,7 +928,7 @@ describe("exec resolve_exec_env hook wiring", () => {
sessionKey: "agent:main:telegram:chat-1",
});
await definition.execute(
await expectDefined(definition, "definition test invariant").execute(
"call-command-rewrite",
{
env: { REQUEST_SAFE: "request" },
+5 -2
View File
@@ -3,6 +3,7 @@
* Exercises exec and process behavior through the shared exported tool factory.
*/
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { drainFormattedSystemEvents } from "../auto-reply/reply/session-system-events.js";
import type { OpenClawConfig } from "../config/config.js";
@@ -907,7 +908,9 @@ describe("exec PATH handling", () => {
expect(index).toBeGreaterThanOrEqual(0);
}
for (let i = 1; i < prependIndexes.length; i += 1) {
expect(prependIndexes[i]).toBeGreaterThan(prependIndexes[i - 1]);
expect(prependIndexes[i]).toBeGreaterThan(
expectDefined(prependIndexes[i - 1], "prependIndexes[i - 1] test invariant"),
);
}
const baseIndex = entries.indexOf(basePath);
expect(baseIndex).toBeGreaterThanOrEqual(0);
@@ -972,7 +975,7 @@ describe("applyPathPrepend with case-insensitive PATH key", () => {
const existingPath = existing.join(delim);
const env: Record<string, string> = { Path: existingPath };
applyPathPrepend(env, prepend);
const parts = env.Path.split(delim);
const parts = expectDefined(env.Path, "env.Path test invariant").split(delim);
expect(parts[0]).toBe(prepend[0]);
for (const entry of existing) {
expect(parts).toContain(entry);
+11 -2
View File
@@ -1,6 +1,7 @@
/** Tests agent bootstrap file discovery, filtering, and injected context modes. */
import fs from "node:fs/promises";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
clearInternalHooks,
@@ -298,7 +299,11 @@ describe("resolveBootstrapFilesForRun", () => {
["HEARTBEAT.md", "heartbeat"],
["BOOTSTRAP.md", "setup"],
].map(([fileName, content]) =>
fs.writeFile(path.join(workspaceDir, fileName), content, "utf8"),
fs.writeFile(
path.join(workspaceDir, expectDefined(fileName, "fileName test invariant")),
expectDefined(content, "content test invariant"),
"utf8",
),
),
);
@@ -323,7 +328,11 @@ describe("resolveBootstrapFilesForRun", () => {
["HEARTBEAT.md", "heartbeat"],
["BOOTSTRAP.md", "setup"],
].map(([fileName, content]) =>
fs.writeFile(path.join(workspaceDir, fileName), content, "utf8"),
fs.writeFile(
path.join(workspaceDir, expectDefined(fileName, "fileName test invariant")),
expectDefined(content, "content test invariant"),
"utf8",
),
),
);
+6 -1
View File
@@ -1,4 +1,6 @@
/** Tests BTW side-question execution, session context, auth, and harness routing. */
import { expectDefined } from "@openclaw/normalization-core";
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { SessionEntry } from "../config/sessions.js";
@@ -2245,7 +2247,10 @@ describe("runBtwSideQuestion", () => {
const [message] = contextMessages(streamContext());
expectRecordFields(message, { role: "user" });
expectTextBlockContains(
(message.content as Array<unknown>)[0],
expectDefined(
(expectDefined(message, "message test invariant").content as Array<unknown>)[0],
"(message.content as Array<unknown>)[0] test invariant",
),
"<in_flight_main_task>\nbuild me a tic-tac-toe game in brainfuck\n</in_flight_main_task>",
);
});
+3 -1
View File
@@ -1,4 +1,6 @@
/** Tests CLI backend config resolution, normalization, and live-test defaults. */
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import type { CliBackendConfig } from "../config/types.js";
@@ -166,7 +168,7 @@ function normalizeTestClaudeArgs(
let hasSettingSources = false;
let hasPermissionMode = false;
for (let i = 0; i < args.length; i += 1) {
const arg = args[i];
const arg = expectDefined(args[i], "args[i] test invariant");
if (arg === "--dangerously-skip-permissions") {
continue;
}
@@ -1,4 +1,6 @@
/** Tests cron before_agent_reply gating at the CLI runner entrypoint. */
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
import type { CliOutput } from "./cli-output.js";
@@ -338,7 +340,10 @@ describe("runCliAgent cron before_agent_reply seam", () => {
expect(executePreparedCliRunMock).toHaveBeenCalledTimes(1);
expect(closeClaudeLiveSessionForContextMock).toHaveBeenCalledTimes(1);
expect(closeClaudeLiveSessionForContextMock).toHaveBeenCalledWith(
await prepareCliRunContextMock.mock.results[0].value,
await expectDefined(
prepareCliRunContextMock.mock.results[0],
"prepareCliRunContextMock.mock.results[0] test invariant",
).value,
);
});
+11 -6
View File
@@ -4,6 +4,7 @@ import os from "node:os";
import path from "node:path";
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "@openclaw/ai/internal/shared";
import { MAX_IMAGE_BYTES } from "@openclaw/media-core/constants";
import { expectDefined } from "@openclaw/normalization-core";
import type { ImageContent } from "openclaw/plugin-sdk/llm";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createSolidPngBuffer } from "../../test/helpers/image-fixtures.js";
@@ -258,9 +259,11 @@ describe("writeCliImages", () => {
),
]);
expect(second.paths).toEqual(first.paths);
await expect(fs.readFile(first.paths[0])).resolves.toEqual(Buffer.from(image.data, "base64"));
await expect(
fs.readFile(expectDefined(first.paths[0], "first.paths[0] test invariant")),
).resolves.toEqual(Buffer.from(image.data, "base64"));
} finally {
await fs.rm(first.paths[0], { force: true });
await fs.rm(expectDefined(first.paths[0], "first.paths[0] test invariant"), { force: true });
await fs.rm(workspaceDir, { recursive: true, force: true });
}
});
@@ -284,7 +287,9 @@ describe("writeCliImages", () => {
try {
expect(written.paths[0]).toMatch(/\.heic$/);
} finally {
await fs.rm(written.paths[0], { force: true });
await fs.rm(expectDefined(written.paths[0], "written.paths[0] test invariant"), {
force: true,
});
await fs.rm(workspaceDir, { recursive: true, force: true });
}
});
@@ -317,9 +322,9 @@ describe("writeCliImages", () => {
try {
await expect(fs.access(stalePath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(fs.readFile(freshPath, "utf-8")).resolves.toBe("fresh");
await expect(fs.readFile(written.paths[0])).resolves.toEqual(
Buffer.from(image.data, "base64"),
);
await expect(
fs.readFile(expectDefined(written.paths[0], "written.paths[0] test invariant")),
).resolves.toEqual(Buffer.from(image.data, "base64"));
} finally {
await fs.rm(workspaceDir, { recursive: true, force: true });
}
+10 -3
View File
@@ -2,6 +2,7 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createSolidPngBuffer } from "../../test/helpers/image-fixtures.js";
import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js";
@@ -683,8 +684,12 @@ describe("runCliAgent reliability", () => {
: [],
);
expect(imagePaths).toHaveLength(2);
expect(fs.readFileSync(imagePaths[0])).toEqual(offloadedImage);
expect(fs.readFileSync(imagePaths[1])).toEqual(inlineImage);
expect(fs.readFileSync(expectDefined(imagePaths[0], "imagePaths[0] test invariant"))).toEqual(
offloadedImage,
);
expect(fs.readFileSync(expectDefined(imagePaths[1], "imagePaths[1] test invariant"))).toEqual(
inlineImage,
);
expect(argv.includes("resume")).toBe(index === 0);
expect(argv.includes("stale-cli-session")).toBe(index === 0);
}
@@ -3814,7 +3819,9 @@ describe("runCliAgent reliability", () => {
expect(JSON.stringify(hookRunner.runAgentEnd.mock.calls)).not.toContain("secret prompt");
const lines = fs.readFileSync(sessionFile, "utf-8").trim().split("\n");
const blockedLine = JSON.parse(lines[lines.length - 1]);
const blockedLine = JSON.parse(
expectDefined(lines[lines.length - 1], "lines[lines.length - 1] test invariant"),
);
expect(blockedLine.message.content[0].text).toBe(
"Your message could not be sent: The agent cannot read this message. (blocked by policy-plugin)",
);
+5 -1
View File
@@ -2,6 +2,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
testing as replyRunTesting,
@@ -1063,7 +1064,10 @@ describe("runCliAgent spawn path", () => {
const input = (args[0] ?? {}) as { argv?: string[] };
const configArg = requireArgAfter(input.argv, "-c");
const match = requireRegexMatch(configArg, /^model_instructions_file="(.+)"$/);
promptFileText = await fs.readFile(match[1], "utf-8");
promptFileText = await fs.readFile(
expectDefined(match[1], "match[1] test invariant"),
"utf-8",
);
return createManagedRun({
reason: "exit",
exitCode: 0,
+5 -1
View File
@@ -4,6 +4,7 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "@openclaw/ai/internal/shared";
import { expectDefined } from "@openclaw/normalization-core";
import { CURRENT_SESSION_VERSION } from "openclaw/plugin-sdk/agent-sessions";
import { Type } from "typebox";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
@@ -3414,7 +3415,10 @@ describe("shouldSkipLocalCliCredentialEpoch", () => {
native: [],
mcp: ["mcp__openclaw__crestodian"],
});
const mcpConfigPath = args[args.indexOf("--mcp-config") + 1];
const mcpConfigPath = expectDefined(
args[args.indexOf("--mcp-config") + 1],
'args[args.indexOf("--mcp-config") + 1] test invariant',
);
const raw = JSON.parse(fs.readFileSync(mcpConfigPath, "utf-8")) as {
mcpServers?: Record<string, { env?: Record<string, string> }>;
};
+203 -120
View File
@@ -1,4 +1,6 @@
/** Tests Code Mode tool registration, namespace filtering, and run lifecycle. */
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { isRecord } from "../../packages/normalization-core/src/record-coerce.js";
import { setPluginToolMeta } from "../plugins/tools.js";
@@ -304,8 +306,10 @@ describe("Code Mode", () => {
it("marks only the internal wait control as hidden from channel progress", () => {
const { tools } = createCodeModeHarness();
expect(tools[0].hideFromChannelProgress).toBeUndefined();
expect(tools[1].hideFromChannelProgress).toBe(true);
expect(
expectDefined(tools[0], "tools[0] test invariant").hideFromChannelProgress,
).toBeUndefined();
expect(expectDefined(tools[1], "tools[1] test invariant").hideFromChannelProgress).toBe(true);
});
it("tells models to return the final code value", () => {
@@ -358,7 +362,7 @@ describe("Code Mode", () => {
it("uses a flat enum for the exec language schema", () => {
const { tools } = createCodeModeHarness();
const parameters = tools[0].parameters as {
const parameters = expectDefined(tools[0], "tools[0] test invariant").parameters as {
properties?: Record<string, Record<string, unknown>>;
};
const language = parameters.properties?.language;
@@ -373,7 +377,7 @@ describe("Code Mode", () => {
it("describes code-mode runtime constraints in the model-visible exec schema", () => {
const { tools } = createCodeModeHarness();
const execTool = tools[0];
const execTool = expectDefined(tools[0], "tools[0] test invariant");
const parameters = execTool.parameters as {
properties?: Record<string, Record<string, unknown>>;
};
@@ -539,7 +543,7 @@ describe("Code Mode", () => {
});
await expect(
tools[0].execute("code-call-bad-path", {
expectDefined(tools[0], "tools[0] test invariant").execute("code-call-bad-path", {
code: "return 1;",
}),
).rejects.toThrow("Invalid code mode namespace path segment: constructor");
@@ -556,7 +560,7 @@ describe("Code Mode", () => {
});
await expect(
tools[0].execute("code-call-circular", {
expectDefined(tools[0], "tools[0] test invariant").execute("code-call-circular", {
code: "return 1;",
}),
).rejects.toThrow("Circular code mode namespace scope at self");
@@ -573,7 +577,7 @@ describe("Code Mode", () => {
});
await expect(
tools[0].execute("code-call-raw-function", {
expectDefined(tools[0], "tools[0] test invariant").execute("code-call-raw-function", {
code: "return 1;",
}),
).rejects.toThrow("must be created with createCodeModeNamespaceTool");
@@ -600,8 +604,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: 'return { global: typeof Hidden, mapped: "Hidden" in namespaces };',
});
@@ -633,8 +637,8 @@ describe("Code Mode", () => {
expect(compacted.tools[0]?.description).not.toContain("Hidden: Hidden helpers.");
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: 'return { global: typeof Hidden, mapped: "Hidden" in namespaces };',
});
@@ -667,8 +671,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
const left = await Shared.left.read();
const right = await Shared.right.read();
@@ -707,8 +711,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
globalThis.__openclawHostRequest("namespace", JSON.stringify(["leaky", ["hidden"], []]));
await yield_control("pause");
@@ -757,7 +761,7 @@ describe("Code Mode", () => {
catalogRef,
});
const result = resultDetails(
await tools[0].execute("code-call-command-alias", {
await expectDefined(tools[0], "tools[0] test invariant").execute("code-call-command-alias", {
command: "return 7;",
}),
);
@@ -778,7 +782,7 @@ describe("Code Mode", () => {
});
await expect(
tools[0].execute("code-call-divergent-alias", {
expectDefined(tools[0], "tools[0] test invariant").execute("code-call-divergent-alias", {
code: "return 1;",
command: "return 2;",
}),
@@ -798,8 +802,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
const hits = await tools.search("ticket", { limit: 1 });
const described = await tools.describe(hits[0].id);
@@ -831,8 +835,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
try {
await tools.call("file_write", {
@@ -865,8 +869,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
try {
await tools.call("missing_tool", {});
@@ -913,8 +917,8 @@ describe("Code Mode", () => {
expect(compacted.tools[0]?.description).toContain("visible servers: github");
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
const rootApi = await MCP.$api();
const api = await MCP.github.$api("createIssue", { schema: true });
@@ -1046,8 +1050,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
const files = await API.list("mcp");
const api = await API.read("mcp/github.d.ts");
@@ -1120,8 +1124,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
const api = await MCP.docs.$api();
const resource = await MCP.docs.resources.read({ uri: "memo://one" });
@@ -1168,8 +1172,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: 'return (await MCP.constructor2.prototype2({ value: "safe" })).details;',
});
@@ -1228,8 +1232,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
const direct = await Tickets.issues.list({ state: "open" });
const mapped = await namespaces.Tickets.issues.list({ state: "closed" });
@@ -1288,8 +1292,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: 'return await Owned.list({ value: "safe" });',
});
@@ -1340,8 +1344,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: "return await Context.read();",
});
@@ -1379,8 +1383,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
try {
await Broken.fail();
@@ -1407,15 +1411,18 @@ describe("Code Mode", () => {
});
const first = resultDetails(
await codeModeTools[0].execute("code-call-yield", {
restartSafe: true,
code: `
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-yield",
{
restartSafe: true,
code: `
text("before");
await yield_control("pause");
text("after");
return "done";
`,
}),
},
),
);
expect(first.status).toBe("waiting");
@@ -1425,7 +1432,12 @@ describe("Code Mode", () => {
const runId = first.runId;
expect(typeof runId).toBe("string");
const resumed = resultDetails(await codeModeTools[1].execute("code-wait-yield", { runId }));
const resumed = resultDetails(
await expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-yield",
{ runId },
),
);
expect(resumed.status).toBe("completed");
expect(resumed.value).toBe("done");
@@ -1448,27 +1460,36 @@ describe("Code Mode", () => {
});
const first = resultDetails(
await codeModeTools[0].execute("code-call-replay-safety", {
restartSafe: true,
code: `
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-replay-safety",
{
restartSafe: true,
code: `
const matches = await tools.search(${JSON.stringify(targetTool.name)});
return await tools.call(matches[0].id, {});
`,
}),
},
),
);
expect(first.status).toBe("waiting");
expect(first.replaySafe).toBe(true);
const second = resultDetails(
await codeModeTools[1].execute("code-wait-replay-safety", { runId: first.runId }),
await expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-replay-safety",
{ runId: first.runId },
),
);
expect(second.status).toBe("waiting");
expect(second.replaySafe).toBe(true);
const completed = resultDetails(
await codeModeTools[1].execute("code-wait-replay-safety-complete", {
runId: second.runId,
}),
await expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-replay-safety-complete",
{
runId: second.runId,
},
),
);
expect(completed.status).toBe("completed");
});
@@ -1491,8 +1512,8 @@ describe("Code Mode", () => {
});
const completed = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
restartSafe: true,
code: `
const matches = await tools.search("fake_plugin_read");
@@ -1533,8 +1554,8 @@ describe("Code Mode", () => {
});
const completed = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
restartSafe: true,
code: 'return await MCP.github.readFile({ path: "README.md" });',
});
@@ -1558,19 +1579,25 @@ describe("Code Mode", () => {
});
const first = resultDetails(
await codeModeTools[0].execute("code-call-unsafe-restart", {
restartSafe: true,
code: `
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-unsafe-restart",
{
restartSafe: true,
code: `
const matches = await tools.search("fake_write");
return await tools.call(matches[0].id, {});
`,
}),
},
),
);
expect(first.status).toBe("waiting");
expect(first.replaySafe).toBe(true);
const failed = resultDetails(
await codeModeTools[1].execute("code-wait-unsafe-restart", { runId: first.runId }),
await expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-unsafe-restart",
{ runId: first.runId },
),
);
expect(failed.status).toBe("failed");
expect(failed.error).toContain("cannot call side-effecting tools");
@@ -1596,19 +1623,25 @@ describe("Code Mode", () => {
});
const first = resultDetails(
await codeModeTools[0].execute("code-call-forced-restart", {
restartSafe: false,
code: `
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-forced-restart",
{
restartSafe: false,
code: `
const matches = await tools.search("fake_forced_write");
return await tools.call(matches[0].id, {});
`,
}),
},
),
);
expect(first.status).toBe("waiting");
expect(first.replaySafe).toBe(true);
const failed = resultDetails(
await codeModeTools[1].execute("code-wait-forced-restart", { runId: first.runId }),
await expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-forced-restart",
{ runId: first.runId },
),
);
expect(failed.status).toBe("failed");
expect(failed.error).toContain("cannot call side-effecting tools");
@@ -1629,9 +1662,12 @@ describe("Code Mode", () => {
let details: Record<string, unknown>;
try {
details = resultDetails(
await codeModeTools[0].execute("code-call-yield-overflow", {
code: 'await yield_control("pause"); return "done";',
}),
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-yield-overflow",
{
code: 'await yield_control("pause"); return "done";',
},
),
);
} finally {
nowSpy.mockRestore();
@@ -1649,7 +1685,10 @@ describe("Code Mode", () => {
} as never);
await expect(
codeModeTools[1].execute("code-wait-invalid-expiry", { runId: "invalid-expiry-run" }),
expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-invalid-expiry",
{ runId: "invalid-expiry-run" },
),
).rejects.toThrow("code mode run is unavailable or expired");
expect(testing.activeRuns.has("invalid-expiry-run")).toBe(false);
});
@@ -1666,19 +1705,25 @@ describe("Code Mode", () => {
});
const first = resultDetails(
await codeModeTools[0].execute("code-call-wrong-session", {
code: 'await yield_control("pause"); return "done";',
}),
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-wrong-session",
{
code: 'await yield_control("pause"); return "done";',
},
),
);
expect(first.status).toBe("waiting");
const otherWaitTool = createCodeModeTools({
config,
runtimeConfig: config,
sessionId: "other-session",
sessionKey: "agent:other:main",
runId: "run-code-mode",
catalogRef,
})[1];
const otherWaitTool = expectDefined(
createCodeModeTools({
config,
runtimeConfig: config,
sessionId: "other-session",
sessionKey: "agent:other:main",
runId: "run-code-mode",
catalogRef,
})[1],
'createCodeModeTools({ config, runtimeConfig: config, sessionId: "othe... test invariant',
);
await expect(
otherWaitTool.execute("code-wait-wrong-session", { runId: first.runId }),
@@ -1721,17 +1766,26 @@ describe("Code Mode", () => {
});
const first = resultDetails(
await codeModeTools[0].execute("code-call-concurrent-wait", {
code: "await tools.fake_slow({}); return 'done';",
}),
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-concurrent-wait",
{
code: "await tools.fake_slow({}); return 'done';",
},
),
);
expect(first.status).toBe("waiting");
const firstWait = codeModeTools[1].execute("code-wait-concurrent-a", {
runId: first.runId,
});
const firstWait = expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-concurrent-a",
{
runId: first.runId,
},
);
await expect(
codeModeTools[1].execute("code-wait-concurrent-b", { runId: first.runId }),
expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-concurrent-b",
{ runId: first.runId },
),
).rejects.toThrow("already being resumed");
const stillWaiting = resultDetails(await firstWait);
@@ -1776,15 +1830,18 @@ describe("Code Mode", () => {
});
const first = resultDetails(
await codeModeTools[0].execute("code-call-timeout", {
code: `
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-timeout",
{
code: `
const fast = tools.fake_fast({});
const slow = tools.fake_slow({});
await fast;
await slow;
return "done";
`,
}),
},
),
);
expect(first.status).toBe("waiting");
expect(first.pendingToolCalls).toHaveLength(2);
@@ -1798,7 +1855,12 @@ describe("Code Mode", () => {
expect(activeRun).toBeDefined();
activeRun!.config.timeoutMs = 100;
const second = resultDetails(await codeModeTools[1].execute("code-wait-timeout", { runId }));
const second = resultDetails(
await expectDefined(codeModeTools[1], "codeModeTools[1] test invariant").execute(
"code-wait-timeout",
{ runId },
),
);
expect(second.status).toBe("waiting");
expect(second.pendingToolCalls).toEqual([expect.objectContaining({ method: "call" })]);
@@ -1816,8 +1878,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: "return 42;",
});
@@ -1838,8 +1900,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: `
const important = 41;
const message = "import docs later";
@@ -1864,9 +1926,12 @@ describe("Code Mode", () => {
const beforeRunCount = testing.activeRuns.size;
const details = resultDetails(
await codeModeTools[0].execute("code-call-empty-wait", {
code: "await new Promise(() => undefined); return 'never';",
}),
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-empty-wait",
{
code: "await new Promise(() => undefined); return 'never';",
},
),
);
expect(details.status).toBe("failed");
@@ -1886,7 +1951,10 @@ describe("Code Mode", () => {
});
const details = resultDetails(
await codeModeTools[0].execute("code-call-syntax", { code: "const x = ;" }),
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-syntax",
{ code: "const x = ;" },
),
);
expect(details.status).toBe("failed");
@@ -1911,7 +1979,10 @@ describe("Code Mode", () => {
});
const details = resultDetails(
await codeModeTools[0].execute("code-call-runtime", { code: "return missingFn();" }),
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-runtime",
{ code: "return missingFn();" },
),
);
expect(details.status).toBe("failed");
@@ -1933,9 +2004,12 @@ describe("Code Mode", () => {
});
const details = resultDetails(
await codeModeTools[0].execute("code-call-host-error", {
code: 'return globalThis.__openclawHostRequest("unsupported", "[]");',
}),
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-host-error",
{
code: 'return globalThis.__openclawHostRequest("unsupported", "[]");',
},
),
);
expect(details).toMatchObject({
@@ -1980,8 +2054,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
code: 'const hits = await tools.search("ticket"); return hits.length;',
});
@@ -2012,8 +2086,8 @@ describe("Code Mode", () => {
});
const details = await runUntilCompleted({
execTool: codeModeTools[0],
waitTool: codeModeTools[1],
execTool: expectDefined(codeModeTools[0], "codeModeTools[0] test invariant"),
waitTool: expectDefined(codeModeTools[1], "codeModeTools[1] test invariant"),
language: "typescript",
code: `
const value: number = 40 + 2;
@@ -2042,9 +2116,12 @@ describe("Code Mode", () => {
});
const details = resultDetails(
await codeModeTools[0].execute("code-call-import", {
code,
}),
await expectDefined(codeModeTools[0], "codeModeTools[0] test invariant").execute(
"code-call-import",
{
code,
},
),
);
expect(details.status).toBe("failed");
@@ -2080,7 +2157,7 @@ describe("Code Mode", () => {
});
const details = resultDetails(
await tools[0].execute("code-call-large", {
await expectDefined(tools[0], "tools[0] test invariant").execute("code-call-large", {
code: "return 'x'.repeat(2048);",
}),
);
@@ -2120,7 +2197,7 @@ describe("Code Mode", () => {
const beforeRunCount = testing.activeRuns.size;
const details = resultDetails(
await tools[0].execute("code-call-large-suspend", {
await expectDefined(tools[0], "tools[0] test invariant").execute("code-call-large-suspend", {
code: "text('x'.repeat(2048)); await yield_control('pause'); return 1;",
}),
);
@@ -2172,9 +2249,12 @@ describe("Code Mode", () => {
});
const details = resultDetails(
await tools[0].execute("code-call-large-namespace", {
code: 'text("x".repeat(2048)); await Tickets.list({ state: "open" }); return 1;',
}),
await expectDefined(tools[0], "tools[0] test invariant").execute(
"code-call-large-namespace",
{
code: 'text("x".repeat(2048)); await Tickets.list({ state: "open" }); return 1;',
},
),
);
expect(details.status).toBe("failed");
@@ -2195,9 +2275,12 @@ describe("Code Mode", () => {
});
const details = resultDetails(
await tools[0].execute("code-call-output-before-error", {
code: 'text("before"); throw new Error("boom");',
}),
await expectDefined(tools[0], "tools[0] test invariant").execute(
"code-call-output-before-error",
{
code: 'text("before"); throw new Error("boom");',
},
),
);
expect(details.status).toBe("failed");
@@ -2257,7 +2340,7 @@ describe("Code Mode", () => {
const heartbeat = Promise.resolve("main-event-loop-alive");
const details = resultDetails(
await tools[0].execute("code-call-loop", {
await expectDefined(tools[0], "tools[0] test invariant").execute("code-call-loop", {
code: "while (true) {}",
}),
);
@@ -1,5 +1,7 @@
// Covers session-message sanitization for empty blocks, tool ids, and
// thought-signature replay rules.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import type { AssistantMessage, ToolResultMessage, UserMessage } from "openclaw/plugin-sdk/llm";
import { describe, expect, it } from "vitest";
@@ -67,13 +69,13 @@ function makeOpenAiResponsesAssistantMessage(
function expectToolCallAndResultIds(out: AgentMessage[], expectedId: string) {
// Tool call and result ids must stay in lockstep or replayed transcripts break
// provider tool-result matching.
const assistant = out[0];
const assistant = expectDefined(out[0], "out[0] test invariant");
expect(assistant.role).toBe("assistant");
const assistantContent = assistant.role === "assistant" ? assistant.content : [];
const toolCall = assistantContent.find((block) => block.type === "toolCall");
expect(toolCall?.id).toBe(expectedId);
const toolResult = out[1];
const toolResult = expectDefined(out[1], "out[1] test invariant");
expect(toolResult.role).toBe("toolResult");
if (toolResult.role === "toolResult") {
expect(toolResult.toolCallId).toBe(expectedId);
@@ -2,6 +2,8 @@
* Regression coverage for user-facing text sanitization.
* Includes reasoning/tool-call cleanup and internal event prompt formatting.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import {
downgradeOpenAIFunctionCallReasoningPairs,
@@ -689,8 +691,8 @@ describe("stripThoughtSignatures", () => {
thinking: "test",
thought_signature: "AQID",
});
expect("thought_signature" in result[0]).toBe(false);
expect("thought_signature" in result[1]).toBe(true);
expect("thought_signature" in expectDefined(result[0], "result[0] test invariant")).toBe(false);
expect("thought_signature" in expectDefined(result[1], "result[1] test invariant")).toBe(true);
});
it("preserves blocks without thought_signature", () => {
const input = [
@@ -1,4 +1,6 @@
// Covers provider-specific transcript turn validation and repair.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it } from "vitest";
import {
@@ -284,7 +286,7 @@ describe("validateAnthropicTurns", () => {
const result = validateAnthropicTurns(msgs) as Extract<AgentMessage, { role: "user" }>[];
expect(result).toHaveLength(1);
const merged = result[0];
const merged = expectDefined(result[0], "merged user message");
expect(merged.timestamp).toBe(2000);
expect((merged as { attachments?: unknown[] }).attachments).toEqual([
{ type: "image", url: "new.png" },
@@ -315,7 +317,7 @@ describe("validateAnthropicTurns", () => {
]);
const [merged] = validateAnthropicTurns(msgs) as Extract<AgentMessage, { role: "user" }>[];
expect(merged.content).toEqual([
expect(expectDefined(merged, "merged test invariant").content).toEqual([
{ type: "text", text: "first" },
{ type: "image", url: "img1" },
{ type: "image", url: "img2" },
@@ -1,4 +1,6 @@
// Covers Moonshot-specific extra-params thinking payload behavior.
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
createMoonshotThinkingWrapper,
@@ -228,7 +230,7 @@ describe("applyExtraParamsToAgent Moonshot", () => {
expect(payload).not.toHaveProperty("presence_penalty");
expect(payload).not.toHaveProperty("frequency_penalty");
const messages = payload.messages as Array<Record<string, unknown>>;
expect(messages[0].reasoning_content).toBe("");
expect(expectDefined(messages[0], "messages[0] test invariant").reasoning_content).toBe("");
});
it("repairs only missing assistant tool-call reasoning_content when thinking is enabled", () => {
@@ -261,8 +263,10 @@ describe("applyExtraParamsToAgent Moonshot", () => {
expect(payload.thinking).toEqual({ type: "enabled" });
const messages = payload.messages as Array<Record<string, unknown>>;
expect(messages[1].reasoning_content).toBe("");
expect(messages[2].reasoning_content).toBe("native reasoning");
expect(expectDefined(messages[1], "messages[1] test invariant").reasoning_content).toBe("");
expect(expectDefined(messages[2], "messages[2] test invariant").reasoning_content).toBe(
"native reasoning",
);
expect(messages[3]).not.toHaveProperty("reasoning_content");
});
@@ -284,6 +288,8 @@ describe("applyExtraParamsToAgent Moonshot", () => {
});
const messages = payload.messages as Array<Record<string, unknown>>;
expect(messages[0].reasoning_content).toBeUndefined();
expect(
expectDefined(messages[0], "messages[0] test invariant").reasoning_content,
).toBeUndefined();
});
});
@@ -1,4 +1,6 @@
// Covers delayed flushing of pending tool results after agent idle.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
import { afterEach, describe, expect, it, vi } from "vitest";
@@ -99,7 +101,7 @@ describe("flushPendingToolResultsAfterIdle", () => {
const entries = getMessages(sm);
expect(entries.length).toBe(2);
expect(entries[1].role).toBe("toolResult");
expect(expectDefined(entries[1], "entries[1] test invariant").role).toBe("toolResult");
expect((entries[1] as { isError?: boolean }).isError).toBe(true);
expect((entries[1] as { content?: Array<{ text?: string }> }).content?.[0]?.text).toContain(
"missing tool result",
@@ -1,4 +1,6 @@
// Covers limiting persisted history by recent user turns.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it } from "vitest";
import { limitHistoryTurns } from "./embedded-agent-runner/history.js";
@@ -97,15 +99,15 @@ describe("limitHistoryTurns", () => {
const messages = makeMessages(["user", "assistant", "user", "assistant", "user", "assistant"]);
const limited = limitHistoryTurns(messages, 2);
expect(limited.length).toBe(4);
expect(firstText(limited[0])).toBe("message 2");
expect(firstText(expectDefined(limited[0], "limited[0] test invariant"))).toBe("message 2");
});
it("handles single user turn limit", () => {
const messages = makeMessages(["user", "assistant", "user", "assistant", "user", "assistant"]);
const limited = limitHistoryTurns(messages, 1);
expect(limited.length).toBe(2);
expect(firstText(limited[0])).toBe("message 4");
expect(firstText(limited[1])).toBe("message 5");
expect(firstText(expectDefined(limited[0], "limited[0] test invariant"))).toBe("message 4");
expect(firstText(expectDefined(limited[1], "limited[1] test invariant"))).toBe("message 5");
});
it("handles messages with multiple assistant responses per user turn", () => {
@@ -114,8 +116,8 @@ describe("limitHistoryTurns", () => {
const messages = makeMessages(["user", "assistant", "assistant", "user", "assistant"]);
const limited = limitHistoryTurns(messages, 1);
expect(limited.length).toBe(2);
expect(limited[0].role).toBe("user");
expect(limited[1].role).toBe("assistant");
expect(expectDefined(limited[0], "limited[0] test invariant").role).toBe("user");
expect(expectDefined(limited[1], "limited[1] test invariant").role).toBe("assistant");
});
it("preserves leading compactionSummary when limiting", () => {
@@ -133,8 +135,8 @@ describe("limitHistoryTurns", () => {
const limited = limitHistoryTurns(messages, 1);
// compactionSummary is preserved, last 1 user turn + assistant kept
expect(limited.length).toBe(3);
expect(limited[0].role).toBe("compactionSummary");
expect(firstText(limited[1])).toBe("message 2");
expect(expectDefined(limited[0], "limited[0] test invariant").role).toBe("compactionSummary");
expect(firstText(expectDefined(limited[1], "limited[1] test invariant"))).toBe("message 2");
});
it("preserves leading branchSummary when limiting", () => {
@@ -147,7 +149,7 @@ describe("limitHistoryTurns", () => {
const messages = [branchSummary, ...makeMessages(["user", "assistant", "user", "assistant"])];
const limited = limitHistoryTurns(messages, 1);
expect(limited.length).toBe(3);
expect(limited[0].role).toBe("branchSummary");
expect(expectDefined(limited[0], "limited[0] test invariant").role).toBe("branchSummary");
});
it("returns all when only non-conversation messages exist", () => {
@@ -159,7 +161,7 @@ describe("limitHistoryTurns", () => {
} as AgentMessage;
const limited = limitHistoryTurns([compactionSummary], 2);
expect(limited).toHaveLength(1);
expect(limited[0].role).toBe("compactionSummary");
expect(expectDefined(limited[0], "limited[0] test invariant").role).toBe("compactionSummary");
});
it("preserves message content integrity", () => {
@@ -171,7 +173,7 @@ describe("limitHistoryTurns", () => {
assistantTextMessage("response"),
];
const limited = limitHistoryTurns(messages, 1);
expect(firstText(limited[0])).toBe("second");
expect(firstText(limited[1])).toBe("response");
expect(firstText(expectDefined(limited[0], "limited[0] test invariant"))).toBe("second");
expect(firstText(expectDefined(limited[1], "limited[1] test invariant"))).toBe("response");
});
});
@@ -1,4 +1,6 @@
// Hook integration coverage for direct and queued embedded compaction.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { beforeAll, beforeEach, describe, expect, it, vi, type Mock } from "vitest";
import { createReplyOperation } from "../../auto-reply/reply/reply-run-registry.js";
@@ -791,7 +793,10 @@ describe("compactEmbeddedAgentSessionDirect hooks", () => {
"compaction system prompt",
);
expect(createdSession.session.setActiveToolsByName.mock.invocationCallOrder[0]).toBeLessThan(
createdSession.session.setBaseSystemPrompt.mock.invocationCallOrder[0],
expectDefined(
createdSession.session.setBaseSystemPrompt.mock.invocationCallOrder[0],
"createdSession.session.setBaseSystemPrompt.mock.invocationCallOrder[0] test invariant",
),
);
});
@@ -2066,7 +2071,7 @@ describe("compactEmbeddedAgentSessionDirect hooks", () => {
] as AgentMessage[];
expect(
compactTesting.hasRealConversationContent(
heartbeatToolResultWindow[1],
expectDefined(heartbeatToolResultWindow[1], "heartbeatToolResultWindow[1] test invariant"),
heartbeatToolResultWindow,
1,
),
@@ -2084,7 +2089,7 @@ describe("compactEmbeddedAgentSessionDirect hooks", () => {
] as AgentMessage[];
expect(
compactTesting.hasRealConversationContent(
realAskToolResultWindow[2],
expectDefined(realAskToolResultWindow[2], "realAskToolResultWindow[2] test invariant"),
realAskToolResultWindow,
2,
),
@@ -2111,8 +2116,20 @@ describe("compactEmbeddedAgentSessionDirect hooks", () => {
},
] as AgentMessage[];
expect(compactTesting.hasRealConversationContent(messages[0], messages, 0)).toBe(true);
expect(compactTesting.hasRealConversationContent(messages[2], messages, 2)).toBe(true);
expect(
compactTesting.hasRealConversationContent(
expectDefined(messages[0], "messages[0] test invariant"),
messages,
0,
),
).toBe(true);
expect(
compactTesting.hasRealConversationContent(
expectDefined(messages[2], "messages[2] test invariant"),
messages,
2,
),
).toBe(true);
});
it("registers the Ollama api provider before compaction", () => {
@@ -3468,7 +3485,10 @@ describe("compactEmbeddedAgentSession hooks (ownsCompaction engine)", () => {
{ nativeCompactionRequest: "after_context_engine" },
);
expect(contextEngineCompactMock.mock.invocationCallOrder[0]).toBeLessThan(
maybeCompactAgentHarnessSessionMock.mock.invocationCallOrder[0],
expectDefined(
maybeCompactAgentHarnessSessionMock.mock.invocationCallOrder[0],
"maybeCompactAgentHarnessSessionMock.mock.invocationCallOrder[0] test invariant",
),
);
const details = result.result?.details as
| { codexNativeCompaction?: Record<string, unknown> }
@@ -1,4 +1,6 @@
// Coverage for deferred context-engine maintenance and transcript rewrite hooks.
import { expectDefined } from "@openclaw/normalization-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ContextEngineRuntimeContext } from "../../context-engine/types.js";
import { peekSystemEvents, resetSystemEventsForTest } from "../../infra/system-events.js";
@@ -686,9 +688,14 @@ describe("runContextEngineMaintenance", () => {
});
await waitForAssertion(() =>
expect(getTaskById(queuedTasks[0].taskId)?.status).toBe("succeeded"),
expect(
getTaskById(expectDefined(queuedTasks[0], "queuedTasks[0] test invariant").taskId)
?.status,
).toBe("succeeded"),
);
const completedTask = getTaskById(
expectDefined(queuedTasks[0], "queuedTasks[0] test invariant").taskId,
);
const completedTask = getTaskById(queuedTasks[0].taskId);
const completedTaskRecord = requireRecord(completedTask, "completed task");
expect(completedTaskRecord.status).toBe("succeeded");
expect(String(completedTaskRecord.progressSummary)).toContain(
@@ -853,7 +860,10 @@ describe("runContextEngineMaintenance", () => {
});
expect(deferredPromises).toHaveLength(2);
let secondDeferredSettled = false;
const secondDeferred = deferredPromises[1].then(() => {
const secondDeferred = expectDefined(
deferredPromises[1],
"deferredPromises[1] test invariant",
).then(() => {
secondDeferredSettled = true;
});
@@ -1511,9 +1521,14 @@ describe("runContextEngineMaintenance", () => {
);
expect(tasks).toHaveLength(1);
await waitForAssertion(() =>
expect(getTaskById(tasks[0].taskId)?.status).toBe("succeeded"),
expect(
getTaskById(expectDefined(tasks[0], "tasks[0] test invariant").taskId)?.status,
).toBe("succeeded"),
);
const task = requireRecord(
getTaskById(expectDefined(tasks[0], "tasks[0] test invariant").taskId),
"maintenance task",
);
const task = requireRecord(getTaskById(tasks[0].taskId), "maintenance task");
expectRecordFields(task, {
status: "succeeded",
notifyPolicy: "silent",
@@ -1,4 +1,6 @@
// Coverage for OpenRouter Anthropic cache_control payload rewriting.
import { expectDefined } from "@openclaw/normalization-core";
import type { StreamFn } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it } from "vitest";
import { createOpenRouterSystemCacheWrapper } from "../../llm/providers/stream-wrappers/proxy.js";
@@ -44,10 +46,14 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6");
expect(payload.messages[0].content).toEqual([
expect(
expectDefined(payload.messages[0], "payload.messages[0] test invariant").content,
).toEqual([
{ type: "text", text: "You are a helpful assistant.", cache_control: { type: "ephemeral" } },
]);
expect(payload.messages[1].content).toBe("Hello");
expect(expectDefined(payload.messages[1], "payload.messages[1] test invariant").content).toBe(
"Hello",
);
});
it("adds cache_control to last content block when system message is already array", () => {
@@ -65,7 +71,8 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6");
const content = payload.messages[0].content as Array<Record<string, unknown>>;
const content = expectDefined(payload.messages[0], "payload.messages[0] test invariant")
.content as Array<Record<string, unknown>>;
expect(content[0]).toEqual({ type: "text", text: "Part 1" });
expect(content[1]).toEqual({
type: "text",
@@ -84,7 +91,9 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6", { cacheRetention: "long" });
expect(payload.messages[0].content).toEqual([
expect(
expectDefined(payload.messages[0], "payload.messages[0] test invariant").content,
).toEqual([
{
type: "text",
text: "You are a helpful assistant.",
@@ -115,10 +124,12 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6", { cacheRetention: "none" });
expect(payload.messages[0].content).toBe("You are a helpful assistant.");
expect(payload.messages[1].content).toEqual([
{ type: "thinking", thinking: "internal", thinkingSignature: "sig_1" },
]);
expect(expectDefined(payload.messages[0], "payload.messages[0] test invariant").content).toBe(
"You are a helpful assistant.",
);
expect(
expectDefined(payload.messages[1], "payload.messages[1] test invariant").content,
).toEqual([{ type: "thinking", thinking: "internal", thinkingSignature: "sig_1" }]);
});
it("does not inject cache_control for OpenRouter non-Anthropic models", () => {
@@ -128,7 +139,9 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
runOpenRouterPayload(payload, "google/gemini-3-pro");
expect(payload.messages[0].content).toBe("You are a helpful assistant.");
expect(expectDefined(payload.messages[0], "payload.messages[0] test invariant").content).toBe(
"You are a helpful assistant.",
);
});
it("leaves payload unchanged when no system message exists", () => {
@@ -138,7 +151,9 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6");
expect(payload.messages[0].content).toBe("Hello");
expect(expectDefined(payload.messages[0], "payload.messages[0] test invariant").content).toBe(
"Hello",
);
});
it("does not inject cache_control into thinking blocks", () => {
@@ -156,7 +171,9 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6");
expect(payload.messages[0].content).toEqual([
expect(
expectDefined(payload.messages[0], "payload.messages[0] test invariant").content,
).toEqual([
{ type: "text", text: "Part 1" },
{ type: "thinking", thinking: "internal", thinkingSignature: "sig_1" },
]);
@@ -182,7 +199,9 @@ describe("extra-params: OpenRouter Anthropic cache_control", () => {
runOpenRouterPayload(payload, "anthropic/claude-opus-4-6");
expect(payload.messages[0].content).toEqual([
expect(
expectDefined(payload.messages[0], "payload.messages[0] test invariant").content,
).toEqual([
{ type: "thinking", thinking: "internal", thinkingSignature: "sig_1" },
{ type: "text", text: "visible" },
]);
@@ -1,5 +1,6 @@
// Coverage for Google prompt-cache creation, reuse, and request rewriting.
import crypto from "node:crypto";
import { expectDefined } from "@openclaw/normalization-core";
import type { StreamFn } from "openclaw/plugin-sdk/agent-core";
import type { Model } from "openclaw/plugin-sdk/llm";
import { describe, expect, it, vi } from "vitest";
@@ -203,7 +204,11 @@ describe("google prompt cache", () => {
);
const headers = fetchInit(fetchMock).headers as Record<string, string>;
expect(resolveSecretSentinel(headers.Authorization)).toBe("Bearer google-oauth-token");
expect(
resolveSecretSentinel(
expectDefined(headers.Authorization, "headers.Authorization test invariant"),
),
).toBe("Bearer google-oauth-token");
expect(headers["x-goog-api-key"]).toBeUndefined();
expect(headers["Content-Type"]).toBe("application/json");
});
@@ -236,7 +241,11 @@ describe("google prompt cache", () => {
const headers = fetchInit(fetchMock).headers as Record<string, string>;
expect(headers.Authorization).toBe("Bearer google-kill-switch-token");
expect(isSecretValueRegisteredForRedaction(headers.Authorization)).toBe(true);
expect(
isSecretValueRegisteredForRedaction(
expectDefined(headers.Authorization, "headers.Authorization test invariant"),
),
).toBe(true);
} finally {
vi.unstubAllEnvs();
}
@@ -1,4 +1,6 @@
// Coverage for inline provider model normalization and inheritance.
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import { buildInlineProviderModels, resolveProviderModelInput } from "./model.inline-provider.js";
import { makeModel } from "./model.test-harness.js";
@@ -83,10 +85,12 @@ describe("buildInlineProviderModels", () => {
const result = buildInlineProviderModels(providers);
expect(result).toHaveLength(1);
expect(result[0].provider).toBe("google");
expect(result[0].baseUrl).toBe("https://us-central1-aiplatform.googleapis.com/v1");
expect(result[0].api).toBe("google-vertex");
expect(result[0].id).toBe("gemini-2.5-pro");
expect(expectDefined(result[0], "result[0] test invariant").provider).toBe("google");
expect(expectDefined(result[0], "result[0] test invariant").baseUrl).toBe(
"https://us-central1-aiplatform.googleapis.com/v1",
);
expect(expectDefined(result[0], "result[0] test invariant").api).toBe("google-vertex");
expect(expectDefined(result[0], "result[0] test invariant").id).toBe("gemini-2.5-pro");
});
it("model-level api takes precedence over provider-level api", () => {
@@ -124,10 +128,12 @@ describe("buildInlineProviderModels", () => {
const result = buildInlineProviderModels(providers);
expect(result).toHaveLength(1);
expect(result[0].provider).toBe("custom");
expect(result[0].baseUrl).toBe("http://localhost:10000");
expect(result[0].api).toBe("anthropic-messages");
expect(result[0].name).toBe("claude-opus-4.5");
expect(expectDefined(result[0], "result[0] test invariant").provider).toBe("custom");
expect(expectDefined(result[0], "result[0] test invariant").baseUrl).toBe(
"http://localhost:10000",
);
expect(expectDefined(result[0], "result[0] test invariant").api).toBe("anthropic-messages");
expect(expectDefined(result[0], "result[0] test invariant").name).toBe("claude-opus-4.5");
});
it("normalizes bare Google API hosts for custom Google Generative AI providers", () => {
@@ -144,9 +150,11 @@ describe("buildInlineProviderModels", () => {
const result = buildInlineProviderModels(providers);
expect(result).toHaveLength(1);
expect(result[0].provider).toBe("google-paid");
expect(result[0].api).toBe("google-generative-ai");
expect(result[0].baseUrl).toBe("https://generativelanguage.googleapis.com/v1beta");
expect(expectDefined(result[0], "result[0] test invariant").provider).toBe("google-paid");
expect(expectDefined(result[0], "result[0] test invariant").api).toBe("google-generative-ai");
expect(expectDefined(result[0], "result[0] test invariant").baseUrl).toBe(
"https://generativelanguage.googleapis.com/v1beta",
);
});
it("merges provider-level headers into inline models", () => {
@@ -187,21 +195,19 @@ describe("buildInlineProviderModels", () => {
};
const result = buildInlineProviderModels(providers);
const [
{
id,
name,
reasoning,
input,
cost,
contextWindow,
maxTokens,
provider,
baseUrl,
api,
headers,
},
] = result;
const {
id,
name,
reasoning,
input,
cost,
contextWindow,
maxTokens,
provider,
baseUrl,
api,
headers,
} = expectDefined(result[0], "inline proxy model");
expect(result).toHaveLength(1);
expect({
@@ -247,9 +253,11 @@ describe("buildInlineProviderModels", () => {
} as unknown as Parameters<typeof buildInlineProviderModels>[0]);
expect(result).toHaveLength(1);
expect(result[0].provider).toBe("proxy");
expect(result[0].api).toBe("openai-completions");
expect(result[0].baseUrl).toBe("https://proxy.example.com/v1");
expect(expectDefined(result[0], "result[0] test invariant").provider).toBe("proxy");
expect(expectDefined(result[0], "result[0] test invariant").api).toBe("openai-completions");
expect(expectDefined(result[0], "result[0] test invariant").baseUrl).toBe(
"https://proxy.example.com/v1",
);
});
it("omits headers when neither provider nor model specifies them", () => {
@@ -263,7 +271,7 @@ describe("buildInlineProviderModels", () => {
const result = buildInlineProviderModels(providers);
expect(result).toHaveLength(1);
expect(result[0].headers).toBeUndefined();
expect(expectDefined(result[0], "result[0] test invariant").headers).toBeUndefined();
});
it("drops SecretRef marker headers in inline provider models", () => {
@@ -281,7 +289,7 @@ describe("buildInlineProviderModels", () => {
const result = buildInlineProviderModels(providers);
expect(result).toHaveLength(1);
expect(result[0].headers).toEqual({
expect(expectDefined(result[0], "result[0] test invariant").headers).toEqual({
"X-Static": "tenant-a",
});
});
@@ -1,4 +1,6 @@
// Coverage for replay-safe Codex app-server recovery retries.
import { expectDefined } from "@openclaw/normalization-core";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { makeModelFallbackCfg } from "../test-helpers/model-fallback-config-fixture.js";
import { makeAttemptResult } from "./run.overflow-compaction.fixture.js";
@@ -273,7 +275,10 @@ describe("runEmbeddedAgent Codex app-server recovery", () => {
expect(
(
mockedRunEmbeddedAttempt.mock.calls[1][0] as {
expectDefined(
mockedRunEmbeddedAttempt.mock.calls[1],
"mockedRunEmbeddedAttempt.mock.calls[1] test invariant",
)[0] as {
suppressNextUserMessagePersistence?: boolean;
}
).suppressNextUserMessagePersistence,
@@ -304,7 +309,10 @@ describe("runEmbeddedAgent Codex app-server recovery", () => {
expect(
(
mockedRunEmbeddedAttempt.mock.calls[1][0] as {
expectDefined(
mockedRunEmbeddedAttempt.mock.calls[1],
"mockedRunEmbeddedAttempt.mock.calls[1] test invariant",
)[0] as {
suppressNextUserMessagePersistence?: boolean;
}
).suppressNextUserMessagePersistence,
@@ -2,6 +2,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { createReplyOperation } from "../../auto-reply/reply/reply-run-registry.js";
import {
@@ -1578,9 +1579,14 @@ describe("runEmbeddedAgent overflow compaction trigger routing", () => {
expectRecordFields(authProfiles["openai:work"], { provider: "openai" });
expect(harnessParams.toolAuthProfileStore).toBe(codexAuthStore);
expect(mockedMarkAuthProfileSuccess).toHaveBeenCalledTimes(1);
const [[successParams]] = mockedMarkAuthProfileSuccess.mock.calls as unknown as Array<
[{ provider?: string; profileId?: string }]
>;
const [successParams] = expectDefined(
(
mockedMarkAuthProfileSuccess.mock.calls as unknown as Array<
[{ provider?: string; profileId?: string }]
>
)[0],
"(mockedMarkAuthProfileSuccess.mock.calls as unknown as Array<\n [{ provider?: string; profileId?: string }]\n >)[0] test invariant",
);
expect(successParams.provider).toBe("openai");
expect(successParams.profileId).toBe("openai:work");
});
@@ -1,4 +1,6 @@
// Coverage for normalizing tool calls before and during model replay.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it, vi } from "vitest";
import {
@@ -163,7 +165,9 @@ describe("wrapStreamFnPromoteStandaloneTextToolCalls", () => {
arguments: { command: "cat /proc/mounts 2>/dev/null | head -20" },
partialArgs: '{"command":"cat /proc/mounts 2>/dev/null | head -20"}',
});
expect(String(content[1].id)).toMatch(/^call_[a-f0-9]{24}$/);
expect(String(expectDefined(content[1], "content[1] test invariant").id)).toMatch(
/^call_[a-f0-9]{24}$/,
);
expect(content[2]).toMatchObject({
type: "toolCall",
name: "exec",
@@ -1,4 +1,5 @@
import { notifyLlmRequestActivity } from "@openclaw/ai/internal/runtime";
import { expectDefined } from "@openclaw/normalization-core";
// LLM idle-timeout tests cover timeout selection and stream wrapping for
// embedded provider calls, including local-provider and cron exceptions.
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
@@ -674,7 +675,10 @@ describe("streamWithIdleTimeout", () => {
return {
async next() {
if (index < chunks.length) {
return { done: false, value: chunks[index++] };
return {
done: false,
value: expectDefined(chunks[index++], "chunks[index++] test invariant"),
};
}
return { done: true, value: undefined };
},
@@ -3,6 +3,8 @@
* with no pending tool calls, so the parent session is idle when subagent
* results arrive.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { beforeAll, beforeEach, describe, expect, it } from "vitest";
import { makeAttemptResult } from "./run.overflow-compaction.fixture.js";
import {
@@ -80,8 +82,9 @@ describe("sessions_yield orchestration", () => {
// clientToolCalls wins — tool_calls stopReason, pendingToolCalls populated
expect(result.meta.stopReason).toBe("tool_calls");
expect(result.meta.pendingToolCalls).toHaveLength(1);
expect(result.meta.pendingToolCalls![0].name).toBe("hosted_tool");
const pendingToolCalls = expectDefined(result.meta.pendingToolCalls, "pending tool calls");
expect(pendingToolCalls).toHaveLength(1);
expect(expectDefined(pendingToolCalls[0], "hosted tool call").name).toBe("hosted_tool");
});
it("preserves order across multiple client tool calls in one attempt (#52288)", async () => {
@@ -105,13 +108,16 @@ describe("sessions_yield orchestration", () => {
});
expect(result.meta.stopReason).toBe("tool_calls");
expect(result.meta.pendingToolCalls).toHaveLength(3);
expect(result.meta.pendingToolCalls!.map((c) => c.name)).toEqual([
const pendingToolCalls = expectDefined(result.meta.pendingToolCalls, "pending tool calls");
expect(pendingToolCalls).toHaveLength(3);
expect(pendingToolCalls.map((c) => c.name)).toEqual([
"create_graph",
"activate_graph",
"get_status",
]);
expect(JSON.parse(result.meta.pendingToolCalls![0].arguments)).toEqual({
expect(
JSON.parse(expectDefined(pendingToolCalls[0], "first pending tool call").arguments),
).toEqual({
nodes: ["a", "b"],
});
});
@@ -1,5 +1,7 @@
// Tool-result context guard tests cover live replay truncation, mid-turn
// prechecks, and context-engine loop hooks for oversized tool outputs.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it, vi } from "vitest";
import type { ContextEngine, ContextEngineRuntimeSettings } from "../../context-engine/types.js";
@@ -215,10 +217,16 @@ describe("installToolResultContextGuard", () => {
const transformed = (await applyGuardToContext(agent, contextForNextCall)) as AgentMessage[];
expect(transformed).not.toBe(contextForNextCall);
const newResultText = getToolResultText(transformed[0]);
const newResultText = getToolResultText(
expectDefined(transformed[0], "transformed[0] test invariant"),
);
expect(newResultText.length).toBeLessThan(5_000);
expectOpenClawTruncation(newResultText);
expect(getToolResultText(contextForNextCall[0])).toBe("z".repeat(5_000));
expect(
getToolResultText(
expectDefined(contextForNextCall[0], "contextForNextCall[0] test invariant"),
),
).toBe("z".repeat(5_000));
});
it("wraps an existing transformContext and guards the transformed output", async () => {
@@ -234,7 +242,9 @@ describe("installToolResultContextGuard", () => {
const transformed = (await applyGuardToContext(agent, contextForNextCall)) as AgentMessage[];
expect(transformed).not.toBe(contextForNextCall);
expectOpenClawTruncation(getToolResultText(transformed[0]));
expectOpenClawTruncation(
getToolResultText(expectDefined(transformed[0], "transformed[0] test invariant")),
);
});
it("handles legacy role=tool string outputs with truncation wording", async () => {
@@ -242,7 +252,9 @@ describe("installToolResultContextGuard", () => {
const contextForNextCall = [makeLegacyToolResult("call_big", "y".repeat(5_000))];
const transformed = (await applyGuardToContext(agent, contextForNextCall)) as AgentMessage[];
const newResultText = getToolResultText(transformed[0]);
const newResultText = getToolResultText(
expectDefined(transformed[0], "transformed[0] test invariant"),
);
expect(typeof (transformed[0] as { content?: unknown }).content).toBe("string");
expectOpenClawTruncation(newResultText);
@@ -256,7 +268,9 @@ describe("installToolResultContextGuard", () => {
const transformed = (await applyGuardToContext(agent, contextForNextCall)) as AgentMessage[];
const result = transformed[0] as { details?: unknown };
const newResultText = getToolResultText(transformed[0]);
const newResultText = getToolResultText(
expectDefined(transformed[0], "transformed[0] test invariant"),
);
expectOpenClawTruncation(newResultText);
expect(result.details).toBeUndefined();
@@ -279,7 +293,11 @@ describe("installToolResultContextGuard", () => {
await expect(applyGuardToContext(agent, contextForNextCall)).rejects.toThrow(
PREEMPTIVE_CONTEXT_OVERFLOW_MESSAGE,
);
expect(getToolResultText(contextForNextCall[1])).toBe("x".repeat(5_000));
expect(
getToolResultText(
expectDefined(contextForNextCall[1], "contextForNextCall[1] test invariant"),
),
).toBe("x".repeat(5_000));
});
it("throws instead of rewriting older tool results under aggregate pressure", async () => {
@@ -294,9 +312,21 @@ describe("installToolResultContextGuard", () => {
await expect(applyGuardToContext(agent, contextForNextCall)).rejects.toThrow(
PREEMPTIVE_CONTEXT_OVERFLOW_MESSAGE,
);
expect(getToolResultText(contextForNextCall[1])).toBe("a".repeat(500));
expect(getToolResultText(contextForNextCall[2])).toBe("b".repeat(500));
expect(getToolResultText(contextForNextCall[3])).toBe("c".repeat(500));
expect(
getToolResultText(
expectDefined(contextForNextCall[1], "contextForNextCall[1] test invariant"),
),
).toBe("a".repeat(500));
expect(
getToolResultText(
expectDefined(contextForNextCall[2], "contextForNextCall[2] test invariant"),
),
).toBe("b".repeat(500));
expect(
getToolResultText(
expectDefined(contextForNextCall[3], "contextForNextCall[3] test invariant"),
),
).toBe("c".repeat(500));
});
it("does not special-case the latest read result before throwing under aggregate pressure", async () => {
@@ -310,8 +340,16 @@ describe("installToolResultContextGuard", () => {
await expect(applyGuardToContext(agent, contextForNextCall)).rejects.toThrow(
PREEMPTIVE_CONTEXT_OVERFLOW_MESSAGE,
);
expect(getToolResultText(contextForNextCall[1])).toBe("x".repeat(400));
expect(getToolResultText(contextForNextCall[2])).toBe("y".repeat(500));
expect(
getToolResultText(
expectDefined(contextForNextCall[1], "contextForNextCall[1] test invariant"),
),
).toBe("x".repeat(400));
expect(
getToolResultText(
expectDefined(contextForNextCall[2], "contextForNextCall[2] test invariant"),
),
).toBe("y".repeat(500));
});
it("supports model-window-specific truncation for large but otherwise valid tool results", async () => {
@@ -324,7 +362,9 @@ describe("installToolResultContextGuard", () => {
100_000,
)) as AgentMessage[];
expectOpenClawTruncation(getToolResultText(transformed[0]));
expectOpenClawTruncation(
getToolResultText(expectDefined(transformed[0], "transformed[0] test invariant")),
);
});
it("truncates UTF-16 tool results without splitting surrogate pairs", async () => {
@@ -341,10 +381,14 @@ describe("installToolResultContextGuard", () => {
1_000,
)) as AgentMessage[];
expect(getToolResultText(transformed[0])).toBe(
expect(getToolResultText(expectDefined(transformed[0], "transformed[0] test invariant"))).toBe(
"a".repeat(439) + formatContextLimitTruncationNotice(1_002),
);
expect(getToolResultText(contextForNextCall[0])).toBe(text);
expect(
getToolResultText(
expectDefined(contextForNextCall[0], "contextForNextCall[0] test invariant"),
),
).toBe(text);
});
it("raises a structured mid-turn precheck signal after a new tool result overflows", async () => {
@@ -419,8 +463,12 @@ describe("installToolResultContextGuard", () => {
const transformed = (await applyGuardToContext(agent, contextForNextCall)) as AgentMessage[];
expect(transformed).toBe(contextForNextCall);
expect(getToolResultText(transformed[0])).toBe("x".repeat(100));
expect(getToolResultText(transformed[1])).toBe("y".repeat(120));
expect(getToolResultText(expectDefined(transformed[0], "transformed[0] test invariant"))).toBe(
"x".repeat(100),
);
expect(getToolResultText(expectDefined(transformed[1], "transformed[1] test invariant"))).toBe(
"y".repeat(120),
);
expect((contextForNextCall[0] as { details?: unknown }).details).toBeDefined();
expect((contextForNextCall[1] as { details?: unknown }).details).toBeDefined();
});
@@ -3,6 +3,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
import type { AssistantMessage, ToolResultMessage, UserMessage } from "openclaw/plugin-sdk/llm";
@@ -1638,8 +1639,8 @@ describe("truncateOversizedToolResultsInSession", () => {
);
expect(toolTexts[0]).toContain("truncated");
expect(toolTexts[1].length).toBeGreaterThan(0);
expect(toolTexts[2].length).toBeGreaterThan(0);
expect(expectDefined(toolTexts[1], "toolTexts[1] test invariant").length).toBeGreaterThan(0);
expect(expectDefined(toolTexts[2], "toolTexts[2] test invariant").length).toBeGreaterThan(0);
});
it("lets aggregate recovery honor a tiny explicit cap during persisted rewrite", async () => {
@@ -3,6 +3,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -168,15 +169,18 @@ describe("rewriteTranscriptEntriesInSessionManager", () => {
it("branches from the first replaced message and re-appends the remaining suffix", () => {
const { sessionManager, toolResultEntryId } = createReadRewriteSession();
const result = rewriteTranscriptEntriesInSessionManager({
sessionManager,
replacements: [
{
entryId: toolResultEntryId,
message: createToolResultReplacement("read", "[externalized file_123]", 3),
},
],
});
const result = expectDefined(
rewriteTranscriptEntriesInSessionManager({
sessionManager,
replacements: [
{
entryId: expectDefined(toolResultEntryId, "toolResultEntryId test invariant"),
message: createToolResultReplacement("read", "[externalized file_123]", 3),
},
],
}),
"rewriteTranscriptEntriesInSessionManager({ sessionManager, replacemen... test invariant",
);
expect(result.changed).toBe(true);
expect(result.rewrittenEntries).toBe(1);
@@ -203,15 +207,18 @@ describe("rewriteTranscriptEntriesInSessionManager", () => {
);
sessionManager.appendLabelChange(summaryEntry.id, "bookmark");
const result = rewriteTranscriptEntriesInSessionManager({
sessionManager,
replacements: [
{
entryId: toolResultEntryId,
message: createToolResultReplacement("read", "[externalized file_123]", 3),
},
],
});
const result = expectDefined(
rewriteTranscriptEntriesInSessionManager({
sessionManager,
replacements: [
{
entryId: expectDefined(toolResultEntryId, "toolResultEntryId test invariant"),
message: createToolResultReplacement("read", "[externalized file_123]", 3),
},
],
}),
"rewriteTranscriptEntriesInSessionManager({ sessionManager, replacemen... test invariant",
);
expect(result.changed).toBe(true);
const rewrittenSummaryEntry = requireValue(
@@ -230,17 +237,24 @@ describe("rewriteTranscriptEntriesInSessionManager", () => {
toolResultEntryId,
tailAssistantEntryId: keptAssistantEntryId,
} = createReadRewriteSession({ tailAssistantText: "keep me" });
sessionManager.appendCompaction("summary", keptAssistantEntryId, 123);
sessionManager.appendCompaction(
"summary",
expectDefined(keptAssistantEntryId, "keptAssistantEntryId test invariant"),
123,
);
const result = rewriteTranscriptEntriesInSessionManager({
sessionManager,
replacements: [
{
entryId: toolResultEntryId,
message: createToolResultReplacement("read", "[externalized file_123]", 3),
},
],
});
const result = expectDefined(
rewriteTranscriptEntriesInSessionManager({
sessionManager,
replacements: [
{
entryId: expectDefined(toolResultEntryId, "toolResultEntryId test invariant"),
message: createToolResultReplacement("read", "[externalized file_123]", 3),
},
],
}),
"rewriteTranscriptEntriesInSessionManager({ sessionManager, replacemen... test invariant",
);
expect(result.changed).toBe(true);
const branch = sessionManager.getBranch();
@@ -273,15 +287,18 @@ describe("rewriteTranscriptEntriesInSessionManager", () => {
message.role === "assistant" ? { block: true } : undefined,
});
const result = rewriteTranscriptEntriesInSessionManager({
sessionManager,
replacements: [
{
entryId: toolResultEntryId,
message: createToolResultReplacement("exec", "[exact replacement]", 2),
},
],
});
const result = expectDefined(
rewriteTranscriptEntriesInSessionManager({
sessionManager,
replacements: [
{
entryId: expectDefined(toolResultEntryId, "toolResultEntryId test invariant"),
message: createToolResultReplacement("exec", "[exact replacement]", 2),
},
],
}),
"rewriteTranscriptEntriesInSessionManager({ sessionManager, replacemen... test invariant",
);
expect(result.changed).toBe(true);
const branchMessages = getBranchMessages(sessionManager);
@@ -1,5 +1,7 @@
// Tool subscription helper tests cover error extraction, sanitized tool results,
// and safe lifecycle payloads for embedded tool events.
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, describe, expect, it, vi } from "vitest";
import * as loggingConfigModule from "../logging/config.js";
import {
@@ -207,7 +209,7 @@ describe("isToolResultError", () => {
function getTextContent(result: unknown, index = 0): string {
// Sanitizer tests assert text redaction while keeping the result shape opaque.
const record = result as { content: Array<{ text: string }> };
return record.content[index].text;
return expectDefined(record.content[index], "record.content[index] test invariant").text;
}
describe("sanitizeToolResult", () => {
@@ -304,9 +306,15 @@ describe("sanitizeToolResult", () => {
const sanitized = sanitizeToolResult(result) as {
content: Array<{ data?: string; bytes?: number; omitted?: boolean }>;
};
expect(sanitized.content[0].data).toBeUndefined();
expect(sanitized.content[0].omitted).toBe(true);
expect(sanitized.content[0].bytes).toBe("base64imagedata".length);
expect(
expectDefined(sanitized.content[0], "sanitized.content[0] test invariant").data,
).toBeUndefined();
expect(expectDefined(sanitized.content[0], "sanitized.content[0] test invariant").omitted).toBe(
true,
);
expect(expectDefined(sanitized.content[0], "sanitized.content[0] test invariant").bytes).toBe(
"base64imagedata".length,
);
});
it("redacts secrets inside result.details (e.g. exec aggregated stdout)", () => {
+6 -1
View File
@@ -2,6 +2,8 @@
* Regression coverage for internal runtime-context stripping and extraction.
* Verifies protected delimiters, legacy blocks, and custom-message filtering.
*/
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import {
escapeInternalRuntimeContextDelimiters,
@@ -119,7 +121,10 @@ describe("internal runtime context codec", () => {
const lineCount = 4 + Math.floor(rng() * 12);
const payloadLines: string[] = [];
for (let i = 0; i < lineCount; i++) {
const token = tokenPool[Math.floor(rng() * tokenPool.length)];
const token = expectDefined(
tokenPool[Math.floor(rng() * tokenPool.length)],
"tokenPool[Math.floor(rng() * tokenPool.length)] test invariant",
);
payloadLines.push(token);
}
const escapedPayload = payloadLines.map((line) =>
+5 -1
View File
@@ -1,4 +1,5 @@
/** Tests auth-profile backed MCP bearer projection. */
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { resolveMcpBearerBundleConfig, withMcpAuthProfileBearer } from "./mcp-auth-profile.js";
import * as mcpHttpFetch from "./mcp-http-fetch.js";
@@ -148,7 +149,10 @@ describe("mcp auth profile bearer projection", () => {
},
});
const server = resolved.config.mcpServers.ducktape;
const server = expectDefined(
resolved.config.mcpServers.ducktape,
"resolved.config.mcpServers.ducktape test invariant",
);
expect(server.auth).toBeUndefined();
expect(server.oauth).toBeUndefined();
expect(server.headers).toEqual({
+10 -3
View File
@@ -1,6 +1,7 @@
// Covers model fallback ordering, error classification, and auth cooldown behavior.
import crypto from "node:crypto";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { TranscriptNotContinuableError } from "../../packages/agent-core/src/errors.js";
import type { OpenClawConfig } from "../config/config.js";
@@ -904,8 +905,12 @@ describe("runWithModelFallback", () => {
expect(result.result).toBe("ok");
expect(run).toHaveBeenCalledTimes(2);
expect(result.attempts).toHaveLength(1);
expect(result.attempts[0].error).toBe("bad request");
expect(result.attempts[0].reason).toBe("unknown");
expect(expectDefined(result.attempts[0], "result.attempts[0] test invariant").error).toBe(
"bad request",
);
expect(expectDefined(result.attempts[0], "result.attempts[0] test invariant").reason).toBe(
"unknown",
);
});
it("does not treat Codex missing tool-result failures as model fallback candidates", async () => {
@@ -986,7 +991,9 @@ describe("runWithModelFallback", () => {
{ isFinalFallbackAttempt: false },
]);
expect(result.attempts).toHaveLength(1);
expect(result.attempts[0].reason).toBe("overloaded");
expect(expectDefined(result.attempts[0], "result.attempts[0] test invariant").reason).toBe(
"overloaded",
);
});
it("does not prepare agent harness plugins for forced OpenClaw candidates", async () => {
@@ -1,4 +1,5 @@
// Verifies generated models.json preserves source secret markers from runtime snapshots.
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
@@ -182,9 +183,13 @@ function createOpenAiHeaderRuntimeConfig(): OpenClawConfig {
};
}
function getOpenAiProvider(config: OpenClawConfig) {
return expectDefined(config.models?.providers?.openai, "OpenAI provider config");
}
function createOpenAiSourceConfigWithHeadersAndApiKey(): OpenClawConfig {
const config = createOpenAiHeaderSourceConfig();
config.models!.providers!.openai.apiKey = {
getOpenAiProvider(config).apiKey = {
source: "env",
provider: "default",
id: "OPENAI_API_KEY", // pragma: allowlist secret
@@ -194,7 +199,7 @@ function createOpenAiSourceConfigWithHeadersAndApiKey(): OpenClawConfig {
function createOpenAiRuntimeConfigWithHeadersAndApiKey(): OpenClawConfig {
const config = createOpenAiHeaderRuntimeConfig();
config.models!.providers!.openai.apiKey = "sk-runtime-resolved"; // pragma: allowlist secret
getOpenAiProvider(config).apiKey = "sk-runtime-resolved"; // pragma: allowlist secret
return config;
}
@@ -263,7 +268,7 @@ describe("models-config runtime source snapshot", () => {
const sourceConfig: OpenClawConfig = {
models: {
providers: {
openai: createOpenAiApiKeySourceConfig().models!.providers!.openai,
openai: getOpenAiProvider(createOpenAiApiKeySourceConfig()),
moonshot: {
baseUrl: "https://api.moonshot.ai/v1",
apiKey: { source: "file", provider: "vault", id: "/moonshot/apiKey" },
@@ -276,7 +281,7 @@ describe("models-config runtime source snapshot", () => {
const runtimeConfig: OpenClawConfig = {
models: {
providers: {
openai: createOpenAiApiKeyRuntimeConfig().models!.providers!.openai,
openai: getOpenAiProvider(createOpenAiApiKeyRuntimeConfig()),
moonshot: {
baseUrl: "https://api.moonshot.ai/v1",
apiKey: "sk-runtime-moonshot", // pragma: allowlist secret
@@ -349,7 +354,7 @@ describe("models-config runtime source snapshot", () => {
models: {
providers: {
openai: {
...runtimeConfig.models!.providers!.openai,
...getOpenAiProvider(runtimeConfig),
baseUrl: "https://api.openai.com/v1",
headers: {
"X-OpenClaw-Test": "one",
@@ -363,7 +368,7 @@ describe("models-config runtime source snapshot", () => {
models: {
providers: {
openai: {
...runtimeConfig.models!.providers!.openai,
...getOpenAiProvider(runtimeConfig),
baseUrl: "https://mirror.example/v1",
headers: {
"X-OpenClaw-Test": "two",
+24 -13
View File
@@ -1,6 +1,7 @@
// Live-sweeps discovered model profiles with optional provider/model filters and probes.
import { writeSync } from "node:fs";
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
import { expectDefined } from "@openclaw/normalization-core";
import { type Api, completeSimple, type Model } from "openclaw/plugin-sdk/llm";
import { Type } from "typebox";
import { describe, expect, it, vi } from "vitest";
@@ -525,7 +526,13 @@ function isIpv4PrivateRange(host: string): boolean {
return false;
}
const [a, b] = octets;
return a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168);
return (
a === 10 ||
(a === 172 &&
expectDefined(b, "b test invariant") >= 16 &&
expectDefined(b, "b test invariant") <= 31) ||
(a === 192 && b === 168)
);
}
function isIpv6LocalRange(host: string): boolean {
@@ -1963,13 +1970,14 @@ describeLive("live models (profile keys)", () => {
const attemptMax =
model.provider === "anthropic" && anthropicKeys.length > 0 ? anthropicKeys.length : 1;
for (let attempt = 0; attempt < attemptMax; attempt += 1) {
if (model.provider === "anthropic" && anthropicKeys.length > 0) {
process.env.ANTHROPIC_API_KEY = anthropicKeys[attempt];
}
const apiKey =
const anthropicApiKey =
model.provider === "anthropic" && anthropicKeys.length > 0
? anthropicKeys[attempt]
: requireApiKey(apiKeyInfo, model.provider);
? expectDefined(anthropicKeys[attempt], `Anthropic API key ${attempt + 1}`)
: undefined;
if (anthropicApiKey) {
process.env.ANTHROPIC_API_KEY = anthropicApiKey;
}
const apiKey = anthropicApiKey ?? requireApiKey(apiKeyInfo, model.provider);
try {
// Special regression: OpenAI requires replayed `reasoning` items for tool-only turns.
if (
@@ -2119,12 +2127,15 @@ describeLive("live models (profile keys)", () => {
}
logProgress(`${progressLabel}: prompt`);
const ok = await completeOkWithRetry({
model,
apiKey,
timeoutMs: perModelTimeoutMs,
progressLabel,
});
const ok = expectDefined(
await completeOkWithRetry({
model,
apiKey,
timeoutMs: perModelTimeoutMs,
progressLabel,
}),
`${progressLabel} completion result`,
);
if (ok.res.stopReason === "error") {
const msg = ok.res.errorMessage ?? "";
+14 -5
View File
@@ -1,4 +1,6 @@
/** Tests connected node-hosted plugin tool materialization. */
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { NodePluginToolDescriptor } from "../../packages/gateway-protocol/src/index.js";
import {
@@ -61,11 +63,13 @@ describe("createNodePluginTools", () => {
});
const tools = createNodePluginTools({ existingToolNames: new Set(["read"]) });
const result = await tools[0].execute("call-1", { text: "ping" });
const result = await expectDefined(tools[0], "tools[0] test invariant").execute("call-1", {
text: "ping",
});
expect(tools.map((tool) => tool.name)).toEqual(["remote_echo"]);
expect(tools[0].description).toContain("Studio Node");
expect(getPluginToolMeta(tools[0])).toMatchObject({
expect(expectDefined(tools[0], "tools[0] test invariant").description).toContain("Studio Node");
expect(getPluginToolMeta(expectDefined(tools[0], "tools[0] test invariant"))).toMatchObject({
pluginId: "remote-demo",
mcp: {
serverName: "remote-demo",
@@ -112,7 +116,10 @@ describe("createNodePluginTools", () => {
},
});
const tool = createNodePluginTools({})[0];
const tool = expectDefined(
createNodePluginTools({})[0],
"createNodePluginTools({})[0] test invariant",
);
const result = await tool.execute("call-mcp", { query: "needle" });
expect(callGatewayTool).toHaveBeenCalledWith(
@@ -187,7 +194,9 @@ describe("createNodePluginTools", () => {
});
const tools = createNodePluginTools({});
const result = await tools[1].execute("call-2", { text: "ping" });
const result = await expectDefined(tools[1], "tools[1] test invariant").execute("call-2", {
text: "ping",
});
expect(tools.map((tool) => tool.name)).toEqual(["node_a_remote_echo", "node_b_remote_echo"]);
expect(callGatewayTool).toHaveBeenCalledWith(
+17 -5
View File
@@ -1,6 +1,7 @@
// Verifies OpenAI-compatible streaming payloads, failures, and transport wrapping.
import { createServer } from "node:http";
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "@openclaw/ai/internal/shared";
import { expectDefined } from "@openclaw/normalization-core";
import OpenAI from "openai";
import type { ChatCompletionChunk } from "openai/resources/chat/completions.js";
import type { Api, Model } from "openclaw/plugin-sdk/llm";
@@ -6359,7 +6360,9 @@ describe("openai transport stream", () => {
nested: { keep: "value" },
});
expect(stripped.input[0]).not.toHaveProperty("encrypted_content");
expect(stripped.input[0].nested).not.toHaveProperty("encrypted_content");
expect(
expectDefined(stripped.input[0], "stripped.input[0] test invariant").nested,
).not.toHaveProperty("encrypted_content");
expect(stripped.input[1]).toEqual(params.input[1]);
});
@@ -8199,7 +8202,10 @@ describe("openai transport stream", () => {
) as { reasoning_effort?: unknown; tools?: unknown };
expect(params.tools).toHaveLength(1);
const tool = (params.tools as Array<Record<string, unknown>>)[0];
const tool = expectDefined(
(params.tools as Array<Record<string, unknown>>)[0],
"(params.tools as Array<Record<string, unknown>>)[0] test invariant",
);
expectRecordFields(tool, { type: "function" });
expectRecordFields(tool.function, { name: "lookup_weather" });
expect(params).not.toHaveProperty("reasoning_effort");
@@ -12077,7 +12083,7 @@ describe("openai transport stream", () => {
maxTokens: 8192,
} satisfies Model<"openai-completions">;
const output = {
const output: OpenAICompletionsOutput = {
role: "assistant" as const,
content: [],
api: model.api,
@@ -12151,8 +12157,14 @@ describe("openai transport stream", () => {
await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);
const thinkingBlock = output.content[0] as { type: string; thinking: string };
const textBlock = output.content[1] as { type: string; text: string };
const thinkingBlock = expectDefined(output.content[0], "output.content[0] test invariant") as {
type: string;
thinking: string;
};
const textBlock = expectDefined(output.content[1], "output.content[1] test invariant") as {
type: string;
text: string;
};
expect(output.content.length).toBe(2);
expect(thinkingBlock.type).toBe("thinking");
@@ -1,4 +1,6 @@
// Verifies session status output across scoped stores, tasks, and runtime hooks.
import { expectDefined } from "@openclaw/normalization-core";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { resolveSessionStoreEntry } from "../config/sessions/store-entry.js";
import { mergeSessionEntry, type SessionEntry } from "../config/sessions/types.js";
@@ -1279,7 +1281,10 @@ describe("session_status tool", () => {
expect(details.modelOverride).toBe("anthropic/claude-sonnet-4-6");
expect(updateSessionStoreMock).toHaveBeenCalledTimes(1);
const savedStore = latestMockCallArg(updateSessionStoreMock, 1) as Record<string, SessionEntry>;
const saved = savedStore["agent:main:scope:scopy:direct:scopy"];
const saved = expectDefined(
savedStore["agent:main:scope:scopy:direct:scopy"],
'savedStore["agent:main:scope:scopy:direct:scopy"] test invariant',
);
expectRecordFields(saved, {
providerOverride: "anthropic",
modelOverride: "claude-sonnet-4-6",
@@ -1342,7 +1347,7 @@ describe("session_status tool", () => {
});
await vi.waitFor(() => expect(events).toHaveLength(1));
const event = events[0];
const event = expectDefined(events[0], "events[0] test invariant");
expect(event.type).toBe("session");
expect(event.action).toBe("patch");
expect(event.sessionKey).toBe("main");
@@ -1398,7 +1403,10 @@ describe("session_status tool", () => {
expect(details.sessionKey).toBe("agent:main:scope:scopy:direct:scopy");
expect(updateSessionStoreMock).toHaveBeenCalledTimes(1);
const savedStore = latestMockCallArg(updateSessionStoreMock, 1) as Record<string, SessionEntry>;
const saved = savedStore["agent:main:scope:scopy:direct:scopy"];
const saved = expectDefined(
savedStore["agent:main:scope:scopy:direct:scopy"],
'savedStore["agent:main:scope:scopy:direct:scopy"] test invariant',
);
expectRecordFields(saved, {
providerOverride: "anthropic",
modelOverride: "claude-sonnet-4-6",
@@ -1,4 +1,6 @@
// Verifies embedded runtime outcome classifications drive model fallback correctly.
import { expectDefined } from "@openclaw/normalization-core";
import {
createContractRunResult,
OUTCOME_FALLBACK_RUNTIME_CONTRACT,
@@ -403,7 +405,7 @@ describe("Outcome/fallback runtime contract - embedded runtime fallback classifi
});
it("keeps running on the primary when terminal output is not classified as fallback", async () => {
const contractCase = nonFallbackCases[0];
const contractCase = expectDefined(nonFallbackCases[0], "nonFallbackCases[0] test invariant");
const run = vi.fn().mockResolvedValue(contractCase.result);
const result = await runWithModelFallback({
cfg: undefined,
+10 -4
View File
@@ -1,5 +1,7 @@
// Runtime plan tool tests cover schema normalization and diagnostics when the
// runtime plan owns tool policy, with legacy provider fallback still available.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentTool } from "openclaw/plugin-sdk/agent-core";
import {
createNativeOpenAIResponsesModel,
@@ -228,7 +230,7 @@ describe("AgentRuntimePlan tool policy helpers", () => {
});
expect(result[0]).toBe(normalized);
expect(getPluginToolMeta(result[0])).toMatchObject({
expect(getPluginToolMeta(expectDefined(result[0], "result[0] test invariant"))).toMatchObject({
pluginId: "bundle-mcp",
mcp: {
serverName: "fixture",
@@ -267,8 +269,12 @@ describe("AgentRuntimePlan tool policy helpers", () => {
expect(result[0]).toBe(normalized);
expect((result[0] as AnyAgentTool).catalogMode).toBe("direct-only");
expect(isToolWrappedWithBeforeToolCallHook(result[0])).toBe(true);
expect(getToolTerminalPresentation(result[0])).toBe(formatter);
expect(
isToolWrappedWithBeforeToolCallHook(expectDefined(result[0], "result[0] test invariant")),
).toBe(true);
expect(getToolTerminalPresentation(expectDefined(result[0], "result[0] test invariant"))).toBe(
formatter,
);
});
it("does not reread quarantined tools while preserving normalized metadata", () => {
@@ -306,7 +312,7 @@ describe("AgentRuntimePlan tool policy helpers", () => {
});
expect(result).toEqual([normalized]);
expect(getPluginToolMeta(result[0])).toMatchObject({
expect(getPluginToolMeta(expectDefined(result[0], "result[0] test invariant"))).toMatchObject({
pluginId: "bundle-mcp",
mcp: {
serverName: "fixture",
+14 -9
View File
@@ -5,6 +5,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, describe, expect, it, vi } from "vitest";
import { OPENCLAW_TRANSCRIPT_ARTIFACT_API } from "../shared/transcript-only-openclaw-assistant.js";
import { repairSessionFileIfNeeded } from "./session-file-repair.js";
@@ -374,7 +375,7 @@ describe("repairSessionFileIfNeeded", () => {
const repairedLines = repaired.trim().split("\n");
expect(repairedLines).toHaveLength(4);
const repairedEntry: { message: { content: { type: string; text: string }[] } } = JSON.parse(
repairedLines[2],
expectDefined(repairedLines[2], "repairedLines[2] test invariant"),
);
expect(repairedEntry.message.content).toEqual([
{ type: "text", text: "[assistant turn failed before producing content]" },
@@ -408,7 +409,9 @@ describe("repairSessionFileIfNeeded", () => {
const repaired = await fs.readFile(file, "utf-8");
const repairedLines = repaired.trim().split("\n");
expect(repairedLines).toHaveLength(3);
const rewrittenEntry = JSON.parse(repairedLines[1]);
const rewrittenEntry = JSON.parse(
expectDefined(repairedLines[1], "repairedLines[1] test invariant"),
);
expect(rewrittenEntry.id).toBe("msg-blank");
expect(rewrittenEntry.message.content).toEqual([
{ type: "text", text: BLANK_USER_FALLBACK_TEXT },
@@ -439,7 +442,9 @@ describe("repairSessionFileIfNeeded", () => {
const repaired = await fs.readFile(file, "utf-8");
const repairedLines = repaired.trim().split("\n");
expect(repairedLines).toHaveLength(3);
const rewrittenEntry = JSON.parse(repairedLines[1]);
const rewrittenEntry = JSON.parse(
expectDefined(repairedLines[1], "repairedLines[1] test invariant"),
);
expect(rewrittenEntry.message.content).toBe(BLANK_USER_FALLBACK_TEXT);
});
@@ -861,7 +866,7 @@ describe("repairSessionFileIfNeeded", () => {
const lines = (await fs.readFile(file, "utf-8")).trimEnd().split("\n");
expect(lines).toHaveLength(5);
const inserted = JSON.parse(lines[3]);
const inserted = JSON.parse(expectDefined(lines[3], "lines[3] test invariant"));
expect(inserted.type).toBe("message");
expect(inserted.parentId).toBe("msg-asst-process");
expect(inserted.message.role).toBe("toolResult");
@@ -869,7 +874,7 @@ describe("repairSessionFileIfNeeded", () => {
expect(inserted.message.toolName).toBe("process");
expect(inserted.message.isError).toBe(true);
expect(inserted.message.content[0].text).toBe("aborted");
expect(JSON.parse(lines[4])).toEqual(deliveryMirror);
expect(JSON.parse(expectDefined(lines[4], "lines[4] test invariant"))).toEqual(deliveryMirror);
});
it("inserts missing Responses message-tool results before delivery mirrors", async () => {
@@ -921,7 +926,7 @@ describe("repairSessionFileIfNeeded", () => {
const lines = (await fs.readFile(file, "utf-8")).trimEnd().split("\n");
expect(lines).toHaveLength(5);
const inserted = JSON.parse(lines[3]);
const inserted = JSON.parse(expectDefined(lines[3], "lines[3] test invariant"));
expect(inserted.type).toBe("message");
expect(inserted.parentId).toBe("msg-asst-message-tool");
expect(inserted.message.role).toBe("toolResult");
@@ -929,7 +934,7 @@ describe("repairSessionFileIfNeeded", () => {
expect(inserted.message.toolName).toBe("message");
expect(inserted.message.isError).toBe(true);
expect(inserted.message.content[0].text).toBe("aborted");
expect(JSON.parse(lines[4])).toEqual(deliveryMirror);
expect(JSON.parse(expectDefined(lines[4], "lines[4] test invariant"))).toEqual(deliveryMirror);
});
it("does not duplicate code-mode tool results that are already persisted", async () => {
@@ -1166,8 +1171,8 @@ describe("repairSessionFileIfNeeded", () => {
const after = await fs.readFile(file, "utf-8");
const lines = after.trimEnd().split("\n");
expect(lines).toHaveLength(2);
expect(JSON.parse(lines[0])).toEqual(header);
expect(JSON.parse(lines[1])).toEqual(message);
expect(JSON.parse(expectDefined(lines[0], "lines[0] test invariant"))).toEqual(header);
expect(JSON.parse(expectDefined(lines[1], "lines[1] test invariant"))).toEqual(message);
expect(after).not.toContain('"role":null');
});
+5 -1
View File
@@ -1,4 +1,6 @@
// Verifies session tool-result guard inserts, truncates, and repairs tool results.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
import { describe, expect, it } from "vitest";
@@ -537,7 +539,9 @@ describe("installSessionToolResultGuard", () => {
};
};
const serializedToolResult = JSON.stringify(toolResult);
expect(toolResult.content[0].text).not.toContain("sk-abcdef1234567890xyz");
expect(
expectDefined(toolResult.content[0], "toolResult.content[0] test invariant").text,
).not.toContain("sk-abcdef1234567890xyz");
expect(serializedToolResult).not.toContain("plainsecretvalue123");
expect(serializedToolResult).not.toContain("hunter2");
expect(serializedToolResult).not.toContain("nestedplainsecret123");
@@ -1,6 +1,7 @@
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it, vi } from "vitest";
const { uuidQueue } = vi.hoisted(() => ({ uuidQueue: [] as string[] }));
@@ -65,8 +66,12 @@ describe("v1 session migration id assignment", () => {
expect(messages).toHaveLength(2);
const ids = messages.map((m) => m.id);
expect(new Set(ids).size).toBe(ids.length);
expect(messages[1].parentId).toBe(messages[0].id);
expect(messages[1].parentId).not.toBe(messages[1].id);
expect(expectDefined(messages[1], "messages[1] test invariant").parentId).toBe(
expectDefined(messages[0], "messages[0] test invariant").id,
);
expect(expectDefined(messages[1], "messages[1] test invariant").parentId).not.toBe(
expectDefined(messages[1], "messages[1] test invariant").id,
);
});
it("preserves compaction indexes across opaque rows", () => {
+4 -3
View File
@@ -3,6 +3,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { applyPatch } from "diff";
import { Value } from "typebox/value";
import { afterEach, describe, expect, it, vi } from "vitest";
@@ -373,7 +374,7 @@ describe("edit tool", () => {
undefined,
);
const tc0 = result.content[0];
const tc0 = expectDefined(result.content[0], "result.content[0] test invariant");
expect("text" in tc0 ? tc0.text : "").toContain("No changes made");
expect((result as any).terminate).toBe(true);
await expect(fs.readFile(filePath, "utf-8")).resolves.toBe("unchanged content\n");
@@ -599,7 +600,7 @@ describe("edit tool", () => {
undefined,
);
const tcText = result.content[0];
const tcText = expectDefined(result.content[0], "result.content[0] test invariant");
expect("text" in tcText ? tcText.text : "").toContain("Successfully replaced");
expect((result as any).terminate).toBeFalsy();
await expect(fs.readFile(filePath, "utf-8")).resolves.toBe("alpha beta GAMMA\n");
@@ -618,7 +619,7 @@ describe("edit tool", () => {
undefined,
);
const tc1 = result.content[0];
const tc1 = expectDefined(result.content[0], "result.content[0] test invariant");
expect("text" in tc1 ? tc1.text : "").toContain("Successfully replaced");
await expect(fs.readFile(filePath, "utf-8")).resolves.toBe("new content\n");
});
+2 -1
View File
@@ -4,6 +4,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, describe, expect, it } from "vitest";
import { createWriteTool, type WriteOperations } from "./write.js";
@@ -135,7 +136,7 @@ describe("write tool", () => {
undefined,
);
const tc0 = result.content[0];
const tc0 = expectDefined(result.content[0], "result.content[0] test invariant");
expect("text" in tc0 ? tc0.text : "").toContain("No changes made");
expect((result as any).terminate).toBe(true);
await expect(fs.readFile(filePath, "utf-8")).resolves.toBe("hello\n");
+18 -4
View File
@@ -3,6 +3,7 @@ import { spawnSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { captureEnv, setTestEnvValue } from "../test-utils/env.js";
import {
@@ -208,7 +209,10 @@ describe("exec shell snapshots", () => {
.filter((entry) => entry.endsWith(".sh"));
expect(snapshotFiles).toHaveLength(1);
const snapshot = fs.readFileSync(
path.join(resolveShellSnapshotDir(env), snapshotFiles[0]),
path.join(
resolveShellSnapshotDir(env),
expectDefined(snapshotFiles[0], "snapshotFiles[0] test invariant"),
),
"utf8",
);
expect(snapshot).toContain("oc_snap_fn");
@@ -396,7 +400,10 @@ describe("exec shell snapshots", () => {
.filter((entry) => entry.endsWith(".sh"));
expect(snapshotFiles).toHaveLength(1);
const snapshot = fs.readFileSync(
path.join(resolveShellSnapshotDir(env), snapshotFiles[0]),
path.join(
resolveShellSnapshotDir(env),
expectDefined(snapshotFiles[0], "snapshotFiles[0] test invariant"),
),
"utf8",
);
expect(snapshot).not.toContain("virtual");
@@ -447,7 +454,11 @@ describe("exec shell snapshots", () => {
const snapshotFiles = fs.readdirSync(snapshotDir).filter((entry) => entry.endsWith(".sh"));
expect(snapshotFiles).toHaveLength(1);
const staleTime = new Date(Date.now() - 10 * 60 * 1000);
fs.utimesSync(path.join(snapshotDir, snapshotFiles[0]), staleTime, staleTime);
fs.utimesSync(
path.join(snapshotDir, expectDefined(snapshotFiles[0], "snapshotFiles[0] test invariant")),
staleTime,
staleTime,
);
resetShellSnapshotCacheForTests();
await expect(runAlias()).resolves.toBe("new");
@@ -486,7 +497,10 @@ describe("exec shell snapshots", () => {
const snapshotDir = resolveShellSnapshotDir(env);
const snapshotFiles = fs.readdirSync(snapshotDir).filter((entry) => entry.endsWith(".sh"));
expect(snapshotFiles).toHaveLength(1);
const snapshotPath = path.join(snapshotDir, snapshotFiles[0]);
const snapshotPath = path.join(
snapshotDir,
expectDefined(snapshotFiles[0], "snapshotFiles[0] test invariant"),
);
fs.writeFileSync(
snapshotPath,
[
@@ -1,5 +1,7 @@
// Nested subagent registry e2e tests cover requester/controller relationships
// across orchestrator and leaf child sessions.
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import "./subagent-registry.mocks.shared.js";
@@ -62,12 +64,12 @@ describe("subagent registry nested agent tracking", () => {
// Main sees its direct child (the orchestrator)
const mainRuns = listSubagentRunsForRequester("agent:main:main");
expect(mainRuns).toHaveLength(1);
expect(mainRuns[0].runId).toBe("run-orch");
expect(expectDefined(mainRuns[0], "mainRuns[0] test invariant").runId).toBe("run-orch");
// Orchestrator sees its direct child (the leaf)
const orchRuns = listSubagentRunsForRequester("agent:main:subagent:orch-uuid");
expect(orchRuns).toHaveLength(1);
expect(orchRuns[0].runId).toBe("run-leaf");
expect(expectDefined(orchRuns[0], "orchRuns[0] test invariant").runId).toBe("run-leaf");
// Leaf has no children
const leafRuns = listSubagentRunsForRequester(
@@ -94,8 +96,12 @@ describe("subagent registry nested agent tracking", () => {
const { listSubagentRunsForRequester } = subagentRegistry;
const orchRuns = listSubagentRunsForRequester("agent:main:subagent:orch");
expect(orchRuns).toHaveLength(1);
expect(orchRuns[0].requesterSessionKey).toBe("agent:main:subagent:orch");
expect(orchRuns[0].childSessionKey).toBe("agent:main:subagent:orch:subagent:child");
expect(expectDefined(orchRuns[0], "orchRuns[0] test invariant").requesterSessionKey).toBe(
"agent:main:subagent:orch",
);
expect(expectDefined(orchRuns[0], "orchRuns[0] test invariant").childSessionKey).toBe(
"agent:main:subagent:orch:subagent:child",
);
});
it("countActiveRunsForSession only counts active children of the specific session", () => {
@@ -4,6 +4,7 @@ import fsSync from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import "./subagent-registry.mocks.shared.js";
import { replaceSessionEntry } from "../config/sessions/session-accessor.js";
@@ -662,7 +663,10 @@ describe("subagent registry persistence", () => {
const afterSecond = JSON.parse(await fs.readFile(registryPath, "utf8")) as {
runs: Record<string, { cleanupCompletedAt?: number }>;
};
expect(afterSecond.runs["run-3"].cleanupCompletedAt).toBeGreaterThanOrEqual(beforeRetry);
expect(
expectDefined(afterSecond.runs["run-3"], 'afterSecond.runs["run-3"] test invariant')
.cleanupCompletedAt,
).toBeGreaterThanOrEqual(beforeRetry);
});
it("retries cleanup announce after announce flow rejects", async () => {
@@ -692,8 +696,14 @@ describe("subagent registry persistence", () => {
const afterFirst = JSON.parse(await fs.readFile(registryPath, "utf8")) as {
runs: Record<string, { cleanupHandled?: boolean; cleanupCompletedAt?: number }>;
};
expect(afterFirst.runs["run-reject"].cleanupHandled).toBe(false);
expect(afterFirst.runs["run-reject"].cleanupCompletedAt).toBeUndefined();
expect(
expectDefined(afterFirst.runs["run-reject"], 'afterFirst.runs["run-reject"] test invariant')
.cleanupHandled,
).toBe(false);
expect(
expectDefined(afterFirst.runs["run-reject"], 'afterFirst.runs["run-reject"] test invariant')
.cleanupCompletedAt,
).toBeUndefined();
announceSpy.mockResolvedValueOnce(true);
const beforeRetry = Date.now();
@@ -709,7 +719,10 @@ describe("subagent registry persistence", () => {
const afterSecond = JSON.parse(await fs.readFile(registryPath, "utf8")) as {
runs: Record<string, { cleanupCompletedAt?: number }>;
};
expect(afterSecond.runs["run-reject"].cleanupCompletedAt).toBeGreaterThanOrEqual(beforeRetry);
expect(
expectDefined(afterSecond.runs["run-reject"], 'afterSecond.runs["run-reject"] test invariant')
.cleanupCompletedAt,
).toBeGreaterThanOrEqual(beforeRetry);
});
it("keeps delete-mode runs retryable when announce is deferred", async () => {
@@ -1,5 +1,7 @@
// Subagent registry steer-restart tests cover replacing child runs after steer
// commands while preserving lifecycle hooks and completion delivery.
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ContextEngine } from "../context-engine/types.js";
import {
@@ -317,7 +319,7 @@ describe("subagent registry steer restarts", () => {
const runs = listMainRuns();
expect(runs).toHaveLength(1);
expect(runs[0].runId).toBe(params.nextRunId);
expect(expectDefined(runs[0], "runs[0] test invariant").runId).toBe(params.nextRunId);
return runs[0];
};
@@ -487,11 +489,14 @@ describe("subagent registry steer restarts", () => {
previous.delivery = { status: "pending", attemptCount: 2, lastAttemptAt: Date.now() };
}
const run = replaceRunAfterSteer({
previousRunId: "run-retry-reset-old",
nextRunId: "run-retry-reset-new",
fallback: previous,
});
const run = expectDefined(
replaceRunAfterSteer({
previousRunId: "run-retry-reset-old",
nextRunId: "run-retry-reset-new",
fallback: previous,
}),
'replaceRunAfterSteer({ previousRunId: "run-retry-reset-old", nextRunI... test invariant',
);
expect(run.delivery?.attemptCount).toBeUndefined();
expect(run.delivery?.lastAttemptAt).toBeUndefined();
}
@@ -514,11 +519,14 @@ describe("subagent registry steer restarts", () => {
previous.outcome = { status: "ok" };
}
const run = replaceRunAfterSteer({
previousRunId: "run-terminal-state-old",
nextRunId: "run-terminal-state-new",
fallback: previous,
});
const run = expectDefined(
replaceRunAfterSteer({
previousRunId: "run-terminal-state-old",
nextRunId: "run-terminal-state-new",
fallback: previous,
}),
'replaceRunAfterSteer({ previousRunId: "run-terminal-state-old", nextR... test invariant',
);
expect(run.endedHookEmittedAt).toBeUndefined();
expect(run.endedReason).toBeUndefined();
@@ -554,11 +562,14 @@ describe("subagent registry steer restarts", () => {
previous.cleanupHandled = true;
}
const run = replaceRunAfterSteer({
previousRunId: "run-frozen-old",
nextRunId: "run-frozen-new",
fallback: previous,
});
const run = expectDefined(
replaceRunAfterSteer({
previousRunId: "run-frozen-old",
nextRunId: "run-frozen-new",
fallback: previous,
}),
'replaceRunAfterSteer({ previousRunId: "run-frozen-old", nextRunId: "r... test invariant',
);
expect(run.completion?.resultText).toBeUndefined();
expect(run.completion?.capturedAt).toBeUndefined();
@@ -585,12 +596,15 @@ describe("subagent registry steer restarts", () => {
expect(previous?.taskRunId).toBe("run-steer-task-old");
expect(previous?.generation).toBe(1);
const run = replaceRunAfterSteer({
previousRunId: "run-steer-task-old",
nextRunId: "run-steer-task-new",
fallback: previous,
task: "new steer instruction from user",
});
const run = expectDefined(
replaceRunAfterSteer({
previousRunId: "run-steer-task-old",
nextRunId: "run-steer-task-new",
fallback: previous,
task: "new steer instruction from user",
}),
'replaceRunAfterSteer({ previousRunId: "run-steer-task-old", nextRunId... test invariant',
);
expect(run.task).toBe("new steer instruction from user");
expect(run.taskRunId).toBe("run-steer-task-old");
@@ -611,11 +625,14 @@ describe("subagent registry steer restarts", () => {
fallback.generation = 2;
mod.releaseSubagentRun(fallback.runId);
const run = replaceRunAfterSteer({
previousRunId: fallback.runId,
nextRunId: "run-fallback-generation-new",
fallback,
});
const run = expectDefined(
replaceRunAfterSteer({
previousRunId: fallback.runId,
nextRunId: "run-fallback-generation-new",
fallback,
}),
'replaceRunAfterSteer({ previousRunId: fallback.runId, nextRunId: "run... test invariant',
);
expect(run.generation).toBe(3);
});
@@ -633,11 +650,14 @@ describe("subagent registry steer restarts", () => {
const previous = listMainRuns()[0];
expect(previous?.runId).toBe("run-task-preserve-old");
const run = replaceRunAfterSteer({
previousRunId: "run-task-preserve-old",
nextRunId: "run-task-preserve-new",
fallback: previous,
});
const run = expectDefined(
replaceRunAfterSteer({
previousRunId: "run-task-preserve-old",
nextRunId: "run-task-preserve-new",
fallback: previous,
}),
'replaceRunAfterSteer({ previousRunId: "run-task-preserve-old", nextRu... test invariant',
);
expect(run.task).toBe("preserve me verbatim");
});
@@ -648,19 +668,25 @@ describe("subagent registry steer restarts", () => {
childSessionKey: "agent:main:subagent:legacy-owner",
task: "legacy owner task",
});
const first = replaceRunAfterSteer({
previousRunId: "run-legacy-owner-original",
nextRunId: "run-legacy-owner-restored",
});
const first = expectDefined(
replaceRunAfterSteer({
previousRunId: "run-legacy-owner-original",
nextRunId: "run-legacy-owner-restored",
}),
'replaceRunAfterSteer({ previousRunId: "run-legacy-owner-original", ne... test invariant',
);
// Pre-change persisted replacement rows did not record taskRunId.
first.taskRunId = undefined;
first.sessionStartedAt = first.createdAt - 1;
const second = replaceRunAfterSteer({
previousRunId: "run-legacy-owner-restored",
nextRunId: "run-legacy-owner-next",
fallback: first,
});
const second = expectDefined(
replaceRunAfterSteer({
previousRunId: "run-legacy-owner-restored",
nextRunId: "run-legacy-owner-next",
fallback: first,
}),
'replaceRunAfterSteer({ previousRunId: "run-legacy-owner-restored", ne... test invariant',
);
expect(second.taskRunId).toBeUndefined();
expect(second.generation).toBe(3);
});
+5 -1
View File
@@ -3,6 +3,7 @@
import { promises as fs } from "node:fs";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { SessionEntry } from "../config/sessions.js";
import type {
@@ -3935,7 +3936,10 @@ describe("subagent registry seam flow", () => {
string,
SessionEntry
>;
const current = store[scope.sessionKey];
const current = expectDefined(
store[scope.sessionKey],
"store[scope.sessionKey] test invariant",
);
const patch = await update(current, { existingEntry: { ...current } });
if (patch) {
mocks.updateSessionStore(scope.storePath, () => {});
+5 -1
View File
@@ -1,3 +1,4 @@
import { expectDefined } from "@openclaw/normalization-core";
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import {
@@ -405,7 +406,10 @@ describe("sessions_spawn context modes", () => {
expect(ensureContextEnginesInitializedMock).toHaveBeenCalledTimes(1);
expect(resolveContextEngineMock).toHaveBeenCalledTimes(1);
expect(ensureContextEnginesInitializedMock.mock.invocationCallOrder[0]).toBeLessThan(
resolveContextEngineMock.mock.invocationCallOrder[0],
expectDefined(
resolveContextEngineMock.mock.invocationCallOrder[0],
"resolveContextEngineMock.mock.invocationCallOrder[0] test invariant",
),
);
});
+3 -1
View File
@@ -1,5 +1,7 @@
// System prompt stability tests cover deterministic workspace bootstrap file
// loading so prompt-cache inputs stay byte-stable.
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it, beforeEach } from "vitest";
import { makeTempWorkspace, writeWorkspaceFile } from "../test-helpers/workspace.js";
import {
@@ -98,7 +100,7 @@ describe("system prompt stability for cache hits", () => {
// All results should have the same file order
for (let i = 1; i < results.length; i++) {
const names1 = results[0].map((f) => f.name);
const namesI = results[i].map((f) => f.name);
const namesI = expectDefined(results[i], "results[i] test invariant").map((f) => f.name);
expect(namesI).toEqual(names1);
}
});
+6 -2
View File
@@ -1,5 +1,7 @@
// Tool image tests cover image payload sanitization before tool outputs are
// returned to model-visible content blocks.
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import {
createNoisyPngBuffer,
@@ -61,7 +63,9 @@ describe("tool image sanitizing", () => {
});
expect(dropped).toBe(0);
expect(out.length).toBe(1);
const meta = await getImageMetadata(Buffer.from(out[0].data, "base64"));
const meta = await getImageMetadata(
Buffer.from(expectDefined(out[0], "out[0] test invariant").data, "base64"),
);
expect(meta?.width).toBeLessThanOrEqual(120);
expect(meta?.height).toBeLessThanOrEqual(120);
}, 20_000);
@@ -158,7 +162,7 @@ describe("tool image sanitizing", () => {
];
const out = await sanitizeContentBlocksImages(blocks, "browser:screenshot");
expect(out).toHaveLength(1);
expect(out[0].type).toBe("text");
expect(expectDefined(out[0], "out[0] test invariant").type).toBe("text");
expect((out[0] as { type: "text"; text: string }).text).toContain("missing data or mimeType");
});
+3 -1
View File
@@ -1,5 +1,7 @@
// Live tool replay repair tests validate repaired historical transcripts across
// selected real model providers.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
import type { Context, Model } from "openclaw/plugin-sdk/llm";
@@ -300,7 +302,7 @@ describeLive("tool replay repair live", () => {
"toolResult",
"user",
]);
const assistantMessage = sanitized[1];
const assistantMessage = expectDefined(sanitized[1], "sanitized[1] test invariant");
expect(assistantMessage?.role).toBe("assistant");
expect(
sanitized.slice(2, 5).map((message) => (message as { toolCallId?: string }).toolCallId),
+91 -50
View File
@@ -1,5 +1,7 @@
// Tool search tests cover catalog compaction, scoped tool lookup, raw fallback
// tools, hooks, abort wrapping, and transcript projection.
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, describe, expect, it, vi } from "vitest";
import { setPluginToolMeta } from "../plugins/tools.js";
import { wrapToolWithAbortSignal } from "./agent-tools.abort.js";
@@ -233,13 +235,16 @@ describe("Tool Search", () => {
sessionKey: "agent:main:main",
config: compacted.tools[0] ? {} : undefined,
});
const result = await runtimeCodeTool.execute("call-1", {
code: `
const result = await expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-1",
{
code: `
const hits = await openclaw.tools.search("ticket", { limit: 1 });
const described = await openclaw.tools.describe(hits[0].id);
return await openclaw.tools.call(described.id, { value: "ship" });
`,
});
},
);
const alphaCall = mockCall(vi.mocked(alpha.execute));
expect(alphaCall[0]).toBe("tool_search_code:call-1:fake_create_ticket:1");
@@ -293,7 +298,7 @@ describe("Tool Search", () => {
runId: "run-a",
config,
});
const runACallTool = runATools[3];
const runACallTool = expectDefined(runATools[3], "runATools[3] test invariant");
await runACallTool.execute("call-run-a", {
id: "fake_run_a",
args: { value: "A" },
@@ -342,7 +347,7 @@ describe("Tool Search", () => {
catalogRef: localRef,
config,
});
const callTool = tools[3];
const callTool = expectDefined(tools[3], "tools[3] test invariant");
await callTool.execute("call-local-ref", {
id: "fake_local_ref",
args: { value: "local" },
@@ -1026,7 +1031,7 @@ describe("Tool Search", () => {
sessionKey: "agent:main:main",
config: {},
});
await runtimeCodeTool.execute("call-hooks", {
await expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute("call-hooks", {
code: `return await openclaw.tools.call("fake_hooked", { value: "ok" });`,
});
const targetCall = mockCall(vi.mocked(target.execute));
@@ -1080,12 +1085,15 @@ describe("Tool Search", () => {
sessionKey: "agent:main:main",
config: {},
});
await runtimeCodeTool.execute("call-repeated", {
code: `
await expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-repeated",
{
code: `
await openclaw.tools.call("fake_repeated", { value: "one" });
return await openclaw.tools.call("fake_repeated", { value: "two" });
`,
});
},
);
const firstCall = mockCall(vi.mocked(target.execute));
expect(firstCall[0]).toBe("tool_search_code:call-repeated:fake_repeated:1");
@@ -1099,9 +1107,12 @@ describe("Tool Search", () => {
expect(secondCall[2]).toBeInstanceOf(AbortSignal);
expect(secondCall[3]).toBeUndefined();
expect(secondCall[4]).toBeUndefined();
await runtimeCodeTool.execute("call-repeated-again", {
code: `return await openclaw.tools.call("fake_repeated", { value: "three" });`,
});
await expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-repeated-again",
{
code: `return await openclaw.tools.call("fake_repeated", { value: "three" });`,
},
);
const thirdCall = mockCall(vi.mocked(target.execute), 2);
expect(thirdCall[0]).toBe("tool_search_code:call-repeated-again:fake_repeated:1");
@@ -1157,8 +1168,8 @@ describe("Tool Search", () => {
abortSignal: abortController.signal,
executeTool,
});
const runtimeCodeTool = runtimeTools[0];
const runtimeCallTool = runtimeTools[3];
const runtimeCodeTool = expectDefined(runtimeTools[0], "runtime code tool");
const runtimeCallTool = expectDefined(runtimeTools[3], "runtimeTools[3] test invariant");
await runtimeCodeTool.execute(
"call-lifecycle",
{
@@ -1315,12 +1326,15 @@ describe("Tool Search", () => {
sessionKey: "agent:main:main",
config: {},
});
const result = await runtimeCodeTool.execute("call-fire-and-forget", {
code: `
const result = await expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-fire-and-forget",
{
code: `
openclaw.tools.call("fake_fire_and_forget", { value: "late" });
return "done";
`,
});
},
);
expect(target.execute).not.toHaveBeenCalled();
const details = resultDetails(result);
@@ -1355,7 +1369,7 @@ describe("Tool Search", () => {
config: {},
});
let settled = false;
const resultPromise = runtimeCodeTool
const resultPromise = expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant")
.execute("call-started-bridge", {
code: `
openclaw.tools.call("fake_then_started", { value: "started" }).then(() => {});
@@ -1389,24 +1403,33 @@ describe("Tool Search", () => {
});
await expect(
runtimeCodeTool.execute("call-escape", {
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute("call-escape", {
code: `return Function("return process")();`,
}),
).rejects.toThrow();
await expect(
runtimeCodeTool.execute("call-constructor-escape", {
code: `return globalThis.constructor.constructor("return process")();`,
}),
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-constructor-escape",
{
code: `return globalThis.constructor.constructor("return process")();`,
},
),
).rejects.toThrow();
await expect(
runtimeCodeTool.execute("call-console-escape", {
code: `return console.log.constructor.constructor("return process")();`,
}),
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-console-escape",
{
code: `return console.log.constructor.constructor("return process")();`,
},
),
).rejects.toThrow();
await expect(
runtimeCodeTool.execute("call-bridge-escape", {
code: `return openclaw.tools.call.constructor.constructor("return process")();`,
}),
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-bridge-escape",
{
code: `return openclaw.tools.call.constructor.constructor("return process")();`,
},
),
).rejects.toThrow();
});
@@ -1427,7 +1450,7 @@ describe("Tool Search", () => {
sessionKey: "agent:main:main",
config: { tools: { toolSearch: { mode: "tools" } } } as never,
});
const runtimeCallTool = runtimeTools[3];
const runtimeCallTool = expectDefined(runtimeTools[3], "runtimeTools[3] test invariant");
await expect(
runtimeCallTool.execute("call-guessed-file-write", {
@@ -1460,10 +1483,13 @@ describe("Tool Search", () => {
});
await expect(
runtimeTools[3].execute("call-duplicate-write", {
id: "file_write",
args: {},
}),
expectDefined(runtimeTools[3], "runtimeTools[3] test invariant").execute(
"call-duplicate-write",
{
id: "file_write",
args: {},
},
),
).rejects.toThrow("Did you mean: openclaw:first-plugin:write, openclaw:second-plugin:write?");
});
@@ -1484,7 +1510,7 @@ describe("Tool Search", () => {
sessionKey: "agent:main:main",
config: { tools: { toolSearch: { mode: "tools" } } } as never,
});
const runtimeCallTool = runtimeTools[3];
const runtimeCallTool = expectDefined(runtimeTools[3], "runtimeTools[3] test invariant");
await expect(
runtimeCallTool.execute("call-missing-raw-tool", {
@@ -1514,9 +1540,12 @@ describe("Tool Search", () => {
});
await expect(
runtimeCodeTool.execute("call-code-guessed-file-write", {
code: `return await openclaw.tools.call("file_write", { path: "memory/2026-05-22.md" });`,
}),
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-code-guessed-file-write",
{
code: `return await openclaw.tools.call("file_write", { path: "memory/2026-05-22.md" });`,
},
),
).rejects.toThrow(
"Unknown tool id: file_write. Did you mean: write? Use openclaw.tools.search to find a tool, openclaw.tools.describe to inspect it, then openclaw.tools.call with the exact id or name.",
);
@@ -1539,9 +1568,12 @@ describe("Tool Search", () => {
});
await expect(
runtimeCodeTool.execute("call-missing-tool", {
code: `return await openclaw.tools.call("missing_tool", {});`,
}),
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-missing-tool",
{
code: `return await openclaw.tools.call("missing_tool", {});`,
},
),
).rejects.toThrow(
"Unknown tool id: missing_tool. Use openclaw.tools.search to find a tool, openclaw.tools.describe to inspect it, then openclaw.tools.call with the exact id or name.",
);
@@ -1565,12 +1597,15 @@ describe("Tool Search", () => {
});
await expect(
runtimeCodeTool.execute("call-bridge-result-escape", {
code: `
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-bridge-result-escape",
{
code: `
const hits = await openclaw.tools.search("bridge result", { limit: 1 });
return hits.constructor.constructor("return process")();
`,
}),
},
),
).rejects.toThrow();
expect(target.execute).not.toHaveBeenCalled();
});
@@ -1593,8 +1628,10 @@ describe("Tool Search", () => {
});
await expect(
runtimeCodeTool.execute("call-controller-escape", {
code: `
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-controller-escape",
{
code: `
})(openclaw, console),
bridgeMessages.push({
id: "forged",
@@ -1604,7 +1641,8 @@ describe("Tool Search", () => {
(async (openclaw, console) => {
return "done";
`,
}),
},
),
).rejects.toThrow();
expect(target.execute).not.toHaveBeenCalled();
});
@@ -1634,7 +1672,7 @@ describe("Tool Search", () => {
});
await expect(
runtimeCodeTool.execute("call-timeout", {
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute("call-timeout", {
code: `
await openclaw.tools.search("timeout", { limit: 1 });
while (true) {}
@@ -1694,9 +1732,12 @@ describe("Tool Search", () => {
});
await expect(
runtimeCodeTool.execute("call-abort-timeout", {
code: `return await openclaw.tools.call("fake_abort_on_timeout", { value: "wait" });`,
}),
expectDefined(runtimeCodeTool, "runtimeCodeTool test invariant").execute(
"call-abort-timeout",
{
code: `return await openclaw.tools.call("fake_abort_on_timeout", { value: "wait" });`,
},
),
).rejects.toThrow("tool_search_code timed out");
if (!observedSignal) {
throw new Error("Expected observed abort signal");
+13 -6
View File
@@ -1,5 +1,6 @@
// Gateway call helper tests pin URL override, token, and RPC scope behavior for
// agent tools that route through the local gateway client.
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
import { verifyAgentRuntimeIdentityToken } from "../../gateway/agent-runtime-identity-token.js";
import type { CallGatewayOptions } from "../../gateway/call.js";
@@ -269,9 +270,12 @@ describe("gateway tool defaults", () => {
);
expect(mocks.callGateway).toHaveBeenCalledTimes(1);
const [[callParams]] = mocks.callGateway.mock.calls as unknown as Array<
[{ method?: string; scopes?: string[] }]
>;
const [callParams] = expectDefined(
(
mocks.callGateway.mock.calls as unknown as Array<[{ method?: string; scopes?: string[] }]>
)[0],
"(mocks.callGateway.mock.calls as unknown as Array<[{ method?: string; scopes?: string[] }]>)[0] test invariant",
);
expect(callParams.method).toBe("plugins.sessionAction");
expect(callParams.scopes).toEqual(["operator.approvals"]);
});
@@ -290,9 +294,12 @@ describe("gateway tool defaults", () => {
);
expect(mocks.callGateway).toHaveBeenCalledTimes(1);
const [[callParams]] = mocks.callGateway.mock.calls as unknown as Array<
[{ method?: string; scopes?: string[] }]
>;
const [callParams] = expectDefined(
(
mocks.callGateway.mock.calls as unknown as Array<[{ method?: string; scopes?: string[] }]>
)[0],
"(mocks.callGateway.mock.calls as unknown as Array<[{ method?: string; scopes?: string[] }]>)[0] test invariant",
);
expect(callParams.method).toBe("plugins.sessionAction");
expect(callParams.scopes).toEqual([
"operator.admin",
@@ -3,6 +3,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, describe, expect, it } from "vitest";
import type { ModelApi } from "../../config/types.models.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
@@ -91,7 +92,7 @@ function readJpegDimensions(buffer: Buffer): { width: number; height: number } {
offset += 1;
continue;
}
const marker = buffer[offset + 1];
const marker = expectDefined(buffer[offset + 1], "buffer[offset + 1] test invariant");
offset += 2;
if (marker === 0xd8 || marker === 0xd9 || (marker >= 0xd0 && marker <= 0xd7)) {
continue;
+2 -1
View File
@@ -5,6 +5,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { isInboundPathAllowed } from "@openclaw/media-core/inbound-path-policy";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
import type { ModelDefinitionConfig } from "../../config/types.models.js";
@@ -302,7 +303,7 @@ function readJpegDimensions(buffer: Buffer): { width: number; height: number } {
offset += 1;
continue;
}
const marker = buffer[offset + 1];
const marker = expectDefined(buffer[offset + 1], "buffer[offset + 1] test invariant");
offset += 2;
if (marker === 0xd8 || marker === 0xd9 || (marker >= 0xd0 && marker <= 0xd7)) {
continue;
@@ -3,6 +3,7 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import type { callGateway as gatewayCall } from "../../gateway/call.js";
import { deleteTestEnvValue, setTestEnvValue } from "../../test-utils/env.js";
@@ -150,7 +151,10 @@ describe("sessions_history redaction", () => {
method: "chat.history",
params: { sessionKey: "main", limit: 2 },
});
expect((requests[0].params as Record<string, unknown>).offset).toBeUndefined();
expect(
(expectDefined(requests[0], "requests[0] test invariant").params as Record<string, unknown>)
.offset,
).toBeUndefined();
expect((result.details as Record<string, unknown>).offset).toBeUndefined();
});
+7 -2
View File
@@ -2,6 +2,7 @@
// announce-target resolution, and assistant-visible text sanitization.
import os from "node:os";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ChannelMessagingAdapter } from "../../channels/plugins/types.js";
@@ -1033,8 +1034,12 @@ describe("sessions_send gating", () => {
if (kind !== "group") {
return null;
}
const [id, threadId] = rawId.split(":topic:");
return threadId ? { id, threadId, baseConversationId: id } : null;
const [rawConversationId, threadId] = rawId.split(":topic:");
if (!threadId) {
return null;
}
const id = expectDefined(rawConversationId, "Telegram conversation id");
return { id, threadId, baseConversationId: id };
});
setRuntimeConfigSnapshot({ plugins: { entries: { telegram: { enabled: true } } } });
expect(parseSessionThreadInfo(topicSessionKey).threadId).toBe("77");
+14 -3
View File
@@ -1,5 +1,7 @@
// TTS tool tests cover guidance, speech runtime arguments, delivery metadata,
// timeout validation, and reply-directive defusing.
import { expectDefined } from "@openclaw/normalization-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
import * as ttsRuntime from "../../tts/tts.js";
import { createTtsTool } from "./tts-tool.js";
@@ -171,7 +173,10 @@ describe("createTtsTool", () => {
const tool = createTtsTool();
const result = await tool.execute("call-1", { text: spoken });
const rendered = (result.content as Array<{ type: string; text: string }>)[0].text;
const rendered = expectDefined(
(result.content as Array<{ type: string; text: string }>)[0],
"(result.content as Array<{ type: string; text: string }>)[0] test invariant",
).text;
// The literal directive tokens must not appear verbatim, so
// parseReplyDirectives can no longer surface them as media/audio flags.
expect(rendered).not.toMatch(/^MEDIA:/m);
@@ -194,7 +199,10 @@ describe("createTtsTool", () => {
const tool = createTtsTool();
const result = await tool.execute("call-1", { text: spoken });
const rendered = (result.content as Array<{ type: string; text: string }>)[0].text;
const rendered = expectDefined(
(result.content as Array<{ type: string; text: string }>)[0],
"(result.content as Array<{ type: string; text: string }>)[0] test invariant",
).text;
expect(rendered).toContain("\u00A0\u2060MEDIA:/tmp/secret.png");
expect(rendered).not.toMatch(/^\u00A0MEDIA:/m);
});
@@ -211,7 +219,10 @@ describe("createTtsTool", () => {
const tool = createTtsTool();
const result = await tool.execute("call-1", { text: spoken });
const rendered = (result.content as Array<{ type: string; text: string }>)[0].text;
const rendered = expectDefined(
(result.content as Array<{ type: string; text: string }>)[0],
"(result.content as Array<{ type: string; text: string }>)[0] test invariant",
).text;
expect(rendered).not.toMatch(/^[ \t]*```/m);
expect(rendered).toContain("`\u2060``");
expect(rendered).toContain("\u2060MEDIA:");
+5 -1
View File
@@ -1,5 +1,6 @@
// web_fetch SSRF tests cover URL, DNS, redirect, and proxy policy enforcement
// before network requests reach fetch or provider fallbacks.
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import * as ssrf from "../../infra/net/ssrf.js";
import { type FetchMock, withFetchPreconnect } from "../../test-utils/fetch-mock.js";
@@ -44,7 +45,10 @@ function expectRawFetchSuccessDetails(details: unknown) {
function firstFetchUrl(fetchSpy: ReturnType<typeof setMockFetch>): string {
const input = fetchSpy.mock.calls[0]?.[0];
return input instanceof Request ? input.url : input instanceof URL ? input.href : input;
return expectDefined(
input instanceof Request ? input.url : input instanceof URL ? input.href : input,
"input instanceof Request ? input.url : input instanceof URL ? input.h... test invariant",
);
}
function createWebFetchToolForTest(params?: {
+196 -73
View File
@@ -1,5 +1,7 @@
// Transcript redaction tests cover structured and text transcript fields so
// secrets do not persist in logs or replay artifacts.
import { expectDefined } from "@openclaw/normalization-core";
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js";
@@ -74,7 +76,10 @@ describe("redactTranscriptMessage", () => {
it("redacts text block matching default patterns (sk- token)", () => {
const msg = textMessage("key is sk-abcdef1234567890xyz end");
const result = redactTranscriptMessage(msg, cfg("tools"));
const text = (msgContent(result) as Array<{ text: string }>)[0].text;
const text = expectDefined(
(msgContent(result) as Array<{ text: string }>)[0],
"(msgContent(result) as Array<{ text: string }>)[0] test invariant",
).text;
expect(text).not.toContain("sk-abcdef1234567890xyz");
expect(text).toContain("end");
});
@@ -87,7 +92,10 @@ describe("redactTranscriptMessage", () => {
],
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ thinking: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ thinking: string }>)[0],
"(msgContent(result) as Array<{ thinking: string }>)[0] test invariant",
);
expect(block.thinking).not.toContain("sk-abcdef1234567890xyz");
});
@@ -139,7 +147,10 @@ describe("redactTranscriptMessage", () => {
msg,
cfg("tools", ["reasoning-1", "reasoning", "summary_text"]),
);
const block = (msgContent(result) as Array<{ thinking: string; thinkingSignature: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ thinking: string; thinkingSignature: string }>)[0],
"(msgContent(result) as Array<{ thinking: string; thinkingSignature: s... test invariant",
);
const replayItem = JSON.parse(block.thinkingSignature) as {
id: string;
type: string;
@@ -150,8 +161,10 @@ describe("redactTranscriptMessage", () => {
};
const blockMetadata = (block as unknown as { openclawReasoningReplay: Record<string, unknown> })
.openclawReasoningReplay;
const rejectedSignature = (msgContent(result) as Array<{ thinkingSignature: string }>)[1]
.thinkingSignature;
const rejectedSignature = expectDefined(
(msgContent(result) as Array<{ thinkingSignature: string }>)[1],
"(msgContent(result) as Array<{ thinkingSignature: string }>)[1] test invariant",
).thinkingSignature;
expect(block.thinking).not.toContain("sk-abcdef1234567890xyz");
expect(replayItem.id).toBe("reasoning-1");
expect(replayItem.type).toBe("reasoning");
@@ -255,8 +268,13 @@ describe("redactTranscriptMessage", () => {
SHORT_GOOGLE_THOUGHT_SIGNATURE,
]),
);
const preservedBlock = (msgContent(result) as Array<Record<string, string>>)[0];
expect(preservedBlock[signatureKey]).toBe(expectedSignature);
const preservedBlock = expectDefined(
(msgContent(result) as Array<Record<string, string>>)[0],
"(msgContent(result) as Array<Record<string, string>>)[0] test invariant",
);
expect(
expectDefined(preservedBlock[signatureKey], "preservedBlock[signatureKey] test invariant"),
).toBe(expectedSignature);
},
);
@@ -286,7 +304,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ thoughtSignature: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ thoughtSignature: string }>)[0],
"(msgContent(result) as Array<{ thoughtSignature: string }>)[0] test invariant",
);
expect(JSON.parse(block.thoughtSignature)).toEqual({
type: "reasoning.encrypted",
data: CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES,
@@ -318,7 +339,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ thoughtSignature: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ thoughtSignature: string }>)[0],
"(msgContent(result) as Array<{ thoughtSignature: string }>)[0] test invariant",
);
expect(JSON.parse(block.thoughtSignature)).toEqual({
type: "reasoning.encrypted",
data: CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES,
@@ -358,12 +382,15 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (
msgContent(result) as Array<{
thoughtSignature: string;
arguments: Record<string, string>;
}>
)[0];
const block = expectDefined(
(
msgContent(result) as Array<{
thoughtSignature: string;
arguments: Record<string, string>;
}>
)[0],
"( msgContent(result) as Array<{ thoughtSignature: string; arguments: ... test invariant",
);
expect(block.thoughtSignature).toBe(GOOGLE_THOUGHT_SIGNATURE);
expect(JSON.stringify(block.arguments)).not.toContain("sk-abcdef1234567890xyz");
expect(block.arguments.apiKey).toBe("plains…e123");
@@ -395,11 +422,21 @@ describe("redactTranscriptMessage", () => {
const result = redactTranscriptMessage(msg, cfg("tools", [GOOGLE_THOUGHT_SIGNATURE]));
const blocks = msgContent(result) as Array<Record<string, string>>;
expect(blocks[0].text).not.toContain("sk-abcdef1234567890xyz");
expect(blocks[0].textSignature).toBe(GOOGLE_THOUGHT_SIGNATURE);
expect(blocks[1].textSignature).not.toContain("sk-abcdef1234567890xyz");
expect(blocks[2].thinking).not.toContain("sk-abcdef1234567890xyz");
expect(blocks[2].thought_signature).toBe(SHORT_GOOGLE_THOUGHT_SIGNATURE);
expect(expectDefined(blocks[0], "blocks[0] test invariant").text).not.toContain(
"sk-abcdef1234567890xyz",
);
expect(expectDefined(blocks[0], "blocks[0] test invariant").textSignature).toBe(
GOOGLE_THOUGHT_SIGNATURE,
);
expect(expectDefined(blocks[1], "blocks[1] test invariant").textSignature).not.toContain(
"sk-abcdef1234567890xyz",
);
expect(expectDefined(blocks[2], "blocks[2] test invariant").thinking).not.toContain(
"sk-abcdef1234567890xyz",
);
expect(expectDefined(blocks[2], "blocks[2] test invariant").thought_signature).toBe(
SHORT_GOOGLE_THOUGHT_SIGNATURE,
);
});
it.each(["openai-responses", "openclaw-openai-responses-transport"])(
@@ -414,7 +451,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools", [COPILOT_CONNECTION_BOUND_ID]));
const block = (msgContent(result) as Array<{ textSignature: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ textSignature: string }>)[0],
"(msgContent(result) as Array<{ textSignature: string }>)[0] test invariant",
);
expect(block.textSignature).toBe(textSignature);
},
);
@@ -444,17 +484,21 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const thinkingBlock = (
msgContent(result) as Array<{ thinking: string; thinkingSignature: string }>
)[0];
const redactedBlock = (
msgContent(result) as Array<{
data: string;
signature: string;
thinkingSignature: string;
metadata: { accessToken: string };
}>
)[1];
const thinkingBlock = expectDefined(
(msgContent(result) as Array<{ thinking: string; thinkingSignature: string }>)[0],
"( msgContent(result) as Array<{ thinking: string; thinkingSignature: ... test invariant",
);
const redactedBlock = expectDefined(
(
msgContent(result) as Array<{
data: string;
signature: string;
thinkingSignature: string;
metadata: { accessToken: string };
}>
)[1],
"( msgContent(result) as Array<{ data: string; signature: string; thin... test invariant",
);
expect(thinkingBlock.thinking).not.toContain("sk-abcdef1234567890xyz");
expect(thinkingBlock.thinkingSignature).toBe(CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES);
expect(redactedBlock.data).toBe(CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES);
@@ -562,37 +606,59 @@ describe("redactTranscriptMessage", () => {
const googleBlocks = msgContent(redactTranscriptMessage(googleMsg, cfg("tools"))) as Array<
Record<string, string>
>;
expect(googleBlocks[0].thoughtSignature).toBe(GOOGLE_CREDENTIAL_COLLISION);
expect(googleBlocks[1].thinkingSignature).toBe(ALIBABA_CREDENTIAL_COLLISION);
expect(expectDefined(googleBlocks[0], "googleBlocks[0] test invariant").thoughtSignature).toBe(
GOOGLE_CREDENTIAL_COLLISION,
);
expect(expectDefined(googleBlocks[1], "googleBlocks[1] test invariant").thinkingSignature).toBe(
ALIBABA_CREDENTIAL_COLLISION,
);
const anthropicBlocks = msgContent(
redactTranscriptMessage(anthropicMsg, cfg("tools")),
) as Array<Record<string, string>>;
expect(anthropicBlocks[0].signature).toBe(OPENAI_COMPAT_OPAQUE_COLLISION);
expect(anthropicBlocks[1].data).toBe(githubToken);
expect(expectDefined(anthropicBlocks[0], "anthropicBlocks[0] test invariant").signature).toBe(
OPENAI_COMPAT_OPAQUE_COLLISION,
);
expect(expectDefined(anthropicBlocks[1], "anthropicBlocks[1] test invariant").data).toBe(
githubToken,
);
const completionsBlocks = msgContent(
redactTranscriptMessage(openAICompletionsMsg, cfg("tools")),
) as Array<{ thoughtSignature: string }>;
expect(JSON.parse(completionsBlocks[0].thoughtSignature)).toEqual({
expect(
JSON.parse(
expectDefined(completionsBlocks[0], "completionsBlocks[0] test invariant").thoughtSignature,
),
).toEqual({
type: "reasoning.encrypted",
data: githubToken,
id: "reasoning-encrypted-1",
});
expect(completionsBlocks[1].thoughtSignature).not.toBe(githubToken);
expect(
expectDefined(completionsBlocks[1], "completionsBlocks[1] test invariant").thoughtSignature,
).not.toBe(githubToken);
const googleCompletionsBlock = (
msgContent(redactTranscriptMessage(googleOpenAICompletionsMsg, googleCompatCfg())) as Array<{
thoughtSignature: string;
}>
)[0];
const googleCompletionsBlock = expectDefined(
(
msgContent(
redactTranscriptMessage(googleOpenAICompletionsMsg, googleCompatCfg()),
) as Array<{
thoughtSignature: string;
}>
)[0],
"( msgContent(redactTranscriptMessage(googleOpenAICompletionsMsg, goog... test invariant",
);
expect(googleCompletionsBlock.thoughtSignature).toBe(OPENAI_COMPAT_OPAQUE_COLLISION);
const responsesBlock = (
msgContent(redactTranscriptMessage(openAIResponsesMsg, cfg("tools"))) as Array<{
thinkingSignature: string;
}>
)[0];
const responsesBlock = expectDefined(
(
msgContent(redactTranscriptMessage(openAIResponsesMsg, cfg("tools"))) as Array<{
thinkingSignature: string;
}>
)[0],
'( msgContent(redactTranscriptMessage(openAIResponsesMsg, cfg("tools")... test invariant',
);
expect(JSON.parse(responsesBlock.thinkingSignature)).toEqual({
id: "reasoning-1",
type: "reasoning",
@@ -748,10 +814,17 @@ describe("redactTranscriptMessage", () => {
cfg("tools", [CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES, SHORT_GOOGLE_THOUGHT_SIGNATURE]),
);
const blocks = msgContent(result) as Array<Record<string, string>>;
expect(JSON.parse(blocks[0].thinkingSignature).encrypted_content).toBe(
CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES,
expect(
JSON.parse(
expectDefined(
expectDefined(blocks[0], "thinking block").thinkingSignature,
"thinking signature",
),
).encrypted_content,
).toBe(CIPHERTEXT_WITH_TOKEN_SHAPED_BYTES);
expect(expectDefined(blocks[1], "blocks[1] test invariant").thoughtSignature).toBe(
SHORT_GOOGLE_THOUGHT_SIGNATURE,
);
expect(blocks[1].thoughtSignature).toBe(SHORT_GOOGLE_THOUGHT_SIGNATURE);
});
it("redacts provider-shaped fields outside direct assistant content blocks", () => {
@@ -784,7 +857,10 @@ describe("redactTranscriptMessage", () => {
content: [{ type: "toolCallDelta", partialJson: '{"key":"sk-abcdef1234567890xyz"}' }],
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ partialJson: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ partialJson: string }>)[0],
"(msgContent(result) as Array<{ partialJson: string }>)[0] test invariant",
);
expect(block.partialJson).not.toContain("sk-abcdef1234567890xyz");
});
@@ -806,7 +882,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ arguments: unknown }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ arguments: unknown }>)[0],
"(msgContent(result) as Array<{ arguments: unknown }>)[0] test invariant",
);
const argumentsValue = block.arguments as {
command: string;
env: { nested: string[] };
@@ -819,7 +898,10 @@ describe("redactTranscriptMessage", () => {
expect(argumentsValue.count).toBe(1);
expect(serializedArguments).toContain("openclaw health");
expect(block.arguments).not.toBe(
(msgContent(msg) as Array<{ arguments: unknown }>)[0].arguments,
expectDefined(
(msgContent(msg) as Array<{ arguments: unknown }>)[0],
"(msgContent(msg) as Array<{ arguments: unknown }>)[0] test invariant",
).arguments,
);
});
@@ -842,7 +924,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ arguments: unknown }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ arguments: unknown }>)[0],
"(msgContent(result) as Array<{ arguments: unknown }>)[0] test invariant",
);
const argumentsValue = block.arguments as {
apiKey: string;
password: string;
@@ -878,7 +963,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ input: unknown }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ input: unknown }>)[0],
"(msgContent(result) as Array<{ input: unknown }>)[0] test invariant",
);
const inputValue = block.input as {
apiKey: string;
nested: { accessToken: string[] };
@@ -912,7 +1000,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ input: unknown }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ input: unknown }>)[0],
"(msgContent(result) as Array<{ input: unknown }>)[0] test invariant",
);
const inputValue = block.input as {
password: string;
nested: { accessToken: string[] };
@@ -1004,7 +1095,9 @@ describe("redactTranscriptMessage", () => {
nested: { accessToken: string[] };
safe: string;
};
expect(result.content[0].text).not.toContain("sk-abcdef1234567890xyz");
expect(expectDefined(result.content[0], "result.content[0] test invariant").text).not.toContain(
"sk-abcdef1234567890xyz",
);
expect(serializedDetails).not.toContain("plainsecretvalue123");
expect(serializedDetails).not.toContain("hunter2");
expect(serializedDetails).not.toContain("nestedplainsecret123");
@@ -1038,8 +1131,12 @@ describe("redactTranscriptMessage", () => {
const result = redactTranscriptMessage(msg, cfg("tools"));
const content = msgContent(result) as Array<{ type: string; text?: string; data?: string }>;
expect(content[0].text).not.toContain("sk-abcdef1234567890xyz");
expect(content[1].data).toBe(IMAGE_BASE64_WITH_SECRET_TOKEN_SUBSTRING);
expect(expectDefined(content[0], "content[0] test invariant").text).not.toContain(
"sk-abcdef1234567890xyz",
);
expect(expectDefined(content[1], "content[1] test invariant").data).toBe(
IMAGE_BASE64_WITH_SECRET_TOKEN_SUBSTRING,
);
expect(JSON.stringify(result)).not.toContain("sk-abcdef1234567890xyz");
});
@@ -1057,7 +1154,7 @@ describe("redactTranscriptMessage", () => {
const result = redactTranscriptMessage(msg, cfg("tools"));
const content = msgContent(result) as Array<{ data: string }>;
expect(content[0].data).toBe("sk-abc…0xyz");
expect(expectDefined(content[0], "content[0] test invariant").data).toBe("sk-abc…0xyz");
});
it("preserves valid BMP image base64 while redacting adjacent text", () => {
@@ -1075,8 +1172,12 @@ describe("redactTranscriptMessage", () => {
const result = redactTranscriptMessage(msg, cfg("tools"));
const content = msgContent(result) as Array<{ type: string; text?: string; data?: string }>;
expect(content[0].text).not.toContain("sk-abcdef1234567890xyz");
expect(content[1].data).toBe(BMP_BASE64_WITH_SECRET_TOKEN_SUBSTRING);
expect(expectDefined(content[0], "content[0] test invariant").text).not.toContain(
"sk-abcdef1234567890xyz",
);
expect(expectDefined(content[1], "content[1] test invariant").data).toBe(
BMP_BASE64_WITH_SECRET_TOKEN_SUBSTRING,
);
});
it("preserves provider-style image base64 source data", () => {
@@ -1096,7 +1197,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ source: { data: string }; apiKey: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ source: { data: string }; apiKey: string }>)[0],
"(msgContent(result) as Array<{ source: { data: string }; apiKey: stri... test invariant",
);
expect(block.source.data).toBe(IMAGE_BASE64_WITH_SECRET_TOKEN_SUBSTRING);
expect(block.apiKey).toBe("plains…e123");
});
@@ -1117,9 +1221,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (
msgContent(result) as Array<{ source: { data: string; media_type: string } }>
)[0];
const block = expectDefined(
(msgContent(result) as Array<{ source: { data: string; media_type: string } }>)[0],
"( msgContent(result) as Array<{ source: { data: string; media_type: s... test invariant",
);
expect(block.source.data).toBe(IMAGE_BASE64_WITH_SECRET_TOKEN_SUBSTRING);
expect(block.source.media_type).toBe("image/png");
});
@@ -1138,7 +1243,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ image_url: string; data: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ image_url: string; data: string }>)[0],
"(msgContent(result) as Array<{ image_url: string; data: string }>)[0] test invariant",
);
expect(block.image_url).toBe(dataUrl);
expect(block.data).toBe("AKIDAB…MNOP");
});
@@ -1156,7 +1264,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ image_url: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ image_url: string }>)[0],
"(msgContent(result) as Array<{ image_url: string }>)[0] test invariant",
);
expect(block.image_url).toBe(dataUrl);
});
@@ -1174,7 +1285,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ image_url: string }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ image_url: string }>)[0],
"(msgContent(result) as Array<{ image_url: string }>)[0] test invariant",
);
expect(block.image_url).toBe(canonicalDataUrl);
});
@@ -1191,7 +1305,10 @@ describe("redactTranscriptMessage", () => {
} as unknown as AgentMessage;
const result = redactTranscriptMessage(msg, cfg("tools"));
const block = (msgContent(result) as Array<{ image_url: { url: string } }>)[0];
const block = expectDefined(
(msgContent(result) as Array<{ image_url: { url: string } }>)[0],
"(msgContent(result) as Array<{ image_url: { url: string } }>)[0] test invariant",
);
expect(block.image_url.url).toBe(dataUrl);
});
@@ -1240,7 +1357,10 @@ describe("redactTranscriptMessage", () => {
it("redacts using custom pattern without dropping default patterns", () => {
const msg = textMessage("email peter@dc.io and key sk-abcdef1234567890xyz ok");
const result = redactTranscriptMessage(msg, cfg("tools", [EMAIL_PATTERN]));
const text = (msgContent(result) as Array<{ text: string }>)[0].text;
const text = expectDefined(
(msgContent(result) as Array<{ text: string }>)[0],
"(msgContent(result) as Array<{ text: string }>)[0] test invariant",
).text;
expect(text).not.toContain("peter@dc.io");
expect(text).not.toContain("sk-abcdef1234567890xyz");
expect(text).toContain("ok");
@@ -1322,7 +1442,10 @@ describe("redactTranscriptMessage", () => {
it("redacts with cfg=undefined (falls back to default patterns)", () => {
const msg = textMessage("key is sk-abcdef1234567890xyz");
const result = redactTranscriptMessage(msg, undefined);
const text = (msgContent(result) as Array<{ text: string }>)[0].text;
const text = expectDefined(
(msgContent(result) as Array<{ text: string }>)[0],
"(msgContent(result) as Array<{ text: string }>)[0] test invariant",
).text;
expect(text).not.toContain("sk-abcdef1234567890xyz");
});
+5 -1
View File
@@ -1,4 +1,6 @@
/** Tests text chunking helpers used by auto-reply delivery. */
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it, vi } from "vitest";
import * as fences from "../../packages/markdown-core/src/fences.js";
import { hasBalancedFences } from "../test-utils/chunk-test-helpers.js";
@@ -223,7 +225,9 @@ describe("chunkText", () => {
expectChunkTextCase({ text, limit, assert });
});
runChunkCases(chunkText, [parentheticalCases[0]]);
runChunkCases(chunkText, [
expectDefined(parentheticalCases[0], "parentheticalCases[0] test invariant"),
]);
});
describe("resolveTextChunkLimit", () => {
@@ -2,6 +2,7 @@
import { EventEmitter } from "node:events";
import fs from "node:fs/promises";
import { basename, join } from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, describe, expect, it, vi } from "vitest";
import { slugifySessionKey } from "../agents/sandbox/shared.js";
import { CONFIG_DIR } from "../utils.js";
@@ -171,7 +172,10 @@ describe("stageSandboxMedia scp remote paths", () => {
sessionCtx.MediaPaths = [remotePath];
childProcessMocks.spawn.mockImplementation((_command, argsUnknown) => {
const args = argsUnknown as string[];
const localPath = args[args.length - 1];
const localPath = expectDefined(
args[args.length - 1],
"args[args.length - 1] test invariant",
);
const child = new EventEmitter() as EventEmitter & {
stderr: EventEmitter & { setEncoding: (_encoding: string) => void };
};
@@ -230,7 +234,10 @@ describe("stageSandboxMedia scp remote paths", () => {
sessionCtx.MediaPaths = [remotePath];
childProcessMocks.spawn.mockImplementation((_command, argsUnknown) => {
const args = argsUnknown as string[];
const localPath = args[args.length - 1];
const localPath = expectDefined(
args[args.length - 1],
"args[args.length - 1] test invariant",
);
const child = new EventEmitter() as EventEmitter & {
stderr: EventEmitter & { setEncoding: (_encoding: string) => void };
};
+17 -4
View File
@@ -1,5 +1,6 @@
// Tests abort request handling, cutoff persistence, and active run cleanup.
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { SubagentRunRecord } from "../../agents/subagent-registry.js";
import type { OpenClawConfig } from "../../config/config.js";
@@ -1381,8 +1382,14 @@ describe("abort detection", () => {
expect(result.stoppedSubagents).toBe(1);
expectSessionLaneCleared(depth2Key);
expect(subagentRegistryMocks.markSubagentRunTerminated).toHaveBeenCalledTimes(1);
const [[terminatedRun]] = subagentRegistryMocks.markSubagentRunTerminated.mock
.calls as unknown as Array<[{ runId?: string; childSessionKey?: string }]>;
const [terminatedRun] = expectDefined(
(
subagentRegistryMocks.markSubagentRunTerminated.mock.calls as unknown as Array<
[{ runId?: string; childSessionKey?: string }]
>
)[0],
"(subagentRegistryMocks.markSubagentRunTerminated.mock.calls as unknown as Array<\n [{ runId?: string; childSessionKey?: string }]\n >)[0] test invariant",
);
expect(terminatedRun.runId).toBe("run-2");
expect(terminatedRun.childSessionKey).toBe(depth2Key);
});
@@ -1481,8 +1488,14 @@ describe("abort detection", () => {
expect(result.stoppedSubagents).toBe(1);
expectSessionLaneCleared(depth2Key);
expect(subagentRegistryMocks.markSubagentRunTerminated).toHaveBeenCalledTimes(1);
const [[terminatedRun]] = subagentRegistryMocks.markSubagentRunTerminated.mock
.calls as unknown as Array<[{ runId?: string; childSessionKey?: string }]>;
const [terminatedRun] = expectDefined(
(
subagentRegistryMocks.markSubagentRunTerminated.mock.calls as unknown as Array<
[{ runId?: string; childSessionKey?: string }]
>
)[0],
"(subagentRegistryMocks.markSubagentRunTerminated.mock.calls as unknown as Array<\n [{ runId?: string; childSessionKey?: string }]\n >)[0] test invariant",
);
expect(terminatedRun.runId).toBe("run-active-child");
expect(terminatedRun.childSessionKey).toBe(depth2Key);
});
@@ -1,4 +1,6 @@
// Tests reply payload construction and metadata propagation from agent runs.
import { expectDefined } from "@openclaw/normalization-core";
import { beforeEach, describe, expect, it } from "vitest";
import type { ChannelThreadingAdapter } from "../../channels/plugins/types.public.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../../plugins/runtime.js";
@@ -167,7 +169,10 @@ describe("buildReplyPayloads media filter integration", () => {
originatingChatType: "dm",
});
expect(getReplyPayloadMetadata(replyPayloads[0])?.replyDelivery).toEqual({
expect(
getReplyPayloadMetadata(expectDefined(replyPayloads[0], "replyPayloads[0] test invariant"))
?.replyDelivery,
).toEqual({
chatType: "direct",
replyToMode: "first",
});
@@ -210,9 +215,12 @@ describe("buildReplyPayloads media filter integration", () => {
text: "⚠️ API rate limit reached.",
replyToId: "msg-1",
});
expectFields(getReplyPayloadMetadata(replyPayloads[0]), {
deliverDespiteSourceReplySuppression: true,
});
expectFields(
getReplyPayloadMetadata(expectDefined(replyPayloads[0], "replyPayloads[0] test invariant")),
{
deliverDespiteSourceReplySuppression: true,
},
);
});
it("sanitizes source reply transcript mirror text with final payload text", async () => {
@@ -241,9 +249,10 @@ describe("buildReplyPayloads media filter integration", () => {
expect(replyPayloads).toHaveLength(1);
expect(replyPayloads[0]?.text).toBe("Visible\n\nDone");
expect(getReplyPayloadMetadata(replyPayloads[0])?.sourceReplyTranscriptMirror?.text).toBe(
"Visible\n\nDone",
);
expect(
getReplyPayloadMetadata(expectDefined(replyPayloads[0], "replyPayloads[0] test invariant"))
?.sourceReplyTranscriptMirror?.text,
).toBe("Visible\n\nDone");
});
it("strips media URL from payload when in messagingToolSentMediaUrls", async () => {
@@ -254,7 +263,9 @@ describe("buildReplyPayloads media filter integration", () => {
});
expect(replyPayloads).toHaveLength(1);
expect(replyPayloads[0].mediaUrl).toBeUndefined();
expect(
expectDefined(replyPayloads[0], "replyPayloads[0] test invariant").mediaUrl,
).toBeUndefined();
});
it("preserves media URL when not in messagingToolSentMediaUrls", async () => {
@@ -265,7 +276,9 @@ describe("buildReplyPayloads media filter integration", () => {
});
expect(replyPayloads).toHaveLength(1);
expect(replyPayloads[0].mediaUrl).toBe("file:///tmp/photo.jpg");
expect(expectDefined(replyPayloads[0], "replyPayloads[0] test invariant").mediaUrl).toBe(
"file:///tmp/photo.jpg",
);
});
it("normalizes sent media URLs before deduping normalized reply media", async () => {
@@ -1,4 +1,5 @@
// Tests usage-line formatting for agent runner completion summaries.
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import { getReplyPayloadMetadata, setReplyPayloadMetadata } from "../reply-payload.js";
import { appendUsageLine } from "./agent-runner-usage-line.js";
@@ -21,13 +22,15 @@ describe("appendUsageLine", () => {
const [updated] = appendUsageLine([payload], "Usage: 12 in / 3 out");
expect(updated).toEqual({ text: "message tool reply\nUsage: 12 in / 3 out" });
expect(getReplyPayloadMetadata(updated)).toMatchObject({
deliverDespiteSourceReplySuppression: true,
sourceReplyTranscriptMirror: {
sessionKey: "agent:main:telegram:direct:123",
idempotencyKey: "run-1:internal-source-reply:0",
text: "message tool reply\nUsage: 12 in / 3 out",
expect(getReplyPayloadMetadata(expectDefined(updated, "updated test invariant"))).toMatchObject(
{
deliverDespiteSourceReplySuppression: true,
sourceReplyTranscriptMirror: {
sessionKey: "agent:main:telegram:direct:123",
idempotencyKey: "run-1:internal-source-reply:0",
text: "message tool reply\nUsage: 12 in / 3 out",
},
},
});
);
});
});
@@ -1,4 +1,5 @@
/** Tests bash command aliases and chat shortcut handling. */
import { expectDefined } from "@openclaw/normalization-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
import { handleBashCommand } from "./commands-bash.js";
@@ -71,9 +72,14 @@ describe("handleBashCommand alias routing", () => {
expect(result?.shouldContinue).toBe(false);
expect(handleBashChatCommandMock).toHaveBeenCalledTimes(1);
const [[bashParams]] = handleBashChatCommandMock.mock.calls as unknown as Array<
[{ agentId?: string; sessionKey?: string }]
>;
const [bashParams] = expectDefined(
(
handleBashChatCommandMock.mock.calls as unknown as Array<
[{ agentId?: string; sessionKey?: string }]
>
)[0],
"(handleBashChatCommandMock.mock.calls as unknown as Array<\n [{ agentId?: string; sessionKey?: string }]\n >)[0] test invariant",
);
expect(bashParams.agentId).toBe("target");
expect(bashParams.sessionKey).toBe("agent:target:whatsapp:direct:test-user");
});
@@ -1,5 +1,6 @@
// Tests session export command packaging, filesystem writes, and prompt bundle capture.
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { HandleCommandsParams } from "./commands-types.js";
@@ -175,7 +176,11 @@ function sessionDataFromHtml(html: string): Record<string, unknown> {
if (!match) {
throw new Error("Expected session-data script in exported HTML");
}
return JSON.parse(Buffer.from(match[1].trim(), "base64").toString("utf-8"));
return JSON.parse(
Buffer.from(expectDefined(match[1], "match[1] test invariant").trim(), "base64").toString(
"utf-8",
),
);
}
describe("buildExportSessionReply", () => {
@@ -258,8 +263,14 @@ describe("buildExportSessionReply", () => {
});
expect(reply.text).toContain("✅ Session exported!");
const [[systemPromptBundleParams]] = hoisted.resolveCommandsSystemPromptBundleMock.mock
.calls as unknown as Array<[{ sessionEntry?: { sessionId?: string; updatedAt?: number } }]>;
const [systemPromptBundleParams] = expectDefined(
(
hoisted.resolveCommandsSystemPromptBundleMock.mock.calls as unknown as Array<
[{ sessionEntry?: { sessionId?: string; updatedAt?: number } }]
>
)[0],
"(hoisted.resolveCommandsSystemPromptBundleMock.mock.calls as unknown as Array<\n [{ sessionEntry?: { sessionId?: string; updatedAt?: number } }]\n >)[0] test invariant",
);
expect(systemPromptBundleParams?.sessionEntry?.sessionId).toBe("session-from-store");
expect(systemPromptBundleParams?.sessionEntry?.updatedAt).toBe(2);
});
+9 -2
View File
@@ -1,4 +1,5 @@
// Tests model command output, catalog loading, and provider auth status rendering.
import { expectDefined } from "@openclaw/normalization-core";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { testing as cliBackendsTesting } from "../../agents/cli-backends.js";
import type { ChannelPlugin } from "../../channels/plugins/types.js";
@@ -995,8 +996,14 @@ describe("handleModelsCommand", () => {
const result = await handleModelsCommand(params, true);
expect(result?.reply?.text).toContain("Models (anthropic · 🔑 target-auth) — showing 1-2 of 2");
const [[authLabelParams]] = modelAuthLabelMocks.resolveModelAuthLabel.mock
.calls as unknown as Array<[{ provider?: string; workspaceDir?: string }]>;
const [authLabelParams] = expectDefined(
(
modelAuthLabelMocks.resolveModelAuthLabel.mock.calls as unknown as Array<
[{ provider?: string; workspaceDir?: string }]
>
)[0],
"(modelAuthLabelMocks.resolveModelAuthLabel.mock.calls as unknown as Array<\n [{ provider?: string; workspaceDir?: string }]\n >)[0] test invariant",
);
expect(authLabelParams.provider).toBe("anthropic");
expect(authLabelParams.workspaceDir).toBe("/tmp");
});

Some files were not shown because too many files have changed in this diff Show More