Files
openclaw/scripts/lib/code-mode-matrix-gateway.ts
T
Peter Steinberger dfb2cee6d8 chore: compare Code Mode against disabled on complex workloads (#155613)
* test: add paired Code Mode workload evaluation

* test: preserve initial evidence assertion during build rechecks

* test: align Code Mode evidence checks with paired admission

* ci: refresh merge proof after upstream pairing repair

Refresh the merge ref after main fixed the observed SSH-pairing fixture race in f87f23c483. No source changes.
2026-09-22 04:24:26 -07:00

1999 lines
71 KiB
TypeScript

import { createHash, randomUUID } from "node:crypto";
import { constants as fsConstants } from "node:fs";
import fs from "node:fs/promises";
import net from "node:net";
import os from "node:os";
import path from "node:path";
import { setTimeout as delay } from "node:timers/promises";
import { isDeepStrictEqual } from "node:util";
import { asFiniteNumber } from "@openclaw/normalization-core/number-coercion";
import { isRecord as record } from "@openclaw/normalization-core/record-coerce";
import { parse } from "acorn";
import type { CodeModeExecutorId } from "../../src/agents/code-mode-executor-types.js";
import { resolveCodeModeConfig } from "../../src/agents/code-mode-runtime.js";
import type { OpenClawConfig } from "../../src/config/types.openclaw.js";
import { mergeDeep } from "../../src/infra/deep-merge.js";
import { readResponseWithLimit } from "../../src/infra/http-response-body.js";
import type { ManagedRun } from "../../src/process/supervisor/types.js";
import type { CodeModeMatrixCellResult, RunCellParams } from "../code-mode-model-matrix.ts";
import {
createGatewayMatrixFixture,
createGatewayMatrixPluginManifest,
createGatewayMatrixPluginSource,
type GatewayMatrixTask as GatewayMatrixContractTask,
type GatewayMatrixFixture,
} from "./code-mode-matrix-gateway-fixtures.ts";
import {
createMatrixPerformanceFixture,
isMatrixPerformanceTask,
type MatrixPerformanceTask,
} from "./code-mode-matrix-performance-fixtures.ts";
import type { MatrixPerformanceFixture } from "./code-mode-matrix-performance-types.ts";
import {
classifyCodeModeMatrixProviderFailure,
matrixModelConfig,
matrixProviderEnv,
} from "./code-mode-matrix-provider.ts";
import {
readMatrixSessionLedger,
captureMatrixLedgerBoundary,
selectMatrixLedgerRows,
collectMatrixUsage,
type MatrixLedgerBoundary,
type MatrixSessionLedger,
type MatrixUsageAccounting,
} from "./code-mode-matrix-usage.ts";
import { redactForDevToolLog } from "./dev-tooling-safety.ts";
export type GatewayMatrixTask = GatewayMatrixContractTask | MatrixPerformanceTask;
type RecordValue = Record<string, unknown>;
type ToolCall = {
id: string;
name: string;
args: RecordValue;
eventIndex: number;
sessionKey?: string;
};
type ToolOutcome = {
id: string;
name: string;
details: RecordValue;
content: unknown;
isError: boolean;
eventIndex: number;
sessionKey?: string;
};
type ToolActivity = {
name: string;
input: RecordValue;
result: RecordValue;
content?: unknown;
isError: boolean;
parentId?: string;
sessionKey?: string;
eventIndex?: number;
};
const SHIPPING_CODE_MODE = resolveCodeModeConfig();
const EXEC_TIMEOUT_MS = SHIPPING_CODE_MODE.timeoutMs;
const MAX_OUTPUT_BYTES = SHIPPING_CODE_MODE.maxOutputBytes;
const MAX_MODEL_OUTPUT_TOKENS = 4_000;
const PERFORMANCE_GRADING_REVISION = "performance-outcome-v4";
export type GatewayMatrixActivationDiagnostic = {
runId: string;
active: boolean;
toolsEnabled: boolean;
toolsDisabled: boolean;
rawRun: boolean;
fallbackActive: boolean;
allowlist?: string;
};
export function parseGatewayMatrixActivationDiagnostic(
line: string,
): GatewayMatrixActivationDiagnostic | undefined {
const marker = "code-mode diagnostic ";
const start = line.indexOf(marker);
if (start < 0) {
return undefined;
}
try {
const value: unknown = JSON.parse(line.slice(start + marker.length, line.lastIndexOf("}") + 1));
if (
!record(value) ||
value.boundary !== "activation" ||
typeof value.runId !== "string" ||
typeof value.active !== "boolean" ||
typeof value.toolsEnabled !== "boolean" ||
typeof value.toolsDisabled !== "boolean" ||
typeof value.rawRun !== "boolean" ||
typeof value.fallbackActive !== "boolean"
) {
return undefined;
}
return {
runId: value.runId,
active: value.active,
toolsEnabled: value.toolsEnabled,
toolsDisabled: value.toolsDisabled,
rawRun: value.rawRun,
fallbackActive: value.fallbackActive,
...(typeof value.allowlist === "string" ? { allowlist: value.allowlist } : {}),
};
} catch {
return undefined;
}
}
export function evaluateGatewayMatrixActivation(params: {
diagnostics: readonly GatewayMatrixActivationDiagnostic[];
rootRunId?: string;
childRunIds: readonly string[];
expectedEnabled: boolean;
}) {
const requiredActivationRuns = [
...new Set([...(params.rootRunId ? [params.rootRunId] : []), ...params.childRunIds]),
];
const observedActivation = params.diagnostics.filter((entry) =>
requiredActivationRuns.includes(entry.runId),
);
// Isolated no-tool finalization is outside the surface being compared.
const qualifyingActivation = observedActivation.filter(
(entry) => entry.toolsEnabled && !entry.toolsDisabled && !entry.rawRun,
);
const activationComplete =
Boolean(params.rootRunId) &&
requiredActivationRuns.every((runId) =>
qualifyingActivation.some((entry) => entry.runId === runId),
);
return {
requiredActivationRuns,
observedActivation,
qualifyingActivation,
activationComplete,
actualCodeMode: activationComplete && qualifyingActivation.every((entry) => entry.active),
engagement:
activationComplete &&
qualifyingActivation.every((entry) => entry.active === params.expectedEnabled),
};
}
type DeliveredFileEvidence = {
source: string;
status: "captured" | "unavailable";
path?: string;
bytes?: number;
sha256?: string;
reason?: string;
};
export type GatewayMatrixTrace = {
calls: ToolCall[];
outcomes: ToolOutcome[];
activities: ToolActivity[];
assistantTurns: number;
models: string[];
usage?: {
input: number;
output: number;
total?: number;
cacheRead?: number;
cacheWrite?: number;
};
costUsd?: number;
};
export type GatewayMatrixWorkload = {
promptSha256: string;
fixtureSha256: string;
performanceGradingRevision?: string;
settings: {
executor: CodeModeExecutorId;
thinking: string;
timeoutSeconds: number;
execTimeoutMs: number;
maxOutputBytes: number;
maxModelOutputTokens: number | null;
runtime: "openclaw";
fast: false;
allowedTools: readonly string[];
};
};
export type GatewayMatrixEvidence = GatewayMatrixWorkload & {
behavior: Record<string, boolean>;
taskElapsedMs?: number;
taskResponseAt?: number;
startupMs: number;
traceAvailable: boolean;
upstreamCalls?: number;
outerCalls?: number;
outerOutputBytes?: number;
taskAssistantTurns?: number;
deliveredFiles?: DeliveredFileEvidence[];
interview: {
skipped?: boolean;
accounting?: MatrixUsageAccounting;
elapsedMs?: number;
traceAvailable: boolean;
answer: unknown;
rationaleReview: "required";
checks: Record<string, boolean>;
trace?: GatewayMatrixTrace;
};
artifacts: {
taskTrace: string;
interviewTrace: string;
receipts: string;
taskReceipts: string;
interviewReceipts: string;
log: string;
deliveredFiles?: string;
};
};
function matrixFixture(
task: GatewayMatrixTask,
repetition: number,
): GatewayMatrixFixture & { performance?: MatrixPerformanceFixture } {
if (!isMatrixPerformanceTask(task)) {
return createGatewayMatrixFixture(task, repetition);
}
const performance = createMatrixPerformanceFixture(task, repetition);
return {
prompt: performance.prompt,
expected: { rubricVersion: performance.rubricVersion },
pluginSource: performance.pluginSource ?? createGatewayMatrixPluginSource(""),
requiredTools: performance.requiredTools,
workspaceFiles: performance.workspaceFiles,
interviewPrompt: "",
performance,
};
}
type BehaviorChecks = Record<string, boolean> & { answer: boolean; actualCodeMode: boolean };
/** Workload identity exists before launch, including when a cell cannot start. */
export function createGatewayMatrixWorkload(
task: GatewayMatrixTask,
repetition: number,
thinking: string,
timeoutSeconds: number,
executor: CodeModeExecutorId = "node",
): GatewayMatrixWorkload {
const fixture = matrixFixture(task, repetition);
return {
...(fixture.performance ? { performanceGradingRevision: PERFORMANCE_GRADING_REVISION } : {}),
promptSha256: createHash("sha256")
.update(fixture.prompt)
.update("\0")
.update(fixture.interviewPrompt)
.digest("hex"),
fixtureSha256: createHash("sha256")
.update(fixture.pluginSource)
.update(JSON.stringify(fixture.expected))
.update(JSON.stringify(createGatewayMatrixPluginManifest(fixture.requiredTools)))
.update(fixture.processHelperSource ?? "")
.update(JSON.stringify(fixture.workspaceFiles ?? {}))
.update(JSON.stringify(fixture.performance?.configPatch ?? {}))
.update(fixture.performance?.rubricVersion ?? "contract")
.update(fixture.performance ? PERFORMANCE_GRADING_REVISION : "")
.update(fixture.performance ? JSON.stringify(fixture.performance.deliveredFiles) : "")
.digest("hex"),
settings: {
executor,
thinking,
timeoutSeconds,
execTimeoutMs: EXEC_TIMEOUT_MS,
maxOutputBytes: MAX_OUTPUT_BYTES,
maxModelOutputTokens: fixture.performance ? null : MAX_MODEL_OUTPUT_TOKENS,
runtime: "openclaw",
fast: false,
allowedTools: gatewayAllowedTools(
task,
fixture.requiredTools,
fixture.performance?.allowedTools,
),
},
};
}
function gatewayAllowedTools(
task: GatewayMatrixTask,
fixtureTools: readonly string[],
performanceTools?: readonly string[],
): readonly string[] {
if (performanceTools) {
return performanceTools;
}
if (task === "automation-contracts") {
return ["automations"];
}
if (task === "process-contracts") {
return ["exec", "process"];
}
if (task === "javascript-contracts") {
return ["read", "write"];
}
if (task === "gateway-config-read") {
return ["gateway"];
}
return fixtureTools;
}
function records(value: unknown): RecordValue[] {
if (Array.isArray(value)) {
return value.flatMap(records);
}
return record(value) ? [value, ...Object.values(value).flatMap(records)] : [];
}
function outputDetails(message: RecordValue): RecordValue {
if (record(message.details) && message.details.persistedDetailsTruncated !== true) {
return message.details;
}
for (const item of Array.isArray(message.content) ? message.content : []) {
if (!record(item) || typeof item.text !== "string") {
continue;
}
try {
const decoded: unknown = JSON.parse(item.text);
if (record(decoded)) {
return decoded;
}
} catch {
/* A truncated display is evidence of truncation, not a complete result. */
}
}
return record(message.details) ? message.details : {};
}
/** Only actual assistant calls and persisted terminal activity count as execution. */
export function collectGatewayMatrixTrace(events: readonly unknown[]): GatewayMatrixTrace {
const calls: ToolCall[] = [];
const outcomes: ToolOutcome[] = [];
const activities: ToolActivity[] = [];
const models = new Set<string>();
let assistantTurns = 0;
let usageSamples = 0;
let costSamples = 0;
let totalSamples = 0;
let cacheReadSamples = 0;
let cacheWriteSamples = 0;
let input = 0;
let output = 0;
let total = 0;
let costUsd = 0;
let cacheRead = 0;
let cacheWrite = 0;
for (const [eventIndex, event] of events.entries()) {
if (!record(event)) {
continue;
}
const message = record(event.message) ? event.message : event;
const sessionKey =
typeof event.matrixSessionKey === "string" ? event.matrixSessionKey : undefined;
if (message.role === "assistant") {
assistantTurns += 1;
if (typeof message.provider === "string" && typeof message.model === "string") {
models.add(`${message.provider}/${message.model}`);
}
const usage = record(message.usage) ? message.usage : {};
const inputTokens = asFiniteNumber(usage.input);
const outputTokens = asFiniteNumber(usage.output);
if (inputTokens !== undefined && outputTokens !== undefined) {
usageSamples += 1;
input += inputTokens;
output += outputTokens;
const totalTokens = asFiniteNumber(usage.totalTokens);
if (totalTokens !== undefined) {
totalSamples += 1;
total += totalTokens;
}
const readTokens = asFiniteNumber(usage.cacheRead);
if (readTokens !== undefined) {
cacheReadSamples += 1;
cacheRead += readTokens;
}
const writeTokens = asFiniteNumber(usage.cacheWrite);
if (writeTokens !== undefined) {
cacheWriteSamples += 1;
cacheWrite += writeTokens;
}
const cost = record(usage.cost) ? asFiniteNumber(usage.cost.total) : undefined;
if (cost !== undefined) {
costSamples += 1;
costUsd += cost;
}
}
for (const block of Array.isArray(message.content) ? message.content : []) {
if (
record(block) &&
block.type === "toolCall" &&
typeof block.id === "string" &&
typeof block.name === "string"
) {
calls.push({
id: block.id,
name: block.name,
args: record(block.arguments) ? block.arguments : {},
eventIndex,
...(sessionKey ? { sessionKey } : {}),
});
}
}
} else if (message.role === "toolResult" && typeof message.toolCallId === "string") {
outcomes.push({
id: message.toolCallId,
name: typeof message.toolName === "string" ? message.toolName : "",
details: outputDetails(message),
content: message.content,
isError: message.isError === true,
eventIndex,
...(sessionKey ? { sessionKey } : {}),
});
} else if (message.customType === "openclaw.nested-tool.v1" && record(message.details)) {
const data = message.details;
if (typeof data.toolName !== "string") {
continue;
}
const result = record(data.result) && record(data.result.details) ? data.result.details : {};
activities.push({
name: data.toolName,
input: record(data.input) ? data.input : {},
result,
content: record(data.result) ? data.result.content : undefined,
isError: data.isError === true,
...(typeof data.parentToolCallId === "string" ? { parentId: data.parentToolCallId } : {}),
...(sessionKey ? { sessionKey } : {}),
eventIndex,
});
}
}
// Deferred Tool Search and Code Mode already persist the underlying activity.
// Only ordinary direct calls need projection from their matching tool result.
for (const outcome of outcomes) {
const call = calls.find(
(item) => item.id === outcome.id && item.sessionKey === outcome.sessionKey,
);
if (
!call ||
(call.name === "exec" && typeof call.args.code === "string") ||
["tool_search", "tool_describe", "tool_call", "wait"].includes(call.name) ||
activities.some((item) => item.parentId === call.id && item.sessionKey === call.sessionKey)
) {
continue;
}
activities.push({
name: call.name,
input: call.args,
result: outcome.details,
content: outcome.content,
isError: outcome.isError,
...(call.sessionKey ? { sessionKey: call.sessionKey } : {}),
eventIndex: outcome.eventIndex,
});
}
activities.sort((left, right) => (left.eventIndex ?? 0) - (right.eventIndex ?? 0));
return {
calls,
outcomes,
activities,
assistantTurns,
models: [...models],
...(usageSamples === assistantTurns && assistantTurns > 0
? {
usage: {
input,
output,
...(totalSamples === assistantTurns ? { total } : {}),
...(cacheReadSamples === assistantTurns ? { cacheRead } : {}),
...(cacheWriteSamples === assistantTurns ? { cacheWrite } : {}),
},
}
: {}),
...(costSamples === assistantTurns && assistantTurns > 0 ? { costUsd } : {}),
};
}
function jsonAnswer(text: string): unknown {
try {
return JSON.parse(text.trim());
} catch {
return undefined;
}
}
function callOutcomes(trace: GatewayMatrixTrace, call: ToolCall): ToolOutcome[] {
let outcome = trace.outcomes.findLast((item) => item.id === call.id);
const outcomes = outcome ? [outcome] : [];
let cursor = trace.calls.indexOf(call);
while (outcome && !outcome.isError && outcome.details.status === "waiting") {
const runId = outcome.details.runId;
if (typeof runId !== "string") {
break;
}
const next = trace.calls.findIndex(
(item, index) => index > cursor && item.name === "wait" && item.args.runId === runId,
);
const wait = trace.calls[next];
if (!wait) {
break;
}
cursor = next;
outcome = trace.outcomes.findLast((item) => item.id === wait.id);
if (outcome) {
outcomes.push(outcome);
}
}
return outcomes;
}
function settledCallOutcome(outcomes: readonly ToolOutcome[]): ToolOutcome | undefined {
const outcome = outcomes.at(-1);
return outcome && ["completed", "failed"].includes(String(outcome.details.status))
? outcome
: undefined;
}
function completedCallOutcome(outcomes: readonly ToolOutcome[]): ToolOutcome | undefined {
const outcome = settledCallOutcome(outcomes);
return outcome && !outcome.isError && outcome.details.status === "completed"
? outcome
: undefined;
}
function source(call: ToolCall): string {
return typeof call.args.code === "string"
? call.args.code
: typeof call.args.command === "string"
? call.args.command
: "";
}
function isDirectApiRead(call: ToolCall, method: "list" | "read", argument: string): boolean {
try {
const program = parse(source(call), {
ecmaVersion: "latest",
allowAwaitOutsideFunction: true,
allowReturnOutsideFunction: true,
});
const statement = program.body[0];
if (
program.body.length !== 1 ||
statement?.type !== "ReturnStatement" ||
statement.argument?.type !== "AwaitExpression"
) {
return false;
}
const invocation = statement.argument.argument;
return (
invocation.type === "CallExpression" &&
!invocation.optional &&
invocation.callee.type === "MemberExpression" &&
!invocation.callee.computed &&
!invocation.callee.optional &&
invocation.callee.object.type === "Identifier" &&
invocation.callee.object.name === "API" &&
invocation.callee.property.type === "Identifier" &&
invocation.callee.property.name === method &&
invocation.arguments.length === 1 &&
invocation.arguments[0]?.type === "Literal" &&
invocation.arguments[0].value === argument
);
} catch {
return false;
}
}
function normalizeCaughtError(message: string): string {
// Host activity retains the catalog ID; the guest bridge exposes the callable name.
return message
.replace(/\r\n/gu, "\n")
.trim()
.replace(/^(?:Error|ToolInputError):\s*/u, "")
.replace(
/^Invalid arguments for tool "openclaw:core:read":/u,
'Invalid arguments for tool "read":',
);
}
function matchesTextRead(activity: ToolActivity | undefined, expected: unknown): boolean {
return (
typeof expected === "string" &&
activity?.result.kind === "text" &&
activity.result.content === expected &&
Array.isArray(activity.content) &&
activity.content.length === 1 &&
record(activity.content[0]) &&
activity.content[0].type === "text" &&
activity.content[0].text === expected
);
}
function observedReferences(
trace: GatewayMatrixTrace,
): { id: string; previewComplete: boolean | null }[] {
return trace.outcomes.flatMap((outcome) =>
records(outcome.details).flatMap((item) =>
typeof item.id === "string" &&
typeof item.bytes === "number" &&
typeof item.preview === "string"
? [
{
id: item.id,
previewComplete:
typeof item.previewTruncated === "boolean" ? !item.previewTruncated : null,
},
]
: [],
),
);
}
function referenceIds(trace: GatewayMatrixTrace): string[] {
return [...new Set(observedReferences(trace).map((reference) => reference.id))];
}
export function evaluateGatewayMatrixTask(params: {
task: GatewayMatrixContractTask;
expected: RecordValue;
final: string;
trace: GatewayMatrixTrace;
receipts: readonly unknown[];
probeCode?: string;
}): BehaviorChecks {
const { task, trace, expected } = params;
const receiptRows = params.receipts.filter(record);
const receiptCalls = receiptRows.filter((row) => row.kind === "call");
const codeModeInvocation = (item: ToolActivity) =>
trace.calls.some((call) => call.id === item.parentId && call.name === "exec");
const activity = trace.activities.filter((item) => !item.isError);
const checks: BehaviorChecks = {
answer: isDeepStrictEqual(jsonAnswer(params.final), expected),
actualCodeMode:
trace.calls.some((call) => call.name === "exec") &&
trace.outcomes.some((outcome) =>
["completed", "waiting", "failed"].includes(String(outcome.details.status)),
),
};
if (task === "return-value-effects" || task === "result-save-invalid-json") {
const execs = trace.calls.filter((call) => call.name === "exec");
const probe = execs.length === 1 ? execs[0] : undefined;
const outcomes = probe ? callOutcomes(trace, probe) : [];
const outcome = completedCallOutcome(outcomes);
const output = outcomes.flatMap((item) =>
Array.isArray(item.details.output) ? item.details.output.filter(record) : [],
);
checks.exactProbeSource =
probe !== undefined &&
typeof params.probeCode === "string" &&
source(probe).trim() === params.probeCode.trim();
checks.observedProbeValue =
outcome !== undefined && isDeepStrictEqual(outcome.details.value, expected);
const toolName =
task === "return-value-effects" ? "matrix_return_effect" : "matrix_serialization_seed";
checks.singleProbeInvocation =
trace.activities.length === 1 &&
trace.activities.every(
(item) =>
!item.isError &&
item.parentId === probe?.id &&
item.name === toolName &&
item.result.nonce === expected.nonce,
);
if (task === "return-value-effects") {
checks.singleOutput =
output.length === 1 && output[0]?.type === "text" && output[0].text === expected.marker;
checks.exactlyOneEffect = isDeepStrictEqual(
receiptRows.map(({ kind, tool, nonce }) => ({ kind, tool, nonce })),
["call", "effect"].map((kind) => ({ kind, tool: toolName, nonce: expected.nonce })),
);
} else {
const rejected = output.map((item) =>
item.type === "json" && record(item.value) ? item.value : {},
);
checks.rejectionsObserved =
isDeepStrictEqual(
rejected.map((item) => item.kind),
expected.rejected,
) &&
rejected.every((item) => typeof item.error === "string" && item.error.trim().length > 0);
checks.singleSeedRead =
receiptRows.length === 1 &&
receiptRows[0]?.kind === "call" &&
receiptRows[0].tool === toolName;
}
} else if (task === "gateway-config-read") {
const read = trace.activities.length === 1 ? trace.activities[0] : undefined;
const call = trace.calls.find((item) => item.id === read?.parentId && item.name === "exec");
const outcome = call ? completedCallOutcome(callOutcomes(trace, call)) : undefined;
const result = record(read?.result.result) ? read.result.result : undefined;
const config = record(result?.config) ? result.config : undefined;
checks.singleConfigRead =
read !== undefined &&
!read.isError &&
read.name === "gateway" &&
read.input.action === "config.get" &&
read.input.path === "tools.codeMode";
checks.configSettings =
read?.result.ok === true &&
result?.path === "tools.codeMode" &&
config?.enabled === true &&
(config.timeoutMs === undefined || config.timeoutMs === EXEC_TIMEOUT_MS) &&
(config.maxOutputBytes === undefined || config.maxOutputBytes === MAX_OUTPUT_BYTES);
checks.rawConfigReachedGuest =
outcome !== undefined && isDeepStrictEqual(outcome.details.value, read?.result);
checks.noFixtureEffects = receiptRows.length === 0;
} else if (task === "invoices-auto-retention") {
const firstFetch = trace.activities.find((item) => item.name === "matrix_invoice_export");
const fetchCell = trace.calls.find((call) => call.id === firstFetch?.parentId);
const fetched = fetchCell ? completedCallOutcome(callOutcomes(trace, fetchCell)) : undefined;
const automatic =
fetched &&
record(fetched.details.value) &&
fetched.details.value.truncated === true &&
record(fetched.details.value.reference)
? fetched
: undefined;
const refs = automatic ? referenceIds({ ...trace, outcomes: [automatic] }) : [];
const load = trace.calls.find(
(call) =>
refs.some((id) => source(call).includes(id)) && source(call).includes("results.load"),
);
const outer = JSON.stringify(trace.outcomes.map((outcome) => outcome.content));
checks.automaticReference =
refs.length > 0 && fetchCell !== undefined && !source(fetchCell).includes("results.save");
checks.laterCellReusesReference =
load !== undefined &&
fetchCell !== undefined &&
trace.calls.indexOf(load) > trace.calls.indexOf(fetchCell) &&
completedCallOutcome(callOutcomes(trace, load)) !== undefined;
checks.singleFetch =
receiptCalls.filter((row) => row.tool === "matrix_invoice_export").length === 1;
checks.boundedModelData = new Set(outer.match(/INV-\d+-\d+/gu) ?? []).size <= 8;
checks.noPastedRecords = trace.calls
.filter((call) => call.id !== fetchCell?.id)
.every((call) => !/INV-\d+-\d+/u.test(source(call)));
} else if (task === "inventory-join") {
checks.completeSources = ["matrix_inventory_export", "matrix_supplier_directory"].every(
(name) => receiptCalls.some((row) => row.tool === name),
);
} else if (task === "automation-contracts") {
const automations = activity.filter((item) => item.name === "automations");
const completeInventory = (item: ToolActivity) =>
item.input.action === "list" &&
item.input.includeDisabled === true &&
item.result.hasMore === false &&
item.result.nextOffset === null &&
Array.isArray(item.result.jobs) &&
item.result.jobs.length === item.result.total;
const mutation = (item: ToolActivity) =>
["add", "update", "remove"].includes(String(item.input.action));
const firstMutation = automations.findIndex(mutation);
const lastMutation = automations.findLastIndex(mutation);
const initialInventory = automations.find(
(item, index) => index < firstMutation && completeInventory(item),
);
const terminalInventory = automations.findLast(
(item, index) => index > lastMutation && completeInventory(item),
);
const created = automations.filter((item) => item.input.action === "add");
const initialJobs = Array.isArray(initialInventory?.result.jobs)
? initialInventory.result.jobs.filter(record)
: undefined;
const finalJobs = Array.isArray(terminalInventory?.result.jobs)
? terminalInventory.result.jobs.filter(record)
: [];
const jobId = (item: ToolActivity) =>
record(item.result.job) ? item.result.job.id : item.result.id;
checks.actionContracts =
["add", "get", "list", "update", "runs", "remove"].every((action) =>
automations.some((item) => item.input.action === action),
) &&
automations.some((item, index) => index < firstMutation && item.input.action === "status");
checks.codeModeComposition = automations.length > 0 && automations.every(codeModeInvocation);
checks.createdDisabled =
created.length > 0 &&
created.every(
(item) =>
record(item.input.job) &&
item.input.job.enabled === false &&
(record(item.result.job) ? item.result.job.enabled : item.result.enabled) === false,
);
checks.remainedDisabled = trace.activities
.filter((item) => item.name === "automations")
.every((item) => {
if (["run", "wake"].includes(String(item.input.action))) {
return false;
}
if (item.input.action !== "update") {
return true;
}
if (
item.input.enabled === true ||
(record(item.input.job) && item.input.job.enabled === true) ||
(record(item.input.patch) && item.input.patch.enabled === true)
) {
return false;
}
const job = record(item.result.job) ? item.result.job : item.result;
return item.isError || job.enabled === false;
});
const createdIds = new Set(created.map(jobId));
checks.onlyOwnedMutations = trace.activities
.filter(
(item) =>
item.name === "automations" && ["update", "remove"].includes(String(item.input.action)),
)
.every((item) => createdIds.has(item.input.jobId ?? item.input.id));
checks.createdFacts =
created.length === 1 &&
trace.activities.filter((item) => item.name === "automations" && item.input.action === "add")
.length === 1 &&
created.every((item) => {
const job = record(item.result.job) ? item.result.job : item.result;
const scheduledAt =
record(job.schedule) && job.schedule.kind === "at" && typeof job.schedule.at === "string"
? Date.parse(job.schedule.at)
: Number.NaN;
const createdAt = asFiniteNumber(job.createdAtMs);
return (
job.name === expected.jobName &&
job.sessionTarget === "main" &&
record(job.payload) &&
job.payload.kind === "systemEvent" &&
job.payload.text === expected.payloadText &&
createdAt !== undefined &&
Number.isFinite(scheduledAt) &&
Math.abs(scheduledAt - createdAt - 86_400_000) <= 300_000
);
});
const createdJob = created[0];
const createdId = createdJob && jobId(createdJob);
const createdIndex = createdJob ? automations.indexOf(createdJob) : -1;
const lifecycleStep = (action: string, after: number, name?: unknown) =>
automations.findIndex(
(item, index) =>
index > after &&
item.input.action === action &&
(item.input.jobId ?? item.input.id) === createdId &&
(name === undefined ||
(jobId(item) === createdId &&
(record(item.result.job) ? item.result.job.name : item.result.name) === name)),
);
const initialRead = lifecycleStep("get", createdIndex, expected.jobName);
const update = lifecycleStep("update", initialRead, expected.updatedName);
const updatedRead = lifecycleStep("get", update, expected.updatedName);
const history = lifecycleStep("runs", createdIndex);
const remove = lifecycleStep("remove", Math.max(updatedRead, history));
checks.createdLifecycleObserved =
typeof createdId === "string" &&
[initialRead, update, updatedRead, history, remove].every((index) => index >= 0);
checks.terminalInventoryComplete = terminalInventory !== undefined;
checks.createdRemoved =
terminalInventory !== undefined &&
created.every(
(item) =>
typeof jobId(item) === "string" && !finalJobs.some((job) => job.id === jobId(item)),
);
checks.baselinePreserved =
initialJobs !== undefined &&
terminalInventory !== undefined &&
isDeepStrictEqual(
initialJobs.toSorted((a, b) => String(a.id).localeCompare(String(b.id))),
finalJobs.toSorted((a, b) => String(a.id).localeCompare(String(b.id))),
);
} else if (task === "process-contracts") {
const processes = activity.filter((item) => item.name === "process");
const launches = trace.activities.filter((item) => item.name === "exec");
const helperSessionIds = new Set(
activity.flatMap((item) =>
item.name === "exec" &&
typeof item.input.command === "string" &&
item.input.command.includes("process-probe.mjs") &&
typeof item.result.sessionId === "string"
? [item.result.sessionId]
: [],
),
);
const helperOperations = processes.filter((item) =>
helperSessionIds.has(String(item.input.sessionId)),
);
checks.realProcessControl =
processes.some((item) => item.input.action === "list") &&
processes.some((item) => item.input.action === "poll" || item.input.action === "log");
checks.singleHelperLaunch =
launches.length === 1 &&
launches.every(
(item) =>
!item.isError &&
typeof item.input.command === "string" &&
item.input.command.trim() === "node ./process-probe.mjs" &&
item.input.background === true &&
typeof item.result.sessionId === "string",
);
checks.onlyHelperReads = trace.activities
.filter((item) => item.name === "process")
.every(
(item) =>
item.input.action === "list" ||
(["log", "poll"].includes(String(item.input.action)) &&
helperSessionIds.has(String(item.input.sessionId))),
);
checks.codeModeComposition =
processes.length > 0 && [...launches, ...processes].every(codeModeInvocation);
checks.observedCompletion = helperOperations.some(
(item) => item.result.status === "completed" && item.result.exitCode === 0,
);
checks.observedMarker =
typeof expected.marker === "string" &&
helperOperations.some((item) =>
JSON.stringify(item.result).includes(String(expected.marker)),
);
} else if (task === "partial-failure") {
const mutations = receiptRows.filter((row) => row.kind === "effect");
const failedCall = trace.activities.find(
(item) => item.name === "matrix_settle" && item.isError,
);
const settleAt = receiptCalls.findIndex((row) => row.tool === "matrix_settle");
const inspectAt = receiptCalls.findIndex(
(row, index) => index > settleAt && row.tool === "matrix_settlement_inspect",
);
checks.exactlyOneEffect =
mutations.length === 1 &&
receiptCalls.filter((row) => row.tool === "matrix_settle").length === 1 &&
mutations[0]?.operationId === expected.operationId &&
mutations[0]?.totalCents === expected.totalCents;
checks.inspectedAfterFailure =
failedCall !== undefined && inspectAt > settleAt && settleAt >= 0;
checks.observedPersistedState = activity.some(
(item) =>
item.name === "matrix_settlement_inspect" && isDeepStrictEqual(item.result, expected),
);
const settlementCell = trace.calls.find((call) => call.id === failedCall?.parentId);
const settlementOutcome = settlementCell
? settledCallOutcome(callOutcomes(trace, settlementCell))
: undefined;
const failureText = JSON.stringify({
nested: trace.activities.filter((item) => item.name === "matrix_settle" && item.isError),
recovery: trace.outcomes.filter(
(outcome) =>
outcome.id === failedCall?.parentId ||
outcome.id === settlementOutcome?.id ||
outcome.isError ||
outcome.details.status === "failed",
),
});
checks.actionableDiagnostics =
failureText.includes("receipt") && failureText.includes("totalCents");
} else if (task === "javascript-contracts") {
const execs = trace.calls.filter((call) => call.name === "exec");
checks.javascriptArguments = execs.every(
(call) => !("language" in call.args) && !("typecheck" in call.args),
);
const completedOutput = (call: ToolCall) => {
const outcomes = callOutcomes(trace, call);
return completedCallOutcome(outcomes)
? JSON.stringify(outcomes.map((outcome) => outcome.details))
: "";
};
const fileList = execs.find((call) => {
if (!isDirectApiRead(call, "list", "tools/")) {
return false;
}
const output = completedOutput(call);
return ["read", "write"].every((name) => output.includes(`tools/${name}.d.ts`));
});
const declarations = ["read", "write"].map((name) =>
execs.find((call) => {
if (!isDirectApiRead(call, "read", `tools/${name}.d.ts`)) {
return false;
}
const output = completedOutput(call);
return output.includes(`declare function ${name}(`) && output.includes("string");
}),
);
const reads = activity.filter((item) => item.name === "read");
const writes = activity.filter((item) => item.name === "write");
const sourceRead = reads.find((item) => path.basename(String(item.input.path)) === "facts.txt");
const readback = reads.find((item) => path.basename(String(item.input.path)) === "result.txt");
const firstToolCell = execs.find((call) =>
trace.activities.some((item) => item.parentId === call.id),
);
const discovery = [fileList, ...declarations];
checks.declarationsBeforeTools =
firstToolCell !== undefined &&
discovery.every((call, index) => {
const next = discovery[index + 1] ?? firstToolCell;
return (
call !== undefined &&
(completedCallOutcome(callOutcomes(trace, call))?.eventIndex ?? Infinity) <
next.eventIndex
);
});
const rejectedReads = trace.activities.filter(
(item) => item.name === "read" && item.isError && item.input.path === 42,
);
const rejectedRead = rejectedReads.length === 1 ? rejectedReads[0] : undefined;
checks.caughtArgumentError =
rejectedRead !== undefined &&
execs.some((call) => {
if (call.id !== rejectedRead.parentId) {
return false;
}
const actualError = rejectedRead.result.error;
if (
typeof actualError !== "string" ||
!actualError.includes("Invalid arguments for tool")
) {
return false;
}
const outcomes = callOutcomes(trace, call);
if (!completedCallOutcome(outcomes)) {
return false;
}
const emitted = outcomes.flatMap((outcome) =>
Array.isArray(outcome.details.output) ? outcome.details.output.filter(record) : [],
);
return emitted.some(
(item) =>
item.type === "text" &&
typeof item.text === "string" &&
normalizeCaughtError(item.text) === normalizeCaughtError(actualError),
);
});
const written = writes[0];
checks.dependentReadWrite =
rejectedRead !== undefined &&
sourceRead !== undefined &&
readback !== undefined &&
writes.length === 1 &&
written !== undefined &&
path.basename(String(written.input.path)) === "result.txt" &&
written.input.content === expected.verificationCode &&
trace.activities.indexOf(rejectedRead) < trace.activities.indexOf(sourceRead) &&
activity.indexOf(sourceRead) < activity.indexOf(written) &&
activity.indexOf(written) < activity.indexOf(readback);
checks.observedSource =
typeof expected.verificationCode === "string" &&
matchesTextRead(sourceRead, `verification_code=${expected.verificationCode}\n`);
checks.observedReadback = matchesTextRead(readback, expected.verificationCode);
checks.onlyFixtureAccess =
reads.every(
(item) =>
item.input.path === sourceRead?.input.path || item.input.path === readback?.input.path,
) &&
activity.length === reads.length + writes.length &&
trace.activities.length === activity.length + rejectedReads.length &&
trace.activities.every(codeModeInvocation);
}
return checks;
}
/** Claims support the interview; an attempted expired read also needs observed runtime evidence. */
export function evaluateGatewayMatrixInterview(
task: GatewayMatrixContractTask,
taskTrace: GatewayMatrixTrace,
interviewTrace: GatewayMatrixTrace,
final: string,
): Record<string, boolean> {
const references = observedReferences(taskTrace);
const priorRefs = [...new Set(references.map((reference) => reference.id))];
const attempts = interviewTrace.calls.filter(
(call) =>
source(call).includes("results.load") && priorRefs.some((id) => source(call).includes(id)),
);
const unavailable = attempts.some((call) => {
const outcome = settledCallOutcome(callOutcomes(interviewTrace, call));
return outcome !== undefined && /unavailable|expired/iu.test(JSON.stringify(outcome.details));
});
const previewCoverage = new Set(
references
.filter((reference) => attempts.some((call) => source(call).includes(reference.id)))
.map((reference) => reference.previewComplete),
);
const previewComplete = previewCoverage.size === 1 ? [...previewCoverage][0] : null;
const answer = jsonAnswer(final);
const facts = record(answer) && record(answer.facts) ? answer.facts : {};
return {
answered:
record(answer) && typeof answer.rationale === "string" && answer.rationale.trim().length > 0,
noExternalAction: interviewTrace.activities.length === 0,
priorReferenceProbed: priorRefs.length === 0 || attempts.length > 0,
priorReferenceUnavailable:
priorRefs.length === 0 || (unavailable && facts.priorRefAvailable === false),
retainedSnapshotUnderstood:
priorRefs.length === 0 ||
(facts.retainedDataFresh === false &&
facts.sameRunOnly === true &&
facts.previewComplete === previewComplete),
noRollbackAssumption: task !== "partial-failure" || facts.failureImpliesRollback === false,
};
}
export function requireGatewayMatrixTools(catalog: unknown, required: readonly string[]): string[] {
const available = new Set(
records(catalog).flatMap((item) =>
typeof item.id === "string" &&
(item.source === "core" ||
(item.source === "plugin" && item.pluginId === "code-mode-matrix-fixture"))
? [item.id]
: [],
),
);
const missing = required.filter((name) => !available.has(name));
if (missing.length > 0) {
throw new Error(`Fixture capability preflight failed before model call: ${missing.join(", ")}`);
}
return [...required];
}
async function availablePort(): Promise<number> {
return await new Promise((resolve, reject) => {
const server = net.createServer();
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
const address = server.address();
if (!address || typeof address === "string") {
server.close();
reject(new Error("Unable to reserve loopback port"));
return;
}
server.close((error) => (error ? reject(error) : resolve(address.port)));
});
});
}
async function waitReady(child: ManagedRun, port: number, signal?: AbortSignal): Promise<void> {
const deadline = Date.now() + 90_000;
while (Date.now() < deadline) {
signal?.throwIfAborted();
if (child.activity.resultSettled) {
throw new Error("Owned benchmark Gateway exited during startup");
}
try {
const response = await fetch(`http://127.0.0.1:${port}/readyz`, {
signal: AbortSignal.timeout(1_000),
});
if (response.ok) {
return;
}
} catch {
/* Readiness is the observed startup condition. */
}
await delay(250);
}
throw new Error("Owned benchmark Gateway did not become ready within 90 seconds");
}
type ResponseResult = {
id?: string;
status?: string;
final: string;
error?: string;
usage?: unknown;
};
async function agentRequest(
port: number,
token: string,
prompt: string,
timeoutSeconds: number,
previousId?: string,
abortSignal?: AbortSignal,
sessionKey?: string,
maxOutputTokens?: number,
): Promise<ResponseResult> {
const url = `http://127.0.0.1:${port}/v1/responses`;
const timeout = AbortSignal.timeout(timeoutSeconds * 1_000);
const signal = abortSignal ? AbortSignal.any([timeout, abortSignal]) : timeout;
const response = await fetch(url, {
method: "POST",
headers: {
authorization: `Bearer ${token}`,
"content-type": "application/json",
"x-openclaw-agent-id": "qa",
...(sessionKey ? { "x-openclaw-session-key": sessionKey } : {}),
"x-openclaw-scopes": "operator.admin,operator.read,operator.write",
},
body: JSON.stringify({
model: "openclaw/qa",
input: prompt,
...(previousId ? { previous_response_id: previousId } : {}),
...(maxOutputTokens === undefined ? {} : { max_output_tokens: maxOutputTokens }),
stream: false,
}),
signal,
});
const bytes = await readResponseWithLimit(response, 4 * 1024 * 1024, {
signal,
onOverflow: ({ maxBytes }) => new Error(`${url} response body exceeded ${maxBytes} bytes`),
});
const text = new TextDecoder().decode(bytes);
if (!response.ok) {
throw new Error(`Gateway HTTP ${response.status}: ${text.slice(0, 2_000)}`);
}
const value: unknown = JSON.parse(text);
if (!record(value)) {
throw new Error("Gateway returned an invalid response envelope");
}
const final = (Array.isArray(value.output) ? value.output : [])
.flatMap((item) =>
record(item) && item.type === "message" && Array.isArray(item.content)
? item.content.flatMap((part) =>
record(part) && part.type === "output_text" && typeof part.text === "string"
? [part.text]
: [],
)
: [],
)
.join("\n");
return {
...(typeof value.id === "string" ? { id: value.id } : {}),
...(typeof value.status === "string" ? { status: value.status } : {}),
final,
...(value.usage !== undefined ? { usage: value.usage } : {}),
...(record(value.error) && typeof value.error.message === "string"
? { error: value.error.message }
: {}),
};
}
async function captureDeliveredFiles(params: {
workspace: string;
artifactDir: string;
outputDir: string;
files: readonly string[];
redact: (value: string) => string;
}): Promise<DeliveredFileEvidence[]> {
const workspace = await fs.realpath(params.workspace);
const evidence: DeliveredFileEvidence[] = [];
const maxFileBytes = 1024 * 1024;
let totalBytes = 0;
for (const [index, relativeSource] of params.files.entries()) {
try {
if (index >= 16) {
throw new Error("Delivered-file count exceeds 16.");
}
const file = path.resolve(workspace, relativeSource);
if (path.isAbsolute(relativeSource) || !file.startsWith(`${workspace}${path.sep}`)) {
throw new Error("Delivered file must stay within the workspace.");
}
if (!(await fs.lstat(file)).isFile()) {
throw new Error("Delivered file must be a regular file, not a symlink.");
}
const resolved = await fs.realpath(file);
if (!resolved.startsWith(`${workspace}${path.sep}`)) {
throw new Error("Delivered file resolves outside the workspace.");
}
const handle = await fs.open(resolved, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
let content: string;
try {
const stat = await handle.stat();
if (!stat.isFile() || stat.nlink !== 1 || stat.size > maxFileBytes) {
throw new Error(
"Delivered file must be a single-link regular file no larger than 1 MiB.",
);
}
const buffer = Buffer.alloc(stat.size + 1);
let length = 0;
while (length < buffer.length) {
const read = await handle.read(buffer, length, buffer.length - length, length);
if (read.bytesRead === 0) {
break;
}
length += read.bytesRead;
}
if (length !== stat.size) {
throw new Error("Delivered file changed during capture.");
}
content = new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(0, length));
} finally {
await handle.close();
}
const redacted = redactForDevToolLog(params.redact(content));
const bytes = Buffer.byteLength(redacted);
if (bytes > maxFileBytes || totalBytes + bytes > 4 * maxFileBytes) {
throw new Error("Redacted deliverables exceed the 1 MiB file or 4 MiB cell limit.");
}
const destination = path.join(
params.artifactDir,
"delivered",
path.relative(workspace, file),
);
await fs.mkdir(path.dirname(destination), { recursive: true });
await fs.writeFile(destination, redacted, { flag: "wx", mode: 0o600 });
totalBytes += bytes;
evidence.push({
source: relativeSource,
status: "captured",
path: path.relative(params.outputDir, destination),
bytes,
sha256: createHash("sha256").update(redacted).digest("hex"),
});
} catch (error) {
evidence.push({
source: relativeSource,
status: "unavailable",
reason: redactForDevToolLog(
params.redact(error instanceof Error ? error.message : "Delivered-file capture failed."),
).slice(0, 300),
});
}
}
return evidence;
}
/** Run a neutral workload or an explicit contract probe in a disposable Gateway. */
export async function runGatewayMatrixCell(
params: RunCellParams & { cell: RunCellParams["cell"] & { task: GatewayMatrixTask } },
): Promise<CodeModeMatrixCellResult> {
if (!params.runtime) {
throw new Error("Built runtime entrypoint was not prepared");
}
const executor = params.executor ?? "node";
const provider = params.cell.model.split("/")[0]!;
const providerConfig: OpenClawConfig = {
plugins: { allow: [provider], entries: { [provider]: { enabled: true } } },
};
const credentials = matrixProviderEnv(params.cell.model, providerConfig, process.env);
const credentialValues = Object.values(credentials).filter((value): value is string =>
Boolean(value),
);
if (credentialValues.length === 0) {
throw new Error(`No API key environment input available for provider ${provider}`);
}
const fixture = matrixFixture(params.cell.task, params.cell.repetition);
const performance = fixture.performance;
const allowedTools = gatewayAllowedTools(
params.cell.task,
fixture.requiredTools,
performance?.allowedTools,
);
const root = await fs.realpath(
await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-code-mode-matrix-")),
);
const stateDir = path.join(root, "state");
const workspace = path.join(root, "workspace");
const pluginDir = path.join(root, "fixture");
const receiptsPath = path.join(root, "receipts.jsonl");
const artifactDir = path.join(params.outputDir, "cells", params.cell.id);
const rootSessionKey = `agent:qa:matrix:${randomUUID()}`;
const token = `synthetic-matrix-${randomUUID()}`;
const redact = (value: string) =>
credentialValues.reduce(
(text, secret) => text.replaceAll(secret, "[REDACTED]"),
value.replaceAll(token, "[SYNTHETIC_GATEWAY_TOKEN]"),
);
const write = async (name: string, value: unknown) =>
fs.writeFile(path.join(artifactDir, name), redact(`${JSON.stringify(value, null, 2)}\n`), {
mode: 0o600,
});
const readReceipts = async (): Promise<unknown[]> =>
(await fs.readFile(receiptsPath, "utf8"))
.split("\n")
.filter(Boolean)
.map((line) => JSON.parse(line));
await Promise.all(
[
stateDir,
workspace,
pluginDir,
path.join(root, "home"),
path.join(root, "tmp"),
artifactDir,
].map((directory) => fs.mkdir(directory, { recursive: true })),
);
await fs.writeFile(path.join(pluginDir, "index.mjs"), fixture.pluginSource);
await fs.writeFile(receiptsPath, "", { mode: 0o600 });
await fs.writeFile(
path.join(pluginDir, "openclaw.plugin.json"),
JSON.stringify(createGatewayMatrixPluginManifest(fixture.requiredTools)),
);
await fs.writeFile(
path.join(pluginDir, "package.json"),
JSON.stringify({
name: "code-mode-matrix-fixture",
version: "1.0.0",
type: "module",
openclaw: { extensions: ["./index.mjs"] },
}),
);
for (const [name, content] of Object.entries(fixture.workspaceFiles ?? {})) {
const file = path.resolve(workspace, name);
if (!file.startsWith(`${workspace}${path.sep}`)) {
throw new Error(`Fixture path escapes its workspace: ${name}`);
}
await fs.mkdir(path.dirname(file), { recursive: true });
await fs.writeFile(file, content);
}
if (fixture.processHelperSource !== undefined) {
await fs.writeFile(path.join(workspace, "process-probe.mjs"), fixture.processHelperSource);
}
const port = await availablePort();
const configPath = path.join(stateDir, "openclaw.json");
const baseConfig = {
logging: {
level: "info",
consoleLevel: "info",
consoleStyle: "compact",
file: path.join(root, "gateway.log"),
},
env: { shellEnv: { enabled: false } },
agents: {
defaults: {
workspace,
skipBootstrap: true,
thinkingDefault: params.thinking,
heartbeat: { every: "0m" },
systemAgent: { agentId: "qa" },
},
entries: { qa: {} },
},
plugins: {
allow: [
provider,
...(executor === "quickjs" ? ["code-mode-quickjs"] : []),
...(fixture.requiredTools.length ? ["code-mode-matrix-fixture"] : []),
],
slots: { memory: "none" },
...(fixture.requiredTools.length ? { load: { paths: [pluginDir] } } : {}),
entries: {
[provider]: { enabled: true },
...(executor === "quickjs" ? { "code-mode-quickjs": { enabled: true } } : {}),
...(fixture.requiredTools.length
? { "code-mode-matrix-fixture": { enabled: true, config: { receiptsPath } } }
: {}),
},
},
memory: { search: { enabled: false } },
skills: { load: { watch: false } },
discovery: { mdns: { mode: "off" } },
tools: {
profile: "full",
allow: allowedTools,
fs: { workspaceOnly: true },
exec: { security: "full", ask: "off" },
},
gateway: {
mode: "local",
bind: "loopback",
port,
auth: { mode: "token", token },
controlUi: { enabled: false },
http: { endpoints: { responses: { enabled: true } } },
},
};
// Task-specific limits cannot change the selected treatment, runtime, or model settings.
const cfg = mergeDeep(mergeDeep(baseConfig, performance?.configPatch ?? {}), {
agents: matrixModelConfig(params.cell.model, params.thinking),
tools: { codeMode: { enabled: params.cell.mode === "code", executor } },
});
await fs.writeFile(configPath, JSON.stringify(cfg), { mode: 0o600 });
const env: NodeJS.ProcessEnv = {
PATH: process.env.PATH,
SystemRoot: process.env.SystemRoot,
HOME: path.join(root, "home"),
USERPROFILE: path.join(root, "home"),
OPENCLAW_HOME: path.join(root, "home"),
TMPDIR: path.join(root, "tmp"),
TEMP: path.join(root, "tmp"),
TMP: path.join(root, "tmp"),
...credentials,
OPENCLAW_STATE_DIR: stateDir,
OPENCLAW_CONFIG_PATH: configPath,
OPENCLAW_BUNDLED_PLUGINS_DIR: path.join(params.runtime.cwd, "dist", "extensions"),
OPENCLAW_SKIP_CHANNELS: "1",
OPENCLAW_SKIP_GMAIL_WATCHER: "1",
OPENCLAW_SKIP_CRON: "1",
OPENCLAW_SKIP_CANVAS_HOST: "1",
OPENCLAW_SKIP_ACPX_RUNTIME: "1",
OPENCLAW_SKIP_ACPX_RUNTIME_PROBE: "1",
NODE_DISABLE_COMPILE_CACHE: "1",
OPENCLAW_DEBUG_CODE_MODE: "1",
NO_COLOR: "1",
};
const startedAt = Date.now();
const { createProcessSupervisor } = await import("../../src/process/supervisor/supervisor.js");
const { runCommandWithTimeout } = await import("../../src/process/exec.js");
const supervisor = createProcessSupervisor();
const scopeKey = `code-mode-matrix:${randomUUID()}`;
const cleanup = supervisor.acquireScopeCleanup(scopeKey, { processTree: "required-all" });
let child: ManagedRun | undefined;
let log = "";
const pendingLogLines = { stdout: "", stderr: "" };
const retryWarnings = new Map<string, string>();
const activationDiagnostics = new Map<string, GatewayMatrixActivationDiagnostic>();
const inspectLogLine = (line: string) => {
for (const signature of ["[responses] retrying", "[session-recovery] Anthropic thinking"]) {
if (line.includes(signature) && !retryWarnings.has(signature)) {
retryWarnings.set(signature, line.slice(0, 4_096));
}
}
const diagnostic = parseGatewayMatrixActivationDiagnostic(line);
if (diagnostic) {
activationDiagnostics.set(JSON.stringify(diagnostic), diagnostic);
}
};
let failure: unknown;
let cleanupCertain: boolean;
let task: ResponseResult = { final: "" };
let interview: ResponseResult = { final: "" };
let taskEvents: unknown[] = [];
let interviewEvents: unknown[] = [];
let startupMs = 0;
let taskElapsedMs: number | undefined;
let taskResponseAt: number | undefined;
let interviewElapsedMs: number | undefined;
let taskStartedAt: number | undefined;
let interviewStartedAt: number | undefined;
let beforeTask: MatrixLedgerBoundary | undefined;
let taskBoundary: MatrixLedgerBoundary | undefined;
let ledger: MatrixSessionLedger | undefined;
let taskRecords: unknown[] | undefined;
let receipts: unknown[] = [];
let taskReceipts: unknown[] | undefined;
const runCli = async (args: string[]) => {
const result = await runCommandWithTimeout(
[process.execPath, ...params.runtime!.args, ...args],
{
cwd: workspace,
baseEnv: {},
env,
input: "",
timeoutMs: 40_000,
signal: params.abortSignal,
maxOutputBytes: 1024 * 1024,
killProcessTree: true,
requireProcessTreeExtinction: true,
},
);
if (result.code !== 0 || result.cleanup === "uncertain") {
throw new Error(
`Benchmark CLI failed: ${redact(result.stderr).slice(-2_000) || result.cleanup || result.code}`,
);
}
return JSON.parse(result.stdout) as unknown;
};
try {
const capture = (stream: "stdout" | "stderr", chunk: string) => {
log = `${log}${chunk}`.slice(-64 * 1024);
const lines = `${pendingLogLines[stream]}${chunk}`.split(/\r?\n/u);
pendingLogLines[stream] = (lines.pop() ?? "").slice(-16_384);
for (const line of lines) {
inspectLogLine(line);
}
};
child = await supervisor.spawn({
mode: "child",
scopeKey,
argv: [
process.execPath,
...params.runtime.args,
"gateway",
"--port",
String(port),
"--bind",
"loopback",
"--allow-unconfigured",
],
cwd: workspace,
env,
exactEnv: true,
stdinMode: "pipe-closed",
timeoutMs: (params.timeoutSeconds * (performance ? 1 : 2) + 120) * 1_000,
captureOutput: false,
onStdout: (chunk) => capture("stdout", chunk),
onStderr: (chunk) => capture("stderr", chunk),
});
await waitReady(child, port, params.abortSignal);
const catalog = await runCli([
"gateway",
"call",
"tools.catalog",
"--params",
JSON.stringify({ agentId: "qa", includePlugins: true }),
"--url",
`ws://127.0.0.1:${port}`,
"--token",
token,
"--timeout",
"30000",
"--json",
]);
requireGatewayMatrixTools(catalog, allowedTools);
await write("tool-catalog.json", catalog);
beforeTask = captureMatrixLedgerBoundary(await readMatrixSessionLedger(stateDir));
startupMs = Date.now() - startedAt;
taskStartedAt = Date.now();
try {
task = await agentRequest(
port,
token,
fixture.prompt,
params.timeoutSeconds,
undefined,
params.abortSignal,
rootSessionKey,
performance ? undefined : MAX_MODEL_OUTPUT_TOKENS,
);
} finally {
taskResponseAt = Date.now();
taskElapsedMs = taskResponseAt - taskStartedAt;
taskReceipts = await readReceipts();
}
taskBoundary = captureMatrixLedgerBoundary(await readMatrixSessionLedger(stateDir));
if (performance?.inspectSubagents) {
const listed = await runCli(["tasks", "list", "--json", "--runtime", "subagent"]);
taskRecords = record(listed) && Array.isArray(listed.tasks) ? listed.tasks : [];
await write("task-records.json", taskRecords);
}
if (!performance) {
if (!task.id) {
throw new Error("Task response lacks continuity id for the interview");
}
interviewStartedAt = Date.now();
try {
interview = await agentRequest(
port,
token,
fixture.interviewPrompt,
params.timeoutSeconds,
task.id,
params.abortSignal,
rootSessionKey,
MAX_MODEL_OUTPUT_TOKENS,
);
} finally {
interviewElapsedMs = Date.now() - interviewStartedAt;
}
}
} catch (error) {
failure = error;
} finally {
if (taskStartedAt === undefined) {
startupMs = Date.now() - startedAt;
}
child?.cancel("manual-cancel");
cleanupCertain = true;
for (const settle of [() => child?.wait(), cleanup, () => supervisor.shutdown()]) {
try {
await settle();
} catch (error) {
cleanupCertain = false;
failure ??= error;
}
}
if (taskStartedAt !== undefined) {
try {
ledger = await readMatrixSessionLedger(stateDir);
const events = (selection: ReturnType<typeof selectMatrixLedgerRows>) =>
selection.rows.map((row) =>
record(row.event) ? { ...row.event, matrixSessionKey: row.sessionKey } : row.event,
);
taskEvents = events(
selectMatrixLedgerRows({
ledger,
before: beforeTask,
...(interviewStartedAt !== undefined ? { after: taskBoundary } : {}),
rootSessionKeys: [rootSessionKey],
}),
);
if (interviewStartedAt !== undefined) {
interviewEvents = events(
selectMatrixLedgerRows({
ledger,
before: taskBoundary,
rootSessionKeys: [rootSessionKey],
}),
);
}
} catch (error) {
failure ??= error;
}
}
try {
receipts = await readReceipts();
} catch (error) {
failure ??= error;
}
taskReceipts ??= receipts;
await write("task-transcript.json", taskEvents);
await write("interview-transcript.json", interviewEvents);
await write("receipts.json", receipts);
await write("task-receipts.json", taskReceipts);
await write("interview-receipts.json", receipts.slice(taskReceipts.length));
if (ledger) {
await write("session-ledger.json", ledger);
}
for (const line of Object.values(pendingLogLines)) {
inspectLogLine(line);
}
await write("activation-diagnostics.json", [...activationDiagnostics.values()]);
await fs.writeFile(path.join(artifactDir, "gateway.log"), redact(log), { mode: 0o600 });
}
const trace = collectGatewayMatrixTrace(taskEvents);
const interviewTrace = collectGatewayMatrixTrace(interviewEvents);
const accounting = ledger
? collectMatrixUsage({
ledger,
before: beforeTask,
...(interviewStartedAt !== undefined ? { after: taskBoundary } : {}),
rootSessionKeys: [rootSessionKey],
settled: cleanupCertain,
terminalResponseObserved: task.status === "completed",
rootUsage: task.usage,
runtimeLog: [...retryWarnings.values(), log].join("\n"),
})
: undefined;
const interviewAccounting =
ledger && interviewStartedAt !== undefined
? collectMatrixUsage({
ledger,
before: taskBoundary,
rootSessionKeys: [rootSessionKey],
settled: cleanupCertain,
terminalResponseObserved: interview.status === "completed",
rootUsage: interview.usage,
runtimeLog: [...retryWarnings.values(), log].join("\n"),
})
: undefined;
const sessionActivation = [
...new Set(trace.calls.map((call) => call.sessionKey ?? rootSessionKey)),
].map((sessionKey) => {
const calls = trace.calls.filter((call) => (call.sessionKey ?? rootSessionKey) === sessionKey);
return {
sessionKey,
codeMode: calls.some((call) => call.name === "exec" && typeof call.args.code === "string"),
toolCalls: calls.length,
};
});
const {
observedActivation,
qualifyingActivation,
activationComplete,
actualCodeMode,
engagement,
} = evaluateGatewayMatrixActivation({
diagnostics: [...activationDiagnostics.values()],
rootRunId: task.id,
childRunIds:
ledger?.runs
.filter((run) => run.requesterSessionKey === rootSessionKey)
.map((run) => run.runId) ?? [],
expectedEnabled: params.cell.mode === "code",
});
let behavior: Record<string, boolean>;
if (performance) {
try {
behavior = await performance.evaluate({
workspace,
trace,
receipts: taskReceipts,
taskResponseAt,
taskRecords,
});
} catch (error) {
failure ??= error;
behavior = { rubricCompleted: false };
}
behavior = {
...behavior,
engagement,
underlyingToolExecution: trace.activities.length > 0,
finalResponsePresent: task.final.trim().length > 0,
};
} else {
if (isMatrixPerformanceTask(params.cell.task)) {
throw new Error("Missing performance fixture");
}
behavior = evaluateGatewayMatrixTask({
task: params.cell.task,
expected: fixture.expected,
final: task.final,
trace,
receipts: taskReceipts,
probeCode: fixture.probeCode,
});
if (params.cell.task === "javascript-contracts") {
behavior.persistedFile =
(await fs.readFile(path.join(workspace, "result.txt"), "utf8").catch(() => undefined)) ===
fixture.expected.verificationCode;
}
}
const deliveredFiles = performance
? await captureDeliveredFiles({
workspace,
artifactDir,
outputDir: params.outputDir,
files: performance.deliveredFiles,
redact,
})
: undefined;
if (deliveredFiles) {
await write("delivered-files.json", deliveredFiles);
}
const interviewChecks =
!performance && !isMatrixPerformanceTask(params.cell.task)
? evaluateGatewayMatrixInterview(params.cell.task, trace, interviewTrace, interview.final)
: {};
const identity =
trace.models.length > 0 &&
trace.models.every((model) => model === params.cell.model) &&
(performance !== undefined ||
(interviewTrace.models.length > 0 &&
interviewTrace.models.every((model) => model === params.cell.model)));
const behaviorPassed =
Object.values(behavior).length > 0 && Object.values(behavior).every(Boolean);
const passed =
!failure &&
cleanupCertain &&
task.status === "completed" &&
identity &&
behaviorPassed &&
(performance !== undefined ||
(interview.status === "completed" && Object.values(interviewChecks).every(Boolean)));
const finalAssistants = new Map<string, RecordValue>();
for (const event of taskEvents) {
if (!record(event)) {
continue;
}
const message = record(event.message) ? event.message : event;
if (message.role === "assistant") {
finalAssistants.set(
typeof event.matrixSessionKey === "string" ? event.matrixSessionKey : rootSessionKey,
message,
);
}
}
const modelError = [...finalAssistants.values()]
.filter((message) => message.stopReason === "error" && typeof message.errorMessage === "string")
.map((message) => message.errorMessage)
.join("\n");
const error =
failure instanceof Error
? redact(failure.message)
: (task.error ?? interview.error ?? (!passed && modelError ? redact(modelError) : undefined));
const providerFailure = !passed
? classifyCodeModeMatrixProviderFailure(redact(`${error ?? ""}\n${modelError}`))
: null;
const timedOut =
failure instanceof Error &&
(failure.name === "TimeoutError" || /timed out|deadline|timeout/iu.test(failure.message));
const gateway: GatewayMatrixEvidence = {
...createGatewayMatrixWorkload(
params.cell.task,
params.cell.repetition,
params.thinking,
params.timeoutSeconds,
executor,
),
behavior,
startupMs,
traceAvailable: ledger !== undefined,
...(deliveredFiles ? { deliveredFiles } : {}),
...(taskElapsedMs !== undefined ? { taskElapsedMs } : {}),
...(taskResponseAt !== undefined ? { taskResponseAt } : {}),
...(ledger
? {
upstreamCalls: trace.activities.length,
outerCalls: trace.calls.length,
outerOutputBytes: Buffer.byteLength(
JSON.stringify(trace.outcomes.map((outcome) => outcome.content)),
),
taskAssistantTurns: trace.assistantTurns,
}
: {}),
interview: {
...(performance ? { skipped: true } : {}),
traceAvailable: ledger !== undefined && interviewStartedAt !== undefined,
...(interviewElapsedMs !== undefined ? { elapsedMs: interviewElapsedMs } : {}),
...(interviewAccounting ? { accounting: interviewAccounting } : {}),
answer: jsonAnswer(interview.final) ?? interview.final,
rationaleReview: "required",
checks: interviewChecks,
...(interviewStartedAt !== undefined ? { trace: interviewTrace } : {}),
},
artifacts: {
taskTrace: path.relative(params.outputDir, path.join(artifactDir, "task-transcript.json")),
interviewTrace: path.relative(
params.outputDir,
path.join(artifactDir, "interview-transcript.json"),
),
receipts: path.relative(params.outputDir, path.join(artifactDir, "receipts.json")),
taskReceipts: path.relative(params.outputDir, path.join(artifactDir, "task-receipts.json")),
interviewReceipts: path.relative(
params.outputDir,
path.join(artifactDir, "interview-receipts.json"),
),
log: path.relative(params.outputDir, path.join(artifactDir, "gateway.log")),
...(deliveredFiles
? {
deliveredFiles: path.relative(
params.outputDir,
path.join(artifactDir, "delivered-files.json"),
),
}
: {}),
},
};
await write("evidence.json", {
gateway,
task,
interview,
accounting,
sessionActivation,
activationComplete,
observedActivation,
qualifyingActivation,
cleanupCertain,
});
if (params.keepState || failure || !passed) {
await write("retained-state.json", {
root,
reason: params.keepState ? "requested" : "failure inspection",
});
} else {
await fs.rm(root, { recursive: true, force: true });
}
const slash = params.cell.model.indexOf("/");
return {
id: params.cell.id,
executor,
task: params.cell.task,
model: params.cell.model,
mode: params.cell.mode,
repetition: params.cell.repetition,
gitSha: params.gitSha,
buildSha256: params.buildSha256,
sourceDirty: params.sourceDirty,
sourcePatchSha256: params.sourcePatchSha256,
timestamp: new Date().toISOString(),
passed,
status: timedOut ? "timeout" : error ? "error" : "ok",
elapsedMs: Date.now() - startedAt,
expected: JSON.stringify(fixture.expected),
final: redact(task.final),
failureCategory: passed
? null
: (providerFailure ??
(timedOut ? "timeout" : null) ??
(failure
? "harness_error"
: !identity
? "model_mismatch"
: !engagement
? "activation"
: !behaviorPassed || task.status !== "completed"
? "tool_execution"
: "interview_mismatch")),
...(error
? {
diagnostics: error.slice(0, 8_000),
error: { kind: "gateway_benchmark", message: error.slice(0, 2_000) },
}
: {}),
codeModeEngaged: activationComplete ? actualCodeMode : null,
observedProvider: identity ? params.cell.model.slice(0, slash) : null,
observedModel: identity ? params.cell.model.slice(slash + 1) : null,
...(accounting ? { accounting } : {}),
...(ledger ? { assistantTurns: trace.assistantTurns } : {}),
...(trace.usage ? { usage: trace.usage } : {}),
...(accounting?.costComplete && accounting.costUsd !== null
? { costUsd: accounting.costUsd }
: {}),
oracle: {
answer: performance ? null : behavior.answer === true,
effect: behaviorPassed,
engagement,
identity,
toolExecution: trace.activities.length > 0,
},
gateway,
};
}