openskynet / src /cron /isolated-agent /run.test-harness.ts
Darochin's picture
Mirror OpenSkyNet workspace snapshot from Git HEAD
fc93158 verified
import { vi, type Mock } from "vitest";
type CronSessionEntry = {
sessionId: string;
updatedAt: number;
systemSent: boolean;
skillsSnapshot: unknown;
model?: string;
modelProvider?: string;
[key: string]: unknown;
};
type CronSession = {
storePath: string;
store: Record<string, unknown>;
sessionEntry: CronSessionEntry;
systemSent: boolean;
isNewSession: boolean;
[key: string]: unknown;
};
function createMock(): Mock {
return vi.fn();
}
export const buildWorkspaceSkillSnapshotMock = createMock();
export const resolveAgentConfigMock = createMock();
export const resolveAgentModelFallbacksOverrideMock = createMock();
export const resolveAgentSkillsFilterMock = createMock();
export const getModelRefStatusMock = createMock();
export const isCliProviderMock = createMock();
export const resolveAllowedModelRefMock = createMock();
export const resolveConfiguredModelRefMock = createMock();
export const resolveHooksGmailModelMock = createMock();
export const resolveThinkingDefaultMock = createMock();
export const runWithModelFallbackMock = createMock();
export const runEmbeddedPiAgentMock = createMock();
export const runCliAgentMock = createMock();
export const getCliSessionIdMock = createMock();
export const updateSessionStoreMock = createMock();
export const resolveCronSessionMock = createMock();
export const logWarnMock = createMock();
export const countActiveDescendantRunsMock = createMock();
export const listDescendantRunsForRequesterMock = createMock();
export const pickLastNonEmptyTextFromPayloadsMock = createMock();
export const resolveCronDeliveryPlanMock = createMock();
export const resolveDeliveryTargetMock = createMock();
vi.mock("../../agents/agent-scope.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/agent-scope.js")>();
return {
...actual,
resolveAgentConfig: resolveAgentConfigMock,
resolveAgentDir: vi.fn().mockReturnValue("/tmp/agent-dir"),
resolveAgentModelFallbacksOverride: resolveAgentModelFallbacksOverrideMock,
resolveAgentWorkspaceDir: vi.fn().mockReturnValue("/tmp/workspace"),
resolveDefaultAgentId: vi.fn().mockReturnValue("default"),
resolveAgentSkillsFilter: resolveAgentSkillsFilterMock,
};
});
vi.mock("../../agents/skills.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/skills.js")>();
return {
...actual,
buildWorkspaceSkillSnapshot: buildWorkspaceSkillSnapshotMock,
};
});
vi.mock("../../agents/skills/refresh.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/skills/refresh.js")>();
return {
...actual,
getSkillsSnapshotVersion: vi.fn().mockReturnValue(42),
};
});
vi.mock("../../agents/workspace.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/workspace.js")>();
return {
...actual,
DEFAULT_IDENTITY_FILENAME: "IDENTITY.md",
ensureAgentWorkspace: vi.fn().mockResolvedValue({ dir: "/tmp/workspace" }),
};
});
vi.mock("../../agents/model-catalog.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/model-catalog.js")>();
return {
...actual,
loadModelCatalog: vi.fn().mockResolvedValue({ models: [] }),
};
});
vi.mock("../../agents/model-selection.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/model-selection.js")>();
return {
...actual,
getModelRefStatus: getModelRefStatusMock,
isCliProvider: isCliProviderMock,
resolveAllowedModelRef: resolveAllowedModelRefMock,
resolveConfiguredModelRef: resolveConfiguredModelRefMock,
resolveHooksGmailModel: resolveHooksGmailModelMock,
resolveThinkingDefault: resolveThinkingDefaultMock,
};
});
vi.mock("../../agents/model-fallback.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/model-fallback.js")>();
return {
...actual,
runWithModelFallback: runWithModelFallbackMock,
};
});
vi.mock("../../agents/pi-embedded.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/pi-embedded.js")>();
return {
...actual,
runEmbeddedPiAgent: runEmbeddedPiAgentMock,
};
});
vi.mock("../../agents/context.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/context.js")>();
return {
...actual,
lookupContextTokens: vi.fn().mockReturnValue(128000),
};
});
vi.mock("../../agents/date-time.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/date-time.js")>();
return {
...actual,
formatUserTime: vi.fn().mockReturnValue("2026-02-10 12:00"),
resolveUserTimeFormat: vi.fn().mockReturnValue("24h"),
resolveUserTimezone: vi.fn().mockReturnValue("UTC"),
};
});
vi.mock("../../agents/timeout.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/timeout.js")>();
return {
...actual,
resolveAgentTimeoutMs: vi.fn().mockReturnValue(60_000),
};
});
vi.mock("../../agents/usage.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/usage.js")>();
return {
...actual,
deriveSessionTotalTokens: vi.fn().mockReturnValue(30),
hasNonzeroUsage: vi.fn().mockReturnValue(false),
};
});
vi.mock("../../agents/subagent-announce.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/subagent-announce.js")>();
return {
...actual,
runSubagentAnnounceFlow: vi.fn().mockResolvedValue(true),
};
});
vi.mock("../../agents/subagent-registry.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/subagent-registry.js")>();
return {
...actual,
countActiveDescendantRuns: countActiveDescendantRunsMock,
listDescendantRunsForRequester: listDescendantRunsForRequesterMock,
};
});
vi.mock("../../agents/cli-runner.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/cli-runner.js")>();
return {
...actual,
runCliAgent: runCliAgentMock,
};
});
vi.mock("../../agents/cli-session.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/cli-session.js")>();
return {
...actual,
getCliSessionId: getCliSessionIdMock,
setCliSessionId: vi.fn(),
};
});
vi.mock("../../auto-reply/thinking.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../auto-reply/thinking.js")>();
return {
...actual,
normalizeThinkLevel: vi.fn().mockReturnValue(undefined),
normalizeVerboseLevel: vi.fn().mockReturnValue("off"),
supportsXHighThinking: vi.fn().mockReturnValue(false),
};
});
vi.mock("../../cli/outbound-send-deps.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../cli/outbound-send-deps.js")>();
return {
...actual,
createOutboundSendDeps: vi.fn().mockReturnValue({}),
};
});
vi.mock("../../config/sessions.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../config/sessions.js")>();
return {
...actual,
resolveAgentMainSessionKey: vi.fn().mockReturnValue("main:default"),
resolveSessionTranscriptPath: vi.fn().mockReturnValue("/tmp/transcript.jsonl"),
setSessionRuntimeModel: vi.fn(),
updateSessionStore: updateSessionStoreMock,
};
});
vi.mock("../../routing/session-key.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../routing/session-key.js")>();
return {
...actual,
buildAgentMainSessionKey: vi.fn().mockReturnValue("agent:default:cron:test"),
normalizeAgentId: vi.fn((id: string) => id),
};
});
vi.mock("../../infra/agent-events.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../infra/agent-events.js")>();
return {
...actual,
registerAgentRunContext: vi.fn(),
};
});
vi.mock("../../infra/outbound/deliver.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../infra/outbound/deliver.js")>();
return {
...actual,
deliverOutboundPayloads: vi.fn().mockResolvedValue(undefined),
};
});
vi.mock("../../infra/skills-remote.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../infra/skills-remote.js")>();
return {
...actual,
getRemoteSkillEligibility: vi.fn().mockReturnValue({}),
};
});
vi.mock("../../logger.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../logger.js")>();
return {
...actual,
logWarn: (...args: unknown[]) => logWarnMock(...args),
};
});
vi.mock("../../security/external-content.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../security/external-content.js")>();
return {
...actual,
buildSafeExternalPrompt: vi.fn().mockReturnValue("safe prompt"),
detectSuspiciousPatterns: vi.fn().mockReturnValue([]),
getHookType: vi.fn().mockReturnValue("unknown"),
isExternalHookSession: vi.fn().mockReturnValue(false),
};
});
vi.mock("../delivery.js", () => ({
resolveCronDeliveryPlan: resolveCronDeliveryPlanMock,
}));
vi.mock("./delivery-target.js", () => ({
resolveDeliveryTarget: resolveDeliveryTargetMock,
}));
vi.mock("./helpers.js", () => ({
isHeartbeatOnlyResponse: vi.fn().mockReturnValue(false),
pickLastDeliverablePayload: vi.fn().mockReturnValue(undefined),
pickLastNonEmptyTextFromPayloads: pickLastNonEmptyTextFromPayloadsMock,
pickSummaryFromOutput: vi.fn().mockReturnValue("summary"),
pickSummaryFromPayloads: vi.fn().mockReturnValue("summary"),
resolveHeartbeatAckMaxChars: vi.fn().mockReturnValue(100),
}));
vi.mock("./session.js", () => ({
resolveCronSession: resolveCronSessionMock,
}));
vi.mock("../../agents/defaults.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../agents/defaults.js")>();
return {
...actual,
DEFAULT_CONTEXT_TOKENS: 128000,
DEFAULT_MODEL: "gpt-4",
DEFAULT_PROVIDER: "openai",
};
});
export function makeCronSessionEntry(overrides?: Record<string, unknown>): CronSessionEntry {
return {
sessionId: "test-session-id",
updatedAt: 0,
systemSent: false,
skillsSnapshot: undefined,
...overrides,
};
}
export function makeCronSession(overrides?: Record<string, unknown>): CronSession {
return {
storePath: "/tmp/store.json",
store: {},
sessionEntry: makeCronSessionEntry(),
systemSent: false,
isNewSession: true,
...overrides,
} as CronSession;
}
function makeDefaultModelFallbackResult() {
return {
result: {
payloads: [{ text: "test output" }],
meta: { agentMeta: { usage: { input: 10, output: 20 } } },
},
provider: "openai",
model: "gpt-4",
};
}
function makeDefaultEmbeddedResult() {
return {
payloads: [{ text: "test output" }],
meta: { agentMeta: { usage: { input: 10, output: 20 } } },
};
}
export function mockRunCronFallbackPassthrough(): void {
runWithModelFallbackMock.mockImplementation(async ({ provider, model, run }) => {
const result = await run(provider, model);
return { result, provider, model, attempts: [] };
});
}
export function resetRunCronIsolatedAgentTurnHarness(): void {
vi.clearAllMocks();
buildWorkspaceSkillSnapshotMock.mockReturnValue({
prompt: "<available_skills></available_skills>",
resolvedSkills: [],
version: 42,
});
resolveAgentConfigMock.mockReturnValue(undefined);
resolveAgentModelFallbacksOverrideMock.mockReturnValue(undefined);
resolveAgentSkillsFilterMock.mockReturnValue(undefined);
resolveConfiguredModelRefMock.mockReturnValue({ provider: "openai", model: "gpt-4" });
resolveAllowedModelRefMock.mockReturnValue({ ref: { provider: "openai", model: "gpt-4" } });
resolveHooksGmailModelMock.mockReturnValue(null);
resolveThinkingDefaultMock.mockReturnValue(undefined);
getModelRefStatusMock.mockReturnValue({ allowed: false });
isCliProviderMock.mockReturnValue(false);
runWithModelFallbackMock.mockReset();
runWithModelFallbackMock.mockResolvedValue(makeDefaultModelFallbackResult());
runEmbeddedPiAgentMock.mockReset();
runEmbeddedPiAgentMock.mockResolvedValue(makeDefaultEmbeddedResult());
runCliAgentMock.mockReset();
getCliSessionIdMock.mockReturnValue(undefined);
updateSessionStoreMock.mockReset();
updateSessionStoreMock.mockResolvedValue(undefined);
resolveCronSessionMock.mockReset();
resolveCronSessionMock.mockReturnValue(makeCronSession());
countActiveDescendantRunsMock.mockReset();
countActiveDescendantRunsMock.mockReturnValue(0);
listDescendantRunsForRequesterMock.mockReset();
listDescendantRunsForRequesterMock.mockReturnValue([]);
pickLastNonEmptyTextFromPayloadsMock.mockReset();
pickLastNonEmptyTextFromPayloadsMock.mockReturnValue("test output");
resolveCronDeliveryPlanMock.mockReset();
resolveCronDeliveryPlanMock.mockReturnValue({ requested: false, mode: "none" });
resolveDeliveryTargetMock.mockReset();
resolveDeliveryTargetMock.mockResolvedValue({
channel: "discord",
to: undefined,
accountId: undefined,
error: undefined,
});
logWarnMock.mockReset();
}
export function clearFastTestEnv(): string | undefined {
const previousFastTestEnv = process.env.OPENCLAW_TEST_FAST;
delete process.env.OPENCLAW_TEST_FAST;
return previousFastTestEnv;
}
export function restoreFastTestEnv(previousFastTestEnv: string | undefined): void {
if (previousFastTestEnv == null) {
delete process.env.OPENCLAW_TEST_FAST;
return;
}
process.env.OPENCLAW_TEST_FAST = previousFastTestEnv;
}
export async function loadRunCronIsolatedAgentTurn() {
const { runCronIsolatedAgentTurn } = await import("./run.js");
return runCronIsolatedAgentTurn;
}