docs: document session guard tests

This commit is contained in:
Peter Steinberger
2026-06-04 15:46:45 -04:00
parent 58f00707ed
commit dca200ade5
6 changed files with 17 additions and 3 deletions

View File

@@ -1,3 +1,4 @@
// Verifies OpenAI tool schema normalization remains stable across runtime paths.
import type { StreamFn } from "openclaw/plugin-sdk/agent-core";
import {
createNativeOpenAIResponsesModel,
@@ -56,6 +57,7 @@ describe("OpenAI transport schema normalization runtime contract", () => {
});
it("passes prepared executable schemas through compaction-triggered Responses requests", () => {
// Server-side compaction must not strip provider-prepared strict tool schemas.
const hooks = buildProviderToolCompatFamilyHooks("openai");
const tools = hooks.normalizeToolSchemas({
provider: "openai",

View File

@@ -1,3 +1,4 @@
// Verifies quota suspension persists lane state and auto-resumes safely.
import { afterEach, describe, expect, it, vi } from "vitest";
import { DEFAULT_CRON_MAX_CONCURRENT_RUNS } from "../config/cron-limits.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
@@ -24,6 +25,7 @@ vi.mock("./command/session.js", () => ({
}));
async function suspendLane(ttlMs: number, cfg: OpenClawConfig, laneId: CommandLane) {
// All cases exercise the public suspendSession path with fixed failure metadata.
const { suspendSession } = await import("./session-suspension.js");
await suspendSession({
cfg,
@@ -104,6 +106,7 @@ describe("session suspension", () => {
});
it("clamps oversized suspension TTLs for timers and persisted resume time", async () => {
// Persisted expectedResumeBy must match the clamped timer, not MAX_SAFE_INTEGER.
vi.useFakeTimers();
vi.setSystemTime(1_000);
const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout");

View File

@@ -1,3 +1,4 @@
// Verifies session tool-result guard inserts, truncates, and repairs tool results.
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
import { describe, expect, it } from "vitest";
@@ -32,6 +33,7 @@ function appendAssistantToolCall(
sm: SessionManager,
params: { id: string; name: string; withArguments?: boolean },
) {
// Builds pending tool calls with optional missing arguments for repair cases.
const toolCall: {
type: "toolCall";
id: string;
@@ -61,6 +63,7 @@ function getPersistedMessages(sm: SessionManager): AgentMessage[] {
}
function expectPersistedRoles(sm: SessionManager, expectedRoles: AgentMessage["role"][]) {
// Role-order assertions prove where synthetic toolResult messages were inserted.
const messages = getPersistedMessages(sm);
expect(messages.map((message) => message.role)).toEqual(expectedRoles);
return messages;
@@ -387,9 +390,7 @@ describe("installSessionToolResultGuard", () => {
);
const messages = expectPersistedRoles(sm, ["assistant", "assistant", "toolResult"]);
expect((messages[2] as { toolCallId?: string; isError?: boolean }).toolCallId).toBe(
"call_1",
);
expect((messages[2] as { toolCallId?: string; isError?: boolean }).toolCallId).toBe("call_1");
expect((messages[2] as { isError?: boolean }).isError).toBe(false);
expect(JSON.stringify(messages)).not.toContain("missing tool result");
expect(guard.getPendingIds()).toStrictEqual(["call_2"]);

View File

@@ -1,3 +1,4 @@
// Verifies persisted tool results are redacted/capped and can be transformed by hooks.
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
@@ -17,6 +18,7 @@ const originalConfigPath = process.env.OPENCLAW_CONFIG_PATH;
let tempDirs: string[] = [];
function writeTempPlugin(params: { dir: string; id: string; body: string }): string {
// Temp plugin manifests allow testing real hook loading without bundled plugins.
const pluginDir = path.join(params.dir, params.id);
fs.mkdirSync(pluginDir, { recursive: true });
const file = path.join(pluginDir, `${params.id}.mjs`);
@@ -99,6 +101,7 @@ function expectPersistedToolResultTextCapped(sm: ReturnType<typeof SessionManage
}
function expectPersistedToolResultDetailsCapped(sm: ReturnType<typeof SessionManager.inMemory>) {
// Large details are summarized before persistence to keep transcript files bounded.
const toolResult = requirePersistedToolResult(sm);
const details = toolResult.details as Record<string, unknown>;
expect(details.persistedDetailsTruncated).toBe(true);

View File

@@ -1,3 +1,4 @@
// Verifies guarded session managers emit transcript update events with stable sequence ids.
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";
@@ -10,6 +11,7 @@ import { guardSessionManager } from "./session-tool-result-guard-wrapper.js";
const listeners: Array<() => void> = [];
afterEach(() => {
// Remove all transcript listeners between tests to avoid duplicate broadcasts.
while (listeners.length > 0) {
listeners.pop()?.();
}
@@ -124,6 +126,7 @@ describe("guardSessionManager transcript updates", () => {
});
it("caches real tool result sequence before final assistant messages", () => {
// Tool results are persisted but not broadcast, so later visible messages must skip their seq.
const updates: SessionTranscriptUpdate[] = [];
listeners.push(onSessionTranscriptUpdate((update) => updates.push(update)));

View File

@@ -1,9 +1,11 @@
// Verifies transcript repair preserves sessions_spawn attachments and ACP routing fields.
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { describe, it, expect } from "vitest";
import { sanitizeToolCallInputs } from "./session-transcript-repair.js";
import { castAgentMessage, castAgentMessages } from "./test-helpers/agent-message-fixtures.js";
function mkSessionsSpawnToolCall(content: string): AgentMessage {
// sessions_spawn attachments are transcript-owned payloads, not redaction targets.
return castAgentMessage({
role: "assistant",
content: [