test(agents): remove aggregate command test facade (#121789)

This commit is contained in:
Peter Steinberger
2026-08-10 18:42:31 -07:00
committed by GitHub
parent b985d5a1ed
commit 595ac6eb28
9 changed files with 74 additions and 188 deletions
@@ -8,7 +8,8 @@
* - emitIngressModelUsageDiagnostic with null/missing usage
*/
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { emitIngressModelUsageDiagnostic } from "./command/ingress-diagnostics.js";
const mocks = vi.hoisted(() => ({
emitTrustedDiagnosticEvent: vi.fn(),
@@ -43,13 +44,6 @@ vi.mock("../config/io.js", () => ({
getRuntimeConfig: () => mocks.getRuntimeConfig(),
}));
let testing: typeof import("./agent-command.js").testing;
beforeAll(async () => {
const mod = await import("./agent-command.js");
testing = mod.testing;
});
beforeEach(() => {
vi.clearAllMocks();
mocks.isDiagnosticsEnabled.mockReturnValue(true);
@@ -63,63 +57,6 @@ afterEach(() => {
vi.clearAllMocks();
});
describe("resolveAgentRunLifecycleEndLogLevel", () => {
it("logs successful stop and tool-use metadata at info", () => {
expect(
testing.resolveAgentRunLifecycleEndLogLevel({
aborted: false,
stopReason: "stop",
}),
).toBe("info");
expect(
testing.resolveAgentRunLifecycleEndLogLevel({
aborted: false,
stopReason: "toolUse",
}),
).toBe("info");
});
it("does not log ordinary end-turn completions", () => {
expect(
testing.resolveAgentRunLifecycleEndLogLevel({
aborted: false,
stopReason: "end_turn",
}),
).toBeUndefined();
expect(testing.resolveAgentRunLifecycleEndLogLevel({ aborted: false })).toBeUndefined();
});
it("keeps timeout metadata out of error severity", () => {
expect(
testing.resolveAgentRunLifecycleEndLogLevel({
aborted: true,
stopReason: "timeout",
}),
).toBe("warn");
expect(
testing.resolveAgentRunLifecycleEndLogLevel({
stopReason: "stop",
timeoutPhase: "provider",
providerStarted: true,
}),
).toBe("warn");
});
it("logs cancelled and failed endings at error", () => {
expect(
testing.resolveAgentRunLifecycleEndLogLevel({
aborted: true,
stopReason: "stop",
}),
).toBe("error");
expect(
testing.resolveAgentRunLifecycleEndLogLevel({
stopReason: "error",
}),
).toBe("error");
});
});
function makeResult(overrides?: Record<string, unknown>) {
return {
payloads: [{ text: "hello", mediaUrl: "" }],
@@ -160,58 +97,12 @@ function makeOpts(overrides?: Record<string, unknown>) {
};
}
// ---------------------------------------------------------------------------
// ingressDiagnosticChannel
// ---------------------------------------------------------------------------
describe("ingressDiagnosticChannel", () => {
it("returns runContext.messageChannel when set", () => {
const channel = testing.ingressDiagnosticChannel({
message: "hi",
allowModelOverride: false,
runContext: { messageChannel: "discord" },
messageChannel: "api",
channel: "http",
});
expect(channel).toBe("discord");
});
it("falls back to opts.messageChannel", () => {
const channel = testing.ingressDiagnosticChannel({
message: "hi",
allowModelOverride: false,
messageChannel: "api",
channel: "http",
});
expect(channel).toBe("api");
});
it("falls back to opts.channel", () => {
const channel = testing.ingressDiagnosticChannel({
message: "hi",
allowModelOverride: false,
channel: "webchat",
});
expect(channel).toBe("webchat");
});
it('defaults to "http" when no channel info is present', () => {
const channel = testing.ingressDiagnosticChannel({
message: "hi",
allowModelOverride: false,
});
expect(channel).toBe("http");
});
});
// ---------------------------------------------------------------------------
// emitIngressModelUsageDiagnostic
// ---------------------------------------------------------------------------
describe("emitIngressModelUsageDiagnostic", () => {
it("emits model.usage when diagnostics are enabled and result has usage", () => {
const result = makeResult();
const opts = makeOpts();
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).toHaveBeenCalledTimes(1);
const event = mocks.emitTrustedDiagnosticEvent.mock.calls[0]?.[0];
@@ -248,7 +139,7 @@ describe("emitIngressModelUsageDiagnostic", () => {
},
});
testing.emitIngressModelUsageDiagnostic(result, makeOpts());
emitIngressModelUsageDiagnostic(result, makeOpts());
expect(mocks.estimateUsageCost).toHaveBeenCalledWith({
usage: {
@@ -281,7 +172,7 @@ describe("emitIngressModelUsageDiagnostic", () => {
const result = makeResult();
const opts = makeOpts();
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).not.toHaveBeenCalled();
});
@@ -295,7 +186,7 @@ describe("emitIngressModelUsageDiagnostic", () => {
const opts = makeOpts();
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).not.toHaveBeenCalled();
});
@@ -305,7 +196,7 @@ describe("emitIngressModelUsageDiagnostic", () => {
const result = makeResult();
const opts = makeOpts();
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).not.toHaveBeenCalled();
});
@@ -317,18 +208,29 @@ describe("emitIngressModelUsageDiagnostic", () => {
messageChannel: "api",
});
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).toHaveBeenCalledTimes(1);
const event = mocks.emitTrustedDiagnosticEvent.mock.calls[0]?.[0];
expect(event.channel).toBe("discord");
});
it("falls back to opts.channel when messageChannel is absent", () => {
const result = makeResult();
const opts = makeOpts({ messageChannel: undefined, channel: "webchat" });
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).toHaveBeenCalledTimes(1);
const event = mocks.emitTrustedDiagnosticEvent.mock.calls[0]?.[0];
expect(event.channel).toBe("webchat");
});
it('defaults channel to "http" when no channel info is present', () => {
const result = makeResult();
const opts = { message: "hi", allowModelOverride: false };
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).toHaveBeenCalledTimes(1);
const event = mocks.emitTrustedDiagnosticEvent.mock.calls[0]?.[0];
@@ -339,7 +241,7 @@ describe("emitIngressModelUsageDiagnostic", () => {
const result = makeResult();
const opts = makeOpts();
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.resolveModelCostConfig).toHaveBeenCalledWith({
provider: "openai",
@@ -363,7 +265,7 @@ describe("emitIngressModelUsageDiagnostic", () => {
});
const opts = makeOpts();
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).toHaveBeenCalledTimes(1);
const event = mocks.emitTrustedDiagnosticEvent.mock.calls[0]?.[0];
@@ -390,7 +292,7 @@ describe("emitIngressModelUsageDiagnostic", () => {
});
const opts = makeOpts();
testing.emitIngressModelUsageDiagnostic(result, opts);
emitIngressModelUsageDiagnostic(result, opts);
expect(mocks.emitTrustedDiagnosticEvent).toHaveBeenCalledTimes(1);
const event = mocks.emitTrustedDiagnosticEvent.mock.calls[0]?.[0];
@@ -670,13 +670,11 @@ vi.mock("../acp/control-plane/manager.js", () => ({
let agentCommand: typeof import("./agent-command.js").agentCommand;
let agentCommandFromSystem: typeof import("./agent-command.js").agentCommandFromSystem;
let agentCommandTesting: typeof import("./agent-command.js").testing;
beforeAll(async () => {
const mod = await import("./agent-command.js");
agentCommand ??= mod.agentCommand;
agentCommandFromSystem ??= mod.agentCommandFromSystem;
agentCommandTesting ??= mod.testing;
});
type FallbackRunnerParams = {
@@ -2213,23 +2211,6 @@ describe("agentCommand LiveSessionModelSwitchError retry", () => {
});
});
it("scopes explicit-agent sentinel store keys before command routing", () => {
expect(
agentCommandTesting.resolveExplicitAgentCommandSessionKey({
rawExplicitSessionKey: "global",
agentIdOverride: "work",
cfg: {},
}),
).toBe("agent:work:global");
expect(
agentCommandTesting.resolveExplicitAgentCommandSessionKey({
rawExplicitSessionKey: "main",
agentIdOverride: "work",
cfg: {},
}),
).toBe("agent:work:main");
});
it("persists explicit overrides even when ingress skips the initial touch", async () => {
setupSingleAttemptFallback();
state.runAgentAttemptMock.mockResolvedValue(makeSuccessResult("openai", "gpt-5.4"));
+2 -19
View File
@@ -30,20 +30,12 @@ import {
shouldPersistRestartRecoveryCleanup,
shouldPersistRestartRecoveryContextClaim,
} from "./agent-command-restart-recovery.js";
import { resolveAgentRuntimeConfig } from "./agent-runtime-config.js";
import { runAcpAgentCommand } from "./command/acp-execution.js";
import { repairPendingAssistantTranscriptTurns } from "./command/assistant-transcript-repair.js";
import {
emitIngressModelUsageDiagnostic,
ingressDiagnosticChannel,
} from "./command/ingress-diagnostics.js";
import { resolveAgentRunLifecycleEndLogLevel } from "./command/lifecycle.js";
import { emitIngressModelUsageDiagnostic } from "./command/ingress-diagnostics.js";
import { resolveEmbeddedModelSelection } from "./command/model-selection.js";
import { finalizeEmbeddedAgentCommand } from "./command/post-run.js";
import {
prepareAgentCommandExecution,
resolveExplicitAgentCommandSessionKey,
} from "./command/prepare.js";
import { prepareAgentCommandExecution } from "./command/prepare.js";
import { runEmbeddedAgentAttempt } from "./command/run-embedded-attempt.js";
import { loadSessionStoreRuntime, resolveAgentCommandDeps } from "./command/runtime-loaders.js";
import { persistSessionEntry, prepareCurrentRunDelivery } from "./command/session-helpers.js";
@@ -694,12 +686,3 @@ export async function agentCommandFromGatewayIngress(
) {
return await agentCommandFromIngressInternal(opts, runtime, deps, recovery);
}
export const testing = {
resolveAgentRuntimeConfig,
prepareAgentCommandExecution,
resolveExplicitAgentCommandSessionKey,
resolveAgentRunLifecycleEndLogLevel,
ingressDiagnosticChannel,
emitIngressModelUsageDiagnostic,
};
+1 -1
View File
@@ -29,7 +29,7 @@ type AgentCommandResult = {
};
/** Resolve the channel label for model.usage diagnostics from ingress run options. */
export function ingressDiagnosticChannel(opts: AgentCommandIngressOpts): string {
function ingressDiagnosticChannel(opts: AgentCommandIngressOpts): string {
return opts.runContext?.messageChannel ?? opts.messageChannel ?? opts.channel ?? "http";
}
+39 -2
View File
@@ -2,14 +2,51 @@ import { describe, expect, it, vi } from "vitest";
import { buildAgentRunTerminalOutcome } from "../agent-run-terminal-outcome.js";
import { createAgentCommandLifecycle } from "./lifecycle.js";
const emitAgentEvent = vi.hoisted(() => vi.fn());
const { emitAgentEvent, lifecycleLog } = vi.hoisted(() => ({
emitAgentEvent: vi.fn(),
lifecycleLog: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
}));
vi.mock("../../infra/agent-events.js", () => ({ emitAgentEvent }));
vi.mock("../../logging/subsystem.js", () => ({
createSubsystemLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn() }),
createSubsystemLogger: () => lifecycleLog,
}));
describe("createAgentCommandLifecycle", () => {
it.each([
{ name: "successful stops", status: "ok", stopReason: "stop", level: "info" },
{ name: "tool-use stops", status: "ok", stopReason: "toolUse", level: "info" },
{ name: "ordinary end turns", status: "ok", stopReason: "end_turn", level: undefined },
{ name: "timeouts", status: "timeout", stopReason: "timeout", level: "warn" },
{ name: "cancelled runs", status: "error", stopReason: "stop", level: "error" },
{ name: "failed runs", status: "error", stopReason: "error", level: "error" },
] as const)("logs $name at the expected severity", ({ status, stopReason, level }) => {
vi.clearAllMocks();
const lifecycle = createAgentCommandLifecycle({
runId: "logged-terminal-owner",
lifecycleGeneration: () => "test-generation",
startedAt: 100,
state: {
currentTurnUserMessagePersisted: true,
lifecycleFinishing: false,
lifecycleEnded: false,
},
});
lifecycle.emitEnd({
metadata: {},
outcome: buildAgentRunTerminalOutcome({ status, stopReason }),
});
for (const candidate of ["info", "warn", "error"] as const) {
if (candidate === level) {
expect(lifecycleLog[candidate]).toHaveBeenCalledOnce();
} else {
expect(lifecycleLog[candidate]).not.toHaveBeenCalled();
}
}
});
it.each(["finishing", "end", "error"] as const)(
"preserves only canonical terminal facts on %s events",
(phase) => {
+1 -16
View File
@@ -2,10 +2,7 @@ import { emitAgentEvent } from "../../infra/agent-events.js";
import { formatErrorMessage } from "../../infra/errors.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { normalizeAgentRunTerminalDeliverySnapshot } from "../agent-run-terminal-delivery.js";
import {
buildAgentRunTerminalOutcomeFromLifecycleEvent,
type AgentRunTerminalOutcome,
} from "../agent-run-terminal-outcome.js";
import type { AgentRunTerminalOutcome } from "../agent-run-terminal-outcome.js";
import { normalizeAgentRunTerminalReceipt } from "../agent-run-terminal-receipt.js";
import type { EmbeddedAgentRunEntryTerminal } from "../embedded-agent-runner/run-entry.js";
import {
@@ -30,18 +27,6 @@ function resolveTerminalLogLevel(
return outcome.status === "timeout" ? "warn" : "error";
}
export function resolveAgentRunLifecycleEndLogLevel(meta: {
aborted?: unknown;
error?: unknown;
stopReason?: unknown;
livenessState?: unknown;
timeoutPhase?: unknown;
providerStarted?: unknown;
}): "info" | "warn" | "error" | undefined {
const outcome = buildAgentRunTerminalOutcomeFromLifecycleEvent({ phase: "end", data: meta });
return resolveTerminalLogLevel(outcome);
}
export function applyAgentRunAbortMetadata<T extends { meta: object }>(
result: T,
signal: AbortSignal | undefined,
+1 -1
View File
@@ -94,7 +94,7 @@ export function normalizeExplicitOverrideInput(raw: string, kind: "provider" | "
return trimmed;
}
export function resolveExplicitAgentCommandSessionKey(params: {
function resolveExplicitAgentCommandSessionKey(params: {
rawExplicitSessionKey?: string;
agentIdOverride?: string;
shouldScopeDefaultAgentKey?: boolean;
+4 -3
View File
@@ -12,6 +12,7 @@ import { executionIdentity } from "../agents/agent-command-execution-identity.js
import * as authProfileStoreModule from "../agents/auth-profiles/store.js";
import * as attemptExecutionRuntime from "../agents/command/attempt-execution.runtime.js";
import { deliverAgentCommandResult } from "../agents/command/delivery.runtime.js";
import { prepareAgentCommandExecution } from "../agents/command/prepare.js";
import { runEmbeddedAgent } from "../agents/embedded-agent.js";
import { loadManifestModelCatalog } from "../agents/model-catalog.js";
import * as modelSelectionModule from "../agents/model-selection.js";
@@ -46,7 +47,7 @@ import {
normalizeSessionDeliveryState,
} from "../utils/delivery-context.shared.js";
import { getAgentHarnessPluginMocks } from "./agent-command-state.test-mocks.js";
import { agentCommand, agentCommandFromIngress, testing as agentCommandTesting } from "./agent.js";
import { agentCommand, agentCommandFromIngress } from "./agent.js";
import { createThrowingTestRuntime } from "./test-runtime-config-helpers.js";
const configIoMocks = vi.hoisted(() => ({
@@ -1163,7 +1164,7 @@ describe("agentCommand", () => {
});
mockConfig(home, store, { models: {} });
const prepared = await agentCommandTesting.prepareAgentCommandExecution(
const prepared = await prepareAgentCommandExecution(
{
message: "prepare only",
sessionKey,
@@ -1210,7 +1211,7 @@ describe("agentCommand", () => {
});
cfg.messages = { visibleReplies: "automatic" };
const prepared = await agentCommandTesting.prepareAgentCommandExecution(
const prepared = await prepareAgentCommandExecution(
{
message: "child completed",
sessionKey,
+3 -6
View File
@@ -6,6 +6,7 @@ import { promisify } from "node:util";
import { withTempHome } from "openclaw/plugin-sdk/test-env";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import "./agent-command.test-mocks.js";
import { prepareAgentCommandExecution } from "../agents/command/prepare.js";
import { ensureAgentWorkspace } from "../agents/workspace.js";
import { getRegistryWorktree } from "../agents/worktrees/registry.js";
import { managedWorktrees } from "../agents/worktrees/service.js";
@@ -13,7 +14,6 @@ import { upsertSqliteSessionEntry } from "../config/sessions/session-accessor.sq
import { clearSessionStoreCacheForTest } from "../config/sessions/store-writer-state.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js";
import { testing as agentCommandTesting } from "./agent.js";
import { createThrowingTestRuntime } from "./test-runtime-config-helpers.js";
const configIoMocks = vi.hoisted(() => ({
@@ -132,7 +132,7 @@ describe("agent command worktree admission", () => {
return { dir: params?.dir ?? "" };
});
const preparing = agentCommandTesting.prepareAgentCommandExecution(
const preparing = prepareAgentCommandExecution(
{ message: "resume in worktree", sessionKey },
runtime,
);
@@ -178,10 +178,7 @@ describe("agent command worktree admission", () => {
let preparationResult: string;
try {
await agentCommandTesting.prepareAgentCommandExecution(
{ message: "resume in worktree", sessionKey },
runtime,
);
await prepareAgentCommandExecution({ message: "resume in worktree", sessionKey }, runtime);
preparationResult = "preparation proceeded without its checkout";
} catch (error) {
preparationResult = `preparation fails: ${(error as Error).message}`;