mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor(deadcode): privatize runtime test seams (#108338)
* refactor(sessions): privatize runtime test seams * refactor(commitments): privatize extraction test seams * refactor(flows): privatize doctor health seams * refactor(tasks): privatize registry test seams * build(commitments): bundle Docker test support * chore(deadcode): shrink runtime export baseline
This commit is contained in:
committed by
GitHub
parent
8d5592548b
commit
3d76a4af92
@@ -85,10 +85,6 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
|
||||
"src/commands/sessions-tail.ts: setSessionsTailFollowIntervalMsForTests",
|
||||
"src/commands/sessions.ts: testing",
|
||||
"src/commands/status.command.ts: resolvePairingRecoveryContext",
|
||||
"src/commitments/extraction.ts: validateCommitmentCandidates",
|
||||
"src/commitments/runtime.ts: configureCommitmentExtractionRuntime",
|
||||
"src/commitments/runtime.ts: drainCommitmentExtractionQueue",
|
||||
"src/commitments/runtime.ts: resetCommitmentExtractionRuntimeForTests",
|
||||
"src/cron/isolated-agent/delivery-dispatch.ts: getCompletedDirectCronDeliveriesCountForTests",
|
||||
"src/cron/isolated-agent/delivery-dispatch.ts: resetCompletedDirectCronDeliveriesForTests",
|
||||
"src/cron/schedule.ts: clearCronScheduleCacheForTest",
|
||||
@@ -100,24 +96,7 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
|
||||
"src/cron/service/timer.ts: executeJobCore",
|
||||
"src/cron/service/timer.ts: onTimer",
|
||||
"src/cron/session-reaper.ts: resetReaperThrottle",
|
||||
"src/flows/doctor-health-contributions.ts: createDoctorHealthContribution",
|
||||
"src/flows/doctor-health-contributions.ts: resolveDoctorHealthContributions",
|
||||
"src/logging/redact-internal.ts: withFullContextToolPayloadRedaction",
|
||||
"src/sessions/session-lifecycle-admission.ts: runExclusiveSessionLifecycle",
|
||||
"src/sessions/session-upstream-monitor.ts: runSessionUpstreamMonitorTick",
|
||||
"src/sessions/user-turn-transcript.ts: persistUserTurnTranscript",
|
||||
"src/tasks/detached-task-runtime.ts: resetDetachedTaskLifecycleRuntimeForTests",
|
||||
"src/tasks/detached-task-runtime.ts: setDetachedTaskLifecycleRuntime",
|
||||
"src/tasks/generated-media-task-activity.ts: resetGeneratedMediaTaskActivityForTests",
|
||||
"src/tasks/task-flow-registry.store.ts: configureTaskFlowRegistryRuntime",
|
||||
"src/tasks/task-flow-registry.ts: createFlowRecord",
|
||||
"src/tasks/task-flow-registry.ts: resetTaskFlowRegistryForTests",
|
||||
"src/tasks/task-registry.ts: maybeDeliverTaskStateChangeUpdate",
|
||||
"src/tasks/task-registry.ts: resetTaskRegistryControlRuntimeForTests",
|
||||
"src/tasks/task-registry.ts: resetTaskRegistryDeliveryRuntimeForTests",
|
||||
"src/tasks/task-registry.ts: resetTaskRegistryForTests",
|
||||
"src/tasks/task-registry.ts: setTaskRegistryControlRuntimeForTests",
|
||||
"src/tasks/task-registry.ts: setTaskRegistryDeliveryRuntimeForTests",
|
||||
];
|
||||
|
||||
// Platform-variant findings. Allowed when present; never required.
|
||||
|
||||
@@ -4,12 +4,12 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { DatabaseSync } from "node:sqlite";
|
||||
import { enqueueCommitmentExtraction } from "../../dist/commitments/runtime.js";
|
||||
import {
|
||||
configureCommitmentExtractionRuntime,
|
||||
drainCommitmentExtractionQueue,
|
||||
enqueueCommitmentExtraction,
|
||||
resetCommitmentExtractionRuntimeForTests,
|
||||
} from "../../dist/commitments/runtime.js";
|
||||
} from "../../dist/commitments/runtime.test-support.js";
|
||||
import {
|
||||
listCommitments,
|
||||
listDueCommitmentsForSession,
|
||||
|
||||
@@ -23,6 +23,7 @@ set +e
|
||||
docker_e2e_run_with_harness \
|
||||
--name "$CONTAINER_NAME" \
|
||||
-e COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \
|
||||
-e OPENCLAW_COMMITMENTS_SAFETY_E2E=1 \
|
||||
"$IMAGE_NAME" \
|
||||
bash -lc 'set -euo pipefail; tsx scripts/e2e/commitments-safety-docker-client.ts' \
|
||||
>"$RUN_LOG" 2>&1
|
||||
|
||||
@@ -20,10 +20,8 @@ import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { createUserTurnTranscriptRecorder } from "../../sessions/user-turn-transcript.js";
|
||||
import { createTestUserTurnTranscriptTarget } from "../../sessions/user-turn-transcript.test-support.js";
|
||||
import { closeOpenClawAgentDatabasesForTest } from "../../state/openclaw-agent-db.js";
|
||||
import {
|
||||
registerGeneratedMediaTaskActivity,
|
||||
resetGeneratedMediaTaskActivityForTests,
|
||||
} from "../../tasks/generated-media-task-activity.js";
|
||||
import { registerGeneratedMediaTaskActivity } from "../../tasks/generated-media-task-activity.js";
|
||||
import { resetGeneratedMediaTaskActivityForTests } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { captureEnv, setTestEnvValue } from "../../test-utils/env.js";
|
||||
import { saveAuthProfileStore } from "../auth-profiles/store.js";
|
||||
import type { EmbeddedAgentRunResult } from "../embedded-agent.js";
|
||||
|
||||
@@ -8,14 +8,14 @@ import { enqueueCommandInLane, markGatewayDraining } from "../../process/command
|
||||
import * as commandQueueModule from "../../process/command-queue.js";
|
||||
import { resetCommandQueueStateForTest } from "../../process/command-queue.test-support.js";
|
||||
import { createQueuedTaskRun as createQueuedTaskRunOrNull } from "../../tasks/task-executor.js";
|
||||
import { getTaskFlowById, resetTaskFlowRegistryForTests } from "../../tasks/task-flow-registry.js";
|
||||
import { getTaskFlowById } from "../../tasks/task-flow-registry.js";
|
||||
import { getTaskById, listTasksForOwnerKey } from "../../tasks/task-registry.js";
|
||||
import type { TaskRecord } from "../../tasks/task-registry.types.js";
|
||||
import {
|
||||
getTaskById,
|
||||
listTasksForOwnerKey,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryForTests,
|
||||
setTaskRegistryDeliveryRuntimeForTests,
|
||||
} from "../../tasks/task-registry.js";
|
||||
import type { TaskRecord } from "../../tasks/task-registry.types.js";
|
||||
} from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { withStateDirEnv } from "../../test-helpers/state-dir-env.js";
|
||||
import { castAgentMessage } from "../test-helpers/agent-message-fixtures.js";
|
||||
import { resolveSessionLane } from "./lanes.js";
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
createRunningTaskRun,
|
||||
} from "../../../tasks/detached-task-runtime.js";
|
||||
import type { TaskRecord } from "../../../tasks/runtime-internal.js";
|
||||
import { resetTaskRegistryForTests } from "../../../tasks/task-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../../../tasks/task-runtime.test-helpers.js";
|
||||
import {
|
||||
requiresCompletionRequiredAsyncTaskWait,
|
||||
shouldWaitForCompletionRequiredAsyncTasks,
|
||||
|
||||
@@ -29,9 +29,9 @@ import type { Context, Model } from "../../../llm/types.js";
|
||||
import {
|
||||
createUserTurnTranscriptRecorder,
|
||||
mergePreparedUserTurnMessageForRuntime,
|
||||
persistUserTurnTranscript,
|
||||
type UserTurnInput,
|
||||
} from "../../../sessions/user-turn-transcript.js";
|
||||
import { persistUserTurnTranscript } from "../../../sessions/user-turn-transcript.test-support.js";
|
||||
import {
|
||||
OPENCLAW_RUNTIME_CONTEXT_CUSTOM_TYPE,
|
||||
relocateCurrentRuntimeContextCarrierToTail,
|
||||
|
||||
@@ -13,8 +13,11 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { setRuntimeConfigSnapshot } from "../config/config.js";
|
||||
import { callGateway } from "../gateway/call.js";
|
||||
import { createRunningTaskRun } from "../tasks/detached-task-runtime.js";
|
||||
import { resetTaskFlowRegistryForTests } from "../tasks/task-flow-registry.js";
|
||||
import { findTaskByRunId, resetTaskRegistryForTests } from "../tasks/task-registry.js";
|
||||
import { findTaskByRunId } from "../tasks/task-registry.js";
|
||||
import {
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../tasks/task-runtime.test-helpers.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { cleanupSessionStateForTest } from "../test-utils/session-state-cleanup.js";
|
||||
import { recoverOrphanedSubagentSessions } from "./subagent-orphan-recovery.js";
|
||||
|
||||
@@ -6,11 +6,11 @@ import path from "node:path";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { callGateway } from "../gateway/call.js";
|
||||
import { SUBAGENT_KILL_TASK_ERROR } from "../tasks/detached-task-runtime-contract.js";
|
||||
import { getDetachedTaskLifecycleRuntime } from "../tasks/detached-task-runtime.js";
|
||||
import {
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../tasks/detached-task-runtime.js";
|
||||
} from "../tasks/task-runtime.test-helpers.js";
|
||||
|
||||
const taskRuntimeMocks = vi.hoisted(() => ({
|
||||
finalizeTaskRunByRunId: vi.fn<(_params: unknown) => unknown[]>(() => [{}]),
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
import { expectDefined } from "@openclaw/normalization-core";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ContextEngine } from "../context-engine/types.js";
|
||||
import {
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../tasks/detached-task-runtime.js";
|
||||
import { getDetachedTaskLifecycleRuntime } from "../tasks/detached-task-runtime.js";
|
||||
import { setDetachedTaskLifecycleRuntime } from "../tasks/task-runtime.test-helpers.js";
|
||||
import { findTaskByRunIdForStatus } from "../tasks/task-status-access.js";
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
@@ -23,11 +23,13 @@ import {
|
||||
findDetachedTaskRun,
|
||||
finalizeTaskRunByRunId,
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../tasks/detached-task-runtime.js";
|
||||
import { resetTaskFlowRegistryForTests } from "../tasks/task-flow-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../tasks/task-registry.js";
|
||||
import {
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../tasks/task-runtime.test-helpers.js";
|
||||
import { findTaskByRunIdForStatus } from "../tasks/task-status-access.js";
|
||||
import {
|
||||
SUBAGENT_ENDED_REASON_COMPLETE,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// wake delivery, and direct media fallback behavior.
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { SessionEntry } from "../../config/sessions/types.js";
|
||||
import { resetGeneratedMediaTaskActivityForTests } from "../../tasks/generated-media-task-activity.js";
|
||||
import { resetGeneratedMediaTaskActivityForTests } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { hasPendingGeneratedMediaTaskForSessionKey } from "../../tasks/task-status-access.js";
|
||||
|
||||
const subagentAnnounceDeliveryMocks = vi.hoisted(() => ({
|
||||
|
||||
@@ -147,8 +147,8 @@ const { buildCommandTestParams } = await import("./commands-spawn.test-harness.j
|
||||
const { testing: acpManagerTesting } = await import("../../acp/control-plane/manager.js");
|
||||
const { testing: acpResetTargetTesting, resolveEffectiveResetTargetSessionKey } =
|
||||
await import("./acp-reset-target.js");
|
||||
const { createTaskRecord, resetTaskRegistryForTests } =
|
||||
await import("../../tasks/task-registry.js");
|
||||
const { createTaskRecord } = await import("../../tasks/task-registry.js");
|
||||
const { resetTaskRegistryForTests } = await import("../../tasks/task-runtime.test-helpers.js");
|
||||
const { configureTaskRegistryRuntime } = await import("../../tasks/task-registry.store.js");
|
||||
const { failTaskRunByRunId } = await import("../../tasks/task-executor.js");
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
createRunningTaskRun,
|
||||
failTaskRunByRunId,
|
||||
} from "../../tasks/task-executor.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { withEnvAsync } from "../../test-utils/env.js";
|
||||
import { buildStatusPluginsReply, buildStatusReply, buildStatusText } from "./commands-status.js";
|
||||
import {
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
import type { SubagentRunRecord } from "../../agents/subagent-registry.types.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { failTaskRunByRunId } from "../../tasks/task-executor.js";
|
||||
import { createTaskRecord, resetTaskRegistryForTests } from "../../tasks/task-registry.js";
|
||||
import { createTaskRecord } from "../../tasks/task-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import type { ReplyPayload } from "../types.js";
|
||||
import { handleSubagentsInfoAction } from "./commands-subagents/action-info.js";
|
||||
import {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
createRunningTaskRun,
|
||||
failTaskRunByRunId,
|
||||
} from "../../tasks/task-executor.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { handleTasksCommand } from "./commands-tasks.js";
|
||||
import {
|
||||
baseCommandTestConfig,
|
||||
|
||||
@@ -2,16 +2,14 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { createRunningTaskRun as createRunningTaskRunOrNull } from "../tasks/task-executor.js";
|
||||
import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "../tasks/task-flow-registry.js";
|
||||
import { createManagedTaskFlow as createManagedTaskFlowOrNull } from "../tasks/task-flow-registry.js";
|
||||
import type { TaskFlowRecord } from "../tasks/task-flow-registry.types.js";
|
||||
import type { TaskRecord } from "../tasks/task-registry.types.js";
|
||||
import {
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../tasks/task-registry.js";
|
||||
import type { TaskRecord } from "../tasks/task-registry.types.js";
|
||||
} from "../tasks/task-runtime.test-helpers.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
import { flowsCancelCommand, flowsListCommand, flowsShowCommand } from "./flows.js";
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
// Tasks JSON tests cover structured task command output and managed task flow state.
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "../tasks/task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "../tasks/task-flow-registry.store.js";
|
||||
import { createManagedTaskFlow as createManagedTaskFlowOrNull } from "../tasks/task-flow-registry.js";
|
||||
import type { TaskFlowRecord } from "../tasks/task-flow-registry.types.js";
|
||||
import { createTaskRecord as createTaskRecordOrNull } from "../tasks/task-registry.js";
|
||||
import type { TaskRecord } from "../tasks/task-registry.types.js";
|
||||
import {
|
||||
createTaskRecord as createTaskRecordOrNull,
|
||||
configureTaskFlowRegistryRuntime,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../tasks/task-registry.js";
|
||||
import type { TaskRecord } from "../tasks/task-registry.types.js";
|
||||
} from "../tasks/task-runtime.test-helpers.js";
|
||||
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
import { tasksAuditJsonCommand, tasksListJsonCommand } from "./tasks-json.js";
|
||||
|
||||
|
||||
@@ -7,22 +7,22 @@ import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import { saveCronStore } from "../cron/store.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { closeOpenClawAgentDatabasesForTest } from "../state/openclaw-agent-db.js";
|
||||
import { resetDetachedTaskLifecycleRuntimeForTests } from "../tasks/detached-task-runtime.js";
|
||||
import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "../tasks/task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "../tasks/task-flow-registry.store.js";
|
||||
import { createManagedTaskFlow as createManagedTaskFlowOrNull } from "../tasks/task-flow-registry.js";
|
||||
import type { TaskFlowRecord } from "../tasks/task-flow-registry.types.js";
|
||||
import {
|
||||
createTaskRecord as createTaskRecordOrNull,
|
||||
getTaskById,
|
||||
reloadTaskRegistryFromStore,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../tasks/task-registry.js";
|
||||
import * as taskRegistryMaintenance from "../tasks/task-registry.maintenance.js";
|
||||
import type { TaskRecord } from "../tasks/task-registry.types.js";
|
||||
import {
|
||||
configureTaskFlowRegistryRuntime,
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../tasks/task-runtime.test-helpers.js";
|
||||
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
import type { OpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
import type { TaskSystemAuditCode, TaskSystemAuditSeverity } from "./tasks-audit-system.js";
|
||||
|
||||
@@ -9,12 +9,12 @@ import {
|
||||
} from "../infra/heartbeat-runner.test-utils.js";
|
||||
import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js";
|
||||
import { withEnvAsync } from "../test-utils/env.js";
|
||||
import { enqueueCommitmentExtraction } from "./runtime.js";
|
||||
import {
|
||||
configureCommitmentExtractionRuntime,
|
||||
drainCommitmentExtractionQueue,
|
||||
enqueueCommitmentExtraction,
|
||||
resetCommitmentExtractionRuntimeForTests,
|
||||
} from "./runtime.js";
|
||||
} from "./runtime.test-support.js";
|
||||
import { readCommitmentsForTest } from "./store.test-utils.js";
|
||||
import type { CommitmentExtractionBatchResult, CommitmentExtractionItem } from "./types.js";
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import "./extraction.js";
|
||||
import type {
|
||||
CommitmentCandidate,
|
||||
CommitmentExtractionBatchResult,
|
||||
CommitmentExtractionItem,
|
||||
} from "./types.js";
|
||||
|
||||
type ValidatedCommitmentCandidate = {
|
||||
item: CommitmentExtractionItem;
|
||||
candidate: CommitmentCandidate;
|
||||
earliestMs: number;
|
||||
latestMs: number;
|
||||
timezone: string;
|
||||
};
|
||||
|
||||
type CommitmentExtractionTestApi = {
|
||||
validateCommitmentCandidates(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
items: CommitmentExtractionItem[];
|
||||
result: CommitmentExtractionBatchResult;
|
||||
nowMs?: number;
|
||||
}): ValidatedCommitmentCandidate[];
|
||||
};
|
||||
|
||||
function getTestApi(): CommitmentExtractionTestApi {
|
||||
const api = (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.commitmentExtractionTestApi")
|
||||
];
|
||||
if (!api) {
|
||||
throw new Error("commitment extraction test API is unavailable");
|
||||
}
|
||||
return api as CommitmentExtractionTestApi;
|
||||
}
|
||||
|
||||
export function validateCommitmentCandidates(
|
||||
params: Parameters<CommitmentExtractionTestApi["validateCommitmentCandidates"]>[0],
|
||||
): ValidatedCommitmentCandidate[] {
|
||||
return getTestApi().validateCommitmentCandidates(params);
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import {
|
||||
buildCommitmentExtractionPrompt,
|
||||
parseCommitmentExtractionOutput,
|
||||
persistCommitmentExtractionResult,
|
||||
validateCommitmentCandidates,
|
||||
} from "./extraction.js";
|
||||
import { validateCommitmentCandidates } from "./extraction.test-support.js";
|
||||
import { readCommitmentsForTest } from "./store.test-utils.js";
|
||||
import type { CommitmentCandidate, CommitmentExtractionItem } from "./types.js";
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ function resolveMinimumDueMs(params: {
|
||||
return params.nowMs + intervalMs;
|
||||
}
|
||||
|
||||
export function validateCommitmentCandidates(params: {
|
||||
function validateCommitmentCandidates(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
items: CommitmentExtractionItem[];
|
||||
result: CommitmentExtractionBatchResult;
|
||||
@@ -370,3 +370,8 @@ export async function persistCommitmentExtractionResult(params: {
|
||||
}
|
||||
return created;
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.commitmentExtractionTestApi")] =
|
||||
{ validateCommitmentCandidates };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import "./runtime.js";
|
||||
import type { CommitmentExtractionBatchResult, CommitmentExtractionItem } from "./types.js";
|
||||
|
||||
type TimerHandle = ReturnType<typeof setTimeout>;
|
||||
|
||||
type CommitmentExtractionRuntime = {
|
||||
extractBatch?: (params: {
|
||||
cfg?: OpenClawConfig;
|
||||
items: CommitmentExtractionItem[];
|
||||
}) => Promise<CommitmentExtractionBatchResult>;
|
||||
resolveDefaultModel?: (params: { cfg: OpenClawConfig; agentId?: string }) => {
|
||||
provider: string;
|
||||
model: string;
|
||||
};
|
||||
setTimer?: (callback: () => void, delayMs: number) => TimerHandle;
|
||||
clearTimer?: (timer: TimerHandle) => void;
|
||||
forceInTests?: boolean;
|
||||
};
|
||||
|
||||
type CommitmentRuntimeTestApi = {
|
||||
configureCommitmentExtractionRuntime(next: CommitmentExtractionRuntime): void;
|
||||
drainCommitmentExtractionQueue(): Promise<number>;
|
||||
resetCommitmentExtractionRuntimeForTests(): void;
|
||||
};
|
||||
|
||||
function getTestApi(): CommitmentRuntimeTestApi {
|
||||
const api = (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.commitmentRuntimeTestApi")
|
||||
];
|
||||
if (!api) {
|
||||
throw new Error("commitment runtime test API is unavailable");
|
||||
}
|
||||
return api as CommitmentRuntimeTestApi;
|
||||
}
|
||||
|
||||
export function configureCommitmentExtractionRuntime(next: CommitmentExtractionRuntime): void {
|
||||
getTestApi().configureCommitmentExtractionRuntime(next);
|
||||
}
|
||||
|
||||
export async function drainCommitmentExtractionQueue(): Promise<number> {
|
||||
return await getTestApi().drainCommitmentExtractionQueue();
|
||||
}
|
||||
|
||||
export function resetCommitmentExtractionRuntimeForTests(): void {
|
||||
getTestApi().resetCommitmentExtractionRuntimeForTests();
|
||||
}
|
||||
@@ -6,12 +6,12 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js";
|
||||
import { captureEnv, setTestEnvValue } from "../test-utils/env.js";
|
||||
import { enqueueCommitmentExtraction } from "./runtime.js";
|
||||
import {
|
||||
configureCommitmentExtractionRuntime,
|
||||
drainCommitmentExtractionQueue,
|
||||
enqueueCommitmentExtraction,
|
||||
resetCommitmentExtractionRuntimeForTests,
|
||||
} from "./runtime.js";
|
||||
} from "./runtime.test-support.js";
|
||||
import { readCommitmentsForTest, seedCommitmentsForTest } from "./store.test-utils.js";
|
||||
import type { CommitmentExtractionBatchResult, CommitmentExtractionItem } from "./types.js";
|
||||
|
||||
|
||||
@@ -91,12 +91,12 @@ function scheduleDrainSoon(debounceMs: number): void {
|
||||
}
|
||||
|
||||
/** Installs runtime hooks for extraction tests or alternate batch extraction. */
|
||||
export function configureCommitmentExtractionRuntime(next: CommitmentExtractionRuntime): void {
|
||||
function configureCommitmentExtractionRuntime(next: CommitmentExtractionRuntime): void {
|
||||
runtime = next;
|
||||
}
|
||||
|
||||
/** Clears queued work, timers, and injected hooks for isolated tests. */
|
||||
export function resetCommitmentExtractionRuntimeForTests(): void {
|
||||
function resetCommitmentExtractionRuntimeForTests(): void {
|
||||
if (timer) {
|
||||
clearTimer(timer);
|
||||
}
|
||||
@@ -299,7 +299,7 @@ function takeAgentBatch(
|
||||
}
|
||||
|
||||
/** Drains queued extraction work in batches and returns processed item count. */
|
||||
export async function drainCommitmentExtractionQueue(): Promise<number> {
|
||||
async function drainCommitmentExtractionQueue(): Promise<number> {
|
||||
if (draining) {
|
||||
return 0;
|
||||
}
|
||||
@@ -357,3 +357,15 @@ export async function drainCommitmentExtractionQueue(): Promise<number> {
|
||||
draining = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
process.env.VITEST ||
|
||||
process.env.NODE_ENV === "test" ||
|
||||
process.env.OPENCLAW_COMMITMENTS_SAFETY_E2E === "1"
|
||||
) {
|
||||
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.commitmentRuntimeTestApi")] = {
|
||||
configureCommitmentExtractionRuntime,
|
||||
drainCommitmentExtractionQueue,
|
||||
resetCommitmentExtractionRuntimeForTests,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,11 +4,8 @@ import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { runOpenClawStateWriteTransaction } from "../../state/openclaw-state-db.js";
|
||||
import * as taskExecutor from "../../tasks/task-executor.js";
|
||||
import {
|
||||
findTaskByRunId,
|
||||
listTaskRecordsUnsorted,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../../tasks/task-registry.js";
|
||||
import { findTaskByRunId, listTaskRecordsUnsorted } from "../../tasks/task-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { formatTaskStatusDetail } from "../../tasks/task-status.js";
|
||||
import { withEnvAsync } from "../../test-utils/env.js";
|
||||
import * as cronSchedule from "../schedule.js";
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../../tasks/detached-task-runtime.js";
|
||||
import { getDetachedTaskLifecycleRuntime } from "../../tasks/detached-task-runtime.js";
|
||||
import * as taskExecutor from "../../tasks/task-executor.js";
|
||||
import { finalizeTaskRunByRunId } from "../../tasks/task-executor.js";
|
||||
import * as taskRegistry from "../../tasks/task-registry.js";
|
||||
import { markTaskLostById, resetTaskRegistryForTests } from "../../tasks/task-registry.js";
|
||||
import { markTaskLostById } from "../../tasks/task-registry.js";
|
||||
import { listTaskRegistryRecordsByRuntimeSourceIdFromSqlite } from "../../tasks/task-registry.store.sqlite.js";
|
||||
import {
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { withOpenClawTestState } from "../../test-utils/openclaw-test-state.js";
|
||||
import { cronStoreKey } from "../store/key.js";
|
||||
import { readCronTaskRunHistoryPage } from "../task-run-history.js";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// computed in memory by applyJobResult.
|
||||
import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { withEnvAsync } from "../../test-utils/env.js";
|
||||
import { setupCronServiceSuite, writeCronStoreSnapshot } from "../service.test-harness.js";
|
||||
import { loadCronStore } from "../store.js";
|
||||
|
||||
@@ -13,13 +13,12 @@ import {
|
||||
import { HEARTBEAT_SKIP_LANES_BUSY, type HeartbeatRunResult } from "../../infra/heartbeat-wake.js";
|
||||
import { enqueueCommandInLane } from "../../process/command-queue.js";
|
||||
import { CommandLane } from "../../process/lanes.js";
|
||||
import { cancelTaskById, listTaskRecords } from "../../tasks/task-registry.js";
|
||||
import {
|
||||
cancelTaskById,
|
||||
listTaskRecords,
|
||||
resetTaskRegistryControlRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
setTaskRegistryControlRuntimeForTests,
|
||||
} from "../../tasks/task-registry.js";
|
||||
} from "../../tasks/task-runtime.test-helpers.js";
|
||||
import {
|
||||
advanceCronActiveJobGeneration,
|
||||
clearCronJobActive,
|
||||
|
||||
@@ -10,11 +10,8 @@ import { loadCronStore } from "../../cron/store.js";
|
||||
import { cronStoreKey } from "../../cron/store/key.js";
|
||||
import type { CronJob } from "../../cron/types.js";
|
||||
import * as taskExecutor from "../../tasks/task-executor.js";
|
||||
import {
|
||||
findTaskByRunId,
|
||||
listTaskRecordsUnsorted,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../../tasks/task-registry.js";
|
||||
import { findTaskByRunId, listTaskRecordsUnsorted } from "../../tasks/task-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { formatTaskStatusDetail } from "../../tasks/task-status.js";
|
||||
|
||||
const { logger, makeStorePath } = setupCronServiceSuite({
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { expectDefined } from "@openclaw/normalization-core";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { resetTaskRegistryForTests } from "../tasks/task-registry.js";
|
||||
import { saveTaskRegistryStateToSqlite } from "../tasks/task-registry.store.sqlite.js";
|
||||
import type { TaskRecord } from "../tasks/task-registry.types.js";
|
||||
import { resetTaskRegistryForTests } from "../tasks/task-runtime.test-helpers.js";
|
||||
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
import type { CronRunLogEntry } from "./run-log-types.js";
|
||||
import { CronService } from "./service.js";
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import type { DoctorHealthFlowContext } from "./doctor-health-contributions.js";
|
||||
import "./doctor-health-contributions.js";
|
||||
import type { HealthCheckInput, RunnableHealthCheck } from "./health-check-runner-types.js";
|
||||
import type { HealthCheck } from "./health-checks.js";
|
||||
import type { FlowContribution } from "./types.js";
|
||||
|
||||
type DoctorContributionHealthCheck =
|
||||
| (Omit<HealthCheck, "id" | "kind" | "source"> & {
|
||||
readonly id?: string;
|
||||
readonly kind?: "core";
|
||||
readonly source?: string;
|
||||
})
|
||||
| (Omit<RunnableHealthCheck, "id" | "kind" | "source"> & {
|
||||
readonly id?: string;
|
||||
readonly kind?: "core";
|
||||
readonly source?: string;
|
||||
});
|
||||
|
||||
type DoctorHealthContribution = FlowContribution & {
|
||||
kind: "core";
|
||||
surface: "health";
|
||||
healthChecks: readonly HealthCheckInput[];
|
||||
healthCheckIds: readonly string[];
|
||||
run: (ctx: DoctorHealthFlowContext) => Promise<void>;
|
||||
};
|
||||
|
||||
type DoctorHealthContributionTestApi = {
|
||||
createDoctorHealthContribution(params: {
|
||||
id: string;
|
||||
label: string;
|
||||
healthCheckIds?: readonly string[];
|
||||
healthChecks?: DoctorContributionHealthCheck | readonly DoctorContributionHealthCheck[];
|
||||
hint?: string;
|
||||
run?: (ctx: DoctorHealthFlowContext) => Promise<void>;
|
||||
}): DoctorHealthContribution;
|
||||
resolveDoctorHealthContributions(): DoctorHealthContribution[];
|
||||
};
|
||||
|
||||
function getTestApi(): DoctorHealthContributionTestApi {
|
||||
const api = (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.doctorHealthContributionsTestApi")
|
||||
];
|
||||
if (!api) {
|
||||
throw new Error("doctor health contributions test API is unavailable");
|
||||
}
|
||||
return api as DoctorHealthContributionTestApi;
|
||||
}
|
||||
|
||||
export function createDoctorHealthContribution(
|
||||
params: Parameters<DoctorHealthContributionTestApi["createDoctorHealthContribution"]>[0],
|
||||
): DoctorHealthContribution {
|
||||
return getTestApi().createDoctorHealthContribution(params);
|
||||
}
|
||||
|
||||
export function resolveDoctorHealthContributions(): DoctorHealthContribution[] {
|
||||
return getTestApi().resolveDoctorHealthContributions();
|
||||
}
|
||||
@@ -7,11 +7,11 @@ import type { DoctorPrompter } from "../commands/doctor-prompter.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { CORE_HEALTH_CHECKS } from "./doctor-core-checks.js";
|
||||
import "./doctor-tool-result-cap-advice.js";
|
||||
import { resolveDoctorContributionHealthChecks } from "./doctor-health-contributions.js";
|
||||
import {
|
||||
createDoctorHealthContribution,
|
||||
resolveDoctorContributionHealthChecks,
|
||||
resolveDoctorHealthContributions,
|
||||
} from "./doctor-health-contributions.js";
|
||||
} from "./doctor-health-contributions.test-support.js";
|
||||
import { runDoctorLintChecks } from "./doctor-lint-flow.js";
|
||||
import type { HealthCheck, HealthFinding } from "./health-checks.js";
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ function shouldSkipLegacyUpdateDoctorConfigWrite(params: { env: NodeJS.ProcessEn
|
||||
return true;
|
||||
}
|
||||
|
||||
export function createDoctorHealthContribution(params: {
|
||||
function createDoctorHealthContribution(params: {
|
||||
id: string;
|
||||
label: string;
|
||||
healthCheckIds?: readonly string[];
|
||||
@@ -1529,7 +1529,7 @@ async function runSkillWorkshopToolPolicyHealth(ctx: DoctorHealthFlowContext): P
|
||||
await runCoreHealthFindingNote(ctx, "core/doctor/skill-workshop-tool-policy");
|
||||
}
|
||||
|
||||
export function resolveDoctorHealthContributions(): DoctorHealthContribution[] {
|
||||
function resolveDoctorHealthContributions(): DoctorHealthContribution[] {
|
||||
return [
|
||||
createDoctorHealthContribution({
|
||||
id: "doctor:gateway-config",
|
||||
@@ -2282,4 +2282,10 @@ export async function runDoctorHealthContributions(ctx: DoctorHealthFlowContext)
|
||||
await contribution.run(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.doctorHealthContributionsTestApi")
|
||||
] = { createDoctorHealthContribution, resolveDoctorHealthContributions };
|
||||
}
|
||||
/* oxlint-disable max-lines -- TODO: split this grandfathered oversized file. */
|
||||
|
||||
@@ -13,11 +13,9 @@ import {
|
||||
resumeGatewaySuspend,
|
||||
} from "../../infra/gateway-suspend-coordinator.js";
|
||||
import { resetGatewayWorkAdmission } from "../../process/gateway-work-admission.js";
|
||||
import {
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../../tasks/detached-task-runtime.js";
|
||||
import { getDetachedTaskLifecycleRuntime } from "../../tasks/detached-task-runtime.js";
|
||||
import { findTaskByRunId } from "../../tasks/task-registry.js";
|
||||
import { setDetachedTaskLifecycleRuntime } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import {
|
||||
getAgentTestMocks,
|
||||
makeContext,
|
||||
|
||||
@@ -9,16 +9,16 @@ import {
|
||||
resetSubagentRegistryForTests,
|
||||
testing as subagentRegistryTesting,
|
||||
} from "../../agents/subagent-registry.test-helpers.js";
|
||||
import {
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../../tasks/detached-task-runtime.js";
|
||||
import { getDetachedTaskLifecycleRuntime } from "../../tasks/detached-task-runtime.js";
|
||||
import {
|
||||
findTaskByRunId,
|
||||
listTaskRecords,
|
||||
markTaskTerminalById,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../../tasks/task-registry.js";
|
||||
import {
|
||||
resetTaskRegistryForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { withTempDir } from "../../test-helpers/temp-dir.js";
|
||||
import {
|
||||
getAgentTestMocks,
|
||||
|
||||
@@ -12,8 +12,10 @@ import type { SessionEntry } from "../../config/sessions.js";
|
||||
import type { SessionTranscriptStats } from "../../config/sessions/session-accessor.js";
|
||||
import { parseSqliteSessionFileMarker } from "../../config/sessions/sqlite-marker.js";
|
||||
import { resetDiagnosticEventsForTest } from "../../infra/diagnostic-events.js";
|
||||
import { resetDetachedTaskLifecycleRuntimeForTests } from "../../tasks/detached-task-runtime.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-registry.js";
|
||||
import {
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { captureEnv, setTestEnvValue } from "../../test-utils/env.js";
|
||||
import { agentHandlers } from "./agent.js";
|
||||
import { suspendHandlers } from "./suspend.js";
|
||||
|
||||
@@ -13,14 +13,14 @@ import {
|
||||
markTaskTerminalById,
|
||||
recordTaskProgressByRunId,
|
||||
} from "../../tasks/runtime-internal.js";
|
||||
import { reloadTaskRegistryFromStore } from "../../tasks/task-registry.js";
|
||||
import { saveTaskRegistryStateToSqlite } from "../../tasks/task-registry.store.sqlite.js";
|
||||
import type { TaskRecord } from "../../tasks/task-registry.types.js";
|
||||
import {
|
||||
reloadTaskRegistryFromStore,
|
||||
resetTaskRegistryControlRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
setTaskRegistryControlRuntimeForTests,
|
||||
} from "../../tasks/task-registry.js";
|
||||
import { saveTaskRegistryStateToSqlite } from "../../tasks/task-registry.store.sqlite.js";
|
||||
import type { TaskRecord } from "../../tasks/task-registry.types.js";
|
||||
} from "../../tasks/task-runtime.test-helpers.js";
|
||||
import { captureEnv, setTestEnvValue } from "../../test-utils/env.js";
|
||||
import { tasksHandlers } from "./tasks.js";
|
||||
import type { RespondFn } from "./types.js";
|
||||
|
||||
@@ -11,8 +11,9 @@ import {
|
||||
emitSessionTranscriptUpdate,
|
||||
type InternalSessionTranscriptUpdate,
|
||||
} from "../sessions/transcript-events.js";
|
||||
import { createTaskRecord, resetTaskRegistryForTests } from "../tasks/task-registry.js";
|
||||
import { createTaskRecord } from "../tasks/task-registry.js";
|
||||
import { getTaskRegistryObservers } from "../tasks/task-registry.store.js";
|
||||
import { resetTaskRegistryForTests } from "../tasks/task-runtime.test-helpers.js";
|
||||
import { installInMemoryTaskRegistryRuntime } from "../test-utils/task-registry-runtime.js";
|
||||
import {
|
||||
createChatRunState,
|
||||
|
||||
@@ -16,9 +16,9 @@ import type { SessionAcpMeta } from "../config/sessions/types.js";
|
||||
import { enqueueSystemEvent, peekSystemEvents } from "../infra/system-events.js";
|
||||
import {
|
||||
beginSessionWorkAdmission,
|
||||
runExclusiveSessionLifecycle,
|
||||
runExclusiveSessionLifecycleMutation,
|
||||
} from "../sessions/session-lifecycle-admission.js";
|
||||
import { runExclusiveSessionLifecycle } from "../sessions/session-lifecycle-admission.test-support.js";
|
||||
import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js";
|
||||
import { embeddedRunMock, testState, writeSessionStore } from "./test-helpers.js";
|
||||
import {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
closeOpenClawStateDatabaseForTest,
|
||||
openOpenClawStateDatabase,
|
||||
} from "../state/openclaw-state-db.js";
|
||||
import { resetTaskRegistryForTests } from "../tasks/task-registry.js";
|
||||
import { resetTaskRegistryForTests } from "../tasks/task-runtime.test-helpers.js";
|
||||
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
|
||||
const CRON_RUN_LOG_TASK_IMPORT_MIGRATION_ID = "state:cron-run-logs-to-task-runs:v1";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Runtime task test harness helpers build mocked plugin runtimes for task-flow tests.
|
||||
import { vi } from "vitest";
|
||||
import { resetDetachedTaskLifecycleRuntimeForTests } from "../../tasks/detached-task-runtime.js";
|
||||
import {
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryControlRuntimeForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Runtime task tests cover plugin task runtime registration, invocation, and cleanup.
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "../../tasks/detached-task-runtime.js";
|
||||
import { getDetachedTaskLifecycleRuntime } from "../../tasks/detached-task-runtime.js";
|
||||
import { setDetachedTaskLifecycleRuntime } from "../../tasks/task-runtime.test-helpers.js";
|
||||
import {
|
||||
getRuntimeTaskMocks,
|
||||
installRuntimeTaskDeliveryMock,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import "./session-lifecycle-admission.js";
|
||||
|
||||
type RunExclusiveSessionLifecycleParams<T> = {
|
||||
scope: string;
|
||||
identities: Iterable<string | undefined>;
|
||||
signal?: AbortSignal;
|
||||
run: () => Promise<T>;
|
||||
};
|
||||
|
||||
type SessionLifecycleAdmissionTestApi = {
|
||||
runExclusiveSessionLifecycle<T>(params: RunExclusiveSessionLifecycleParams<T>): Promise<T>;
|
||||
};
|
||||
|
||||
function getTestApi(): SessionLifecycleAdmissionTestApi {
|
||||
return (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.sessionLifecycleAdmissionTestApi")
|
||||
] as SessionLifecycleAdmissionTestApi;
|
||||
}
|
||||
|
||||
export async function runExclusiveSessionLifecycle<T>(
|
||||
params: RunExclusiveSessionLifecycleParams<T>,
|
||||
): Promise<T> {
|
||||
return await getTestApi().runExclusiveSessionLifecycle(params);
|
||||
}
|
||||
@@ -168,7 +168,7 @@ async function waitForNormalizedSessionLifecycleMutationIdle(
|
||||
}
|
||||
}
|
||||
|
||||
export async function runExclusiveSessionLifecycle<T>(params: {
|
||||
async function runExclusiveSessionLifecycle<T>(params: {
|
||||
scope: string;
|
||||
identities: Iterable<string | undefined>;
|
||||
signal?: AbortSignal;
|
||||
@@ -524,3 +524,9 @@ export async function interruptSessionWorkAdmissions(params: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.sessionLifecycleAdmissionTestApi")
|
||||
] = { runExclusiveSessionLifecycle };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { isEmbeddedAgentRunActive } from "../agents/embedded-agent.js";
|
||||
import type { loadSessionEntry } from "../config/sessions/session-accessor.js";
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import type { SessionCatalogProvider, SessionUpstreamProbe } from "../plugins/session-catalog.js";
|
||||
import type { OpenClawStateDatabaseOptions } from "../state/openclaw-state-db.js";
|
||||
import "./session-upstream-monitor.js";
|
||||
|
||||
type SessionUpstreamMonitorOptions = OpenClawStateDatabaseOptions & {
|
||||
providers?: readonly SessionCatalogProvider[];
|
||||
now?: () => number;
|
||||
loadEntry?: typeof loadSessionEntry;
|
||||
isRunActive?: typeof isEmbeddedAgentRunActive;
|
||||
loadOwnRecentUserTexts?: (params: {
|
||||
entry: SessionEntry;
|
||||
probe: Omit<SessionUpstreamProbe, "ownRecentUserTexts">;
|
||||
}) => Promise<string[]>;
|
||||
};
|
||||
|
||||
type SessionUpstreamMissingCounter = {
|
||||
count: number;
|
||||
linkUpdatedAt: number;
|
||||
};
|
||||
|
||||
type SessionUpstreamMonitorTestApi = {
|
||||
runSessionUpstreamMonitorTick(
|
||||
options?: SessionUpstreamMonitorOptions,
|
||||
missingCounts?: Map<string, SessionUpstreamMissingCounter>,
|
||||
): Promise<void>;
|
||||
};
|
||||
|
||||
function getTestApi(): SessionUpstreamMonitorTestApi {
|
||||
return (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.sessionUpstreamMonitorTestApi")
|
||||
] as SessionUpstreamMonitorTestApi;
|
||||
}
|
||||
|
||||
export async function runSessionUpstreamMonitorTick(
|
||||
options: SessionUpstreamMonitorOptions = {},
|
||||
missingCounts: Map<string, SessionUpstreamMissingCounter> = new Map(),
|
||||
): Promise<void> {
|
||||
await getTestApi().runSessionUpstreamMonitorTick(options, missingCounts);
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
readSessionUpstreamLink,
|
||||
upsertSessionUpstreamLink,
|
||||
} from "./session-upstream-links.js";
|
||||
import { runSessionUpstreamMonitorTick } from "./session-upstream-monitor.js";
|
||||
import { runSessionUpstreamMonitorTick } from "./session-upstream-monitor.test-support.js";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
const watcherSessionKey = "agent:main:main";
|
||||
|
||||
@@ -131,7 +131,7 @@ async function probeProvenanceUnchanged(
|
||||
);
|
||||
}
|
||||
|
||||
export async function runSessionUpstreamMonitorTick(
|
||||
async function runSessionUpstreamMonitorTick(
|
||||
options: SessionUpstreamMonitorOptions = {},
|
||||
missingCounts: Map<string, SessionUpstreamMissingCounter> = new Map(),
|
||||
): Promise<void> {
|
||||
@@ -374,3 +374,9 @@ export function startSessionUpstreamMonitor(
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.sessionUpstreamMonitorTestApi")
|
||||
] = { runSessionUpstreamMonitorTick };
|
||||
}
|
||||
|
||||
@@ -1,4 +1,27 @@
|
||||
import type { UserTurnTranscriptTarget } from "./user-turn-transcript.types.js";
|
||||
import "./user-turn-transcript.js";
|
||||
import type {
|
||||
PersistUserTurnTranscriptParams,
|
||||
UserTurnTranscriptPersistResult,
|
||||
UserTurnTranscriptTarget,
|
||||
} from "./user-turn-transcript.types.js";
|
||||
|
||||
type UserTurnTranscriptTestApi = {
|
||||
persistUserTurnTranscript(
|
||||
params: PersistUserTurnTranscriptParams,
|
||||
): Promise<UserTurnTranscriptPersistResult | undefined>;
|
||||
};
|
||||
|
||||
function getTestApi(): UserTurnTranscriptTestApi {
|
||||
return (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.userTurnTranscriptTestApi")
|
||||
] as UserTurnTranscriptTestApi;
|
||||
}
|
||||
|
||||
export async function persistUserTurnTranscript(
|
||||
params: PersistUserTurnTranscriptParams,
|
||||
): Promise<UserTurnTranscriptPersistResult | undefined> {
|
||||
return await getTestApi().persistUserTurnTranscript(params);
|
||||
}
|
||||
|
||||
/** Creates a store-backed transcript target for tests that do not own runtime session setup. */
|
||||
export function createTestUserTurnTranscriptTarget(
|
||||
|
||||
@@ -16,10 +16,10 @@ import {
|
||||
buildPersistedUserTurnMediaInputsFromFields,
|
||||
createUserTurnTranscriptRecorder,
|
||||
mergePreparedUserTurnMessageForRuntime,
|
||||
persistUserTurnTranscript,
|
||||
resolvePersistedUserTurnText,
|
||||
type UserTurnInput,
|
||||
} from "./user-turn-transcript.js";
|
||||
import { persistUserTurnTranscript } from "./user-turn-transcript.test-support.js";
|
||||
|
||||
describe("user turn transcript persistence", () => {
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
@@ -411,7 +411,7 @@ export function preparePersistedUserTurnMessageForTranscriptWrite(
|
||||
|
||||
// Store-backed persistence resolves the current session transcript file lazily
|
||||
// so callers can pass a session entry/store without knowing the final path.
|
||||
export async function persistUserTurnTranscript(
|
||||
async function persistUserTurnTranscript(
|
||||
params: PersistUserTurnTranscriptParams,
|
||||
): Promise<UserTurnTranscriptPersistResult | undefined> {
|
||||
const message = resolvePersistedUserTurnMessage(params);
|
||||
@@ -710,3 +710,9 @@ export function createUserTurnTranscriptRecorder(
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.userTurnTranscriptTestApi")] = {
|
||||
persistUserTurnTranscript,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { DetachedTaskLifecycleRuntime } from "./detached-task-runtime-contract.js";
|
||||
import {
|
||||
clearDetachedTaskLifecycleRuntimeRegistration,
|
||||
registerDetachedTaskLifecycleRuntime,
|
||||
} from "./detached-task-runtime-state.js";
|
||||
|
||||
export function setDetachedTaskLifecycleRuntime(runtime: DetachedTaskLifecycleRuntime): void {
|
||||
registerDetachedTaskLifecycleRuntime("__test__", runtime);
|
||||
}
|
||||
|
||||
export function resetDetachedTaskLifecycleRuntimeForTests(): void {
|
||||
clearDetachedTaskLifecycleRuntimeRegistration();
|
||||
}
|
||||
@@ -13,13 +13,15 @@ import {
|
||||
finalizeTaskRunByRunId,
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
recordTaskRunProgressByRunId,
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
setDetachedTaskDeliveryStatusByRunId,
|
||||
startTaskRunByRunId,
|
||||
tryRecoverTaskBeforeMarkLost,
|
||||
} from "./detached-task-runtime.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
import {
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
const { mockFindTaskByRunIdForStatus, mockListTasksForSessionKeyForStatus, mockLogWarn } =
|
||||
vi.hoisted(() => ({
|
||||
|
||||
@@ -8,11 +8,7 @@ import type {
|
||||
DetachedTaskFinalizeParams,
|
||||
DetachedTaskLifecycleRuntime,
|
||||
} from "./detached-task-runtime-contract.js";
|
||||
import {
|
||||
clearDetachedTaskLifecycleRuntimeRegistration,
|
||||
getRegisteredDetachedTaskLifecycleRuntime,
|
||||
registerDetachedTaskLifecycleRuntime,
|
||||
} from "./detached-task-runtime-state.js";
|
||||
import { getRegisteredDetachedTaskLifecycleRuntime } from "./detached-task-runtime-state.js";
|
||||
import { cancelTaskById as cancelDetachedTaskRunByIdInCore } from "./runtime-internal.js";
|
||||
import {
|
||||
completeTaskRunByRunId as completeTaskRunByRunIdFromExecutor,
|
||||
@@ -74,14 +70,6 @@ export function getDetachedTaskLifecycleRuntime(): DetachedTaskLifecycleRuntime
|
||||
return getRegisteredDetachedTaskLifecycleRuntime() ?? DEFAULT_DETACHED_TASK_LIFECYCLE_RUNTIME;
|
||||
}
|
||||
|
||||
export function setDetachedTaskLifecycleRuntime(runtime: DetachedTaskLifecycleRuntime): void {
|
||||
registerDetachedTaskLifecycleRuntime("__test__", runtime);
|
||||
}
|
||||
|
||||
export function resetDetachedTaskLifecycleRuntimeForTests(): void {
|
||||
clearDetachedTaskLifecycleRuntimeRegistration();
|
||||
}
|
||||
|
||||
export function createQueuedTaskRun(
|
||||
...args: Parameters<DetachedTaskLifecycleRuntime["createQueuedTaskRun"]>
|
||||
): ReturnType<DetachedTaskLifecycleRuntime["createQueuedTaskRun"]> {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import "./generated-media-task-activity.js";
|
||||
|
||||
type GeneratedMediaTaskActivityTestApi = {
|
||||
resetGeneratedMediaTaskActivityForTests(): void;
|
||||
};
|
||||
|
||||
function getTestApi(): GeneratedMediaTaskActivityTestApi {
|
||||
const api = (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.generatedMediaTaskActivityTestApi")
|
||||
];
|
||||
if (!api) {
|
||||
throw new Error("generated media task activity test API is unavailable");
|
||||
}
|
||||
return api as GeneratedMediaTaskActivityTestApi;
|
||||
}
|
||||
|
||||
export function resetGeneratedMediaTaskActivityForTests(): void {
|
||||
getTestApi().resetGeneratedMediaTaskActivityForTests();
|
||||
}
|
||||
@@ -54,7 +54,13 @@ export function getLatestGeneratedMediaTaskAdmissionIdForSessionKey(
|
||||
return getLatestGeneratedMediaTaskAdmissions().get(sessionKey);
|
||||
}
|
||||
|
||||
export function resetGeneratedMediaTaskActivityForTests(): void {
|
||||
function resetGeneratedMediaTaskActivityForTests(): void {
|
||||
getActiveGeneratedMediaTasks().clear();
|
||||
getLatestGeneratedMediaTaskAdmissions().clear();
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.generatedMediaTaskActivityTestApi")
|
||||
] = { resetGeneratedMediaTaskActivityForTests };
|
||||
}
|
||||
|
||||
@@ -5,11 +5,7 @@ import { resetSystemEventsForTest } from "../infra/system-events.js";
|
||||
import { withStateDirEnv } from "../test-helpers/state-dir-env.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { SUBAGENT_KILL_TASK_ERROR } from "./detached-task-runtime-contract.js";
|
||||
import {
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "./detached-task-runtime.js";
|
||||
import { getDetachedTaskLifecycleRuntime } from "./detached-task-runtime.js";
|
||||
import {
|
||||
cancelFlowById,
|
||||
cancelFlowByIdForOwner,
|
||||
@@ -27,22 +23,26 @@ import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
getTaskFlowById,
|
||||
listTaskFlowRecords,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "./task-flow-registry.store.js";
|
||||
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
|
||||
import {
|
||||
setTaskRegistryDeliveryRuntimeForTests,
|
||||
getTaskById,
|
||||
findTaskByRunId,
|
||||
listTasksForFlowId,
|
||||
markTaskTerminalById,
|
||||
} from "./task-registry.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
import {
|
||||
configureTaskFlowRegistryRuntime,
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
resetTaskRegistryControlRuntimeForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
resetTaskFlowRegistryForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
setTaskRegistryControlRuntimeForTests,
|
||||
} from "./task-registry.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
setTaskRegistryDeliveryRuntimeForTests,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
const ORIGINAL_ENV = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ import {
|
||||
listTaskFlowsForOwner,
|
||||
resolveTaskFlowForLookupTokenForOwner,
|
||||
} from "./task-flow-owner-access.js";
|
||||
import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "./task-flow-registry.store.js";
|
||||
import { createManagedTaskFlow as createManagedTaskFlowOrNull } from "./task-flow-registry.js";
|
||||
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
|
||||
import {
|
||||
configureTaskFlowRegistryRuntime,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
function createManagedTaskFlow(
|
||||
params: Parameters<typeof createManagedTaskFlowOrNull>[0],
|
||||
|
||||
@@ -15,16 +15,16 @@ import {
|
||||
import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
requestFlowCancel,
|
||||
resetTaskFlowRegistryForTests,
|
||||
setFlowWaiting,
|
||||
} from "./task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "./task-flow-registry.store.js";
|
||||
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
import {
|
||||
configureTaskFlowRegistryRuntime,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "./task-registry.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
const ORIGINAL_ENV = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
|
||||
|
||||
@@ -5,12 +5,10 @@ import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
import { SUBAGENT_KILL_TASK_ERROR } from "./detached-task-runtime-contract.js";
|
||||
import { createRunningTaskRun as createRunningTaskRunOrNull } from "./task-executor.js";
|
||||
import {
|
||||
createFlowRecord as createFlowRecordOrNull,
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
getTaskFlowById,
|
||||
listTaskFlowRecords,
|
||||
requestFlowCancel,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-flow-registry.js";
|
||||
import {
|
||||
getInspectableTaskFlowAuditSummary,
|
||||
@@ -18,12 +16,14 @@ import {
|
||||
runTaskFlowRegistryMaintenance,
|
||||
} from "./task-flow-registry.maintenance.js";
|
||||
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
|
||||
import { finalizeTaskRunByRunId } from "./task-registry.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
import {
|
||||
finalizeTaskRunByRunId,
|
||||
createFlowRecord as createFlowRecordOrNull,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "./task-registry.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
const ORIGINAL_ENV = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { TaskFlowRegistryObserverEvent } from "./task-flow-registry.store.js";
|
||||
import type { TaskFlowRegistryStoreSnapshot } from "./task-flow-registry.store.types.js";
|
||||
import "./task-flow-registry.store.js";
|
||||
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
|
||||
|
||||
type TaskFlowRegistryStore = {
|
||||
loadSnapshot: () => TaskFlowRegistryStoreSnapshot;
|
||||
saveSnapshot: (snapshot: TaskFlowRegistryStoreSnapshot) => void;
|
||||
upsertFlow?: (flow: TaskFlowRecord) => void;
|
||||
deleteFlow?: (flowId: string) => void;
|
||||
close?: () => void;
|
||||
};
|
||||
|
||||
type TaskFlowRegistryStoreTestApi = {
|
||||
configureTaskFlowRegistryRuntime(params: {
|
||||
store?: TaskFlowRegistryStore;
|
||||
observers?: { onEvent?: (event: TaskFlowRegistryObserverEvent) => void } | null;
|
||||
}): void;
|
||||
};
|
||||
|
||||
function getTestApi(): TaskFlowRegistryStoreTestApi {
|
||||
const api = (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.taskFlowRegistryStoreTestApi")
|
||||
];
|
||||
if (!api) {
|
||||
throw new Error("task flow registry store test API is unavailable");
|
||||
}
|
||||
return api as TaskFlowRegistryStoreTestApi;
|
||||
}
|
||||
|
||||
export function configureTaskFlowRegistryRuntime(
|
||||
params: Parameters<TaskFlowRegistryStoreTestApi["configureTaskFlowRegistryRuntime"]>[0],
|
||||
): void {
|
||||
getTestApi().configureTaskFlowRegistryRuntime(params);
|
||||
}
|
||||
@@ -11,10 +11,8 @@ import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
getTaskFlowById,
|
||||
requestFlowCancel,
|
||||
resetTaskFlowRegistryForTests,
|
||||
setFlowWaiting,
|
||||
} from "./task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "./task-flow-registry.store.js";
|
||||
import {
|
||||
loadTaskFlowRegistryStateFromSqlite,
|
||||
saveTaskFlowRegistryStateToSqlite,
|
||||
@@ -25,6 +23,10 @@ import {
|
||||
type TaskFlowRecord,
|
||||
} from "./task-flow-registry.types.js";
|
||||
import { parseTaskNotifyPolicy } from "./task-registry.types.js";
|
||||
import {
|
||||
configureTaskFlowRegistryRuntime,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
function createManagedTaskFlow(
|
||||
params: Parameters<typeof createManagedTaskFlowOrNull>[0],
|
||||
|
||||
@@ -57,7 +57,7 @@ export function getTaskFlowRegistryObservers(): TaskFlowRegistryObservers | null
|
||||
return configuredFlowRegistryObservers;
|
||||
}
|
||||
|
||||
export function configureTaskFlowRegistryRuntime(params: {
|
||||
function configureTaskFlowRegistryRuntime(params: {
|
||||
store?: TaskFlowRegistryStore;
|
||||
observers?: TaskFlowRegistryObservers | null;
|
||||
}) {
|
||||
@@ -74,3 +74,9 @@ export function resetTaskFlowRegistryRuntimeForTests() {
|
||||
configuredFlowRegistryStore = defaultFlowRegistryStore;
|
||||
configuredFlowRegistryObservers = null;
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.taskFlowRegistryStoreTestApi")
|
||||
] = { configureTaskFlowRegistryRuntime };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import type {
|
||||
JsonValue,
|
||||
TaskFlowRecord,
|
||||
TaskFlowStatus,
|
||||
TaskFlowSyncMode,
|
||||
} from "./task-flow-registry.types.js";
|
||||
import "./task-flow-registry.js";
|
||||
import type { TaskNotifyPolicy } from "./task-registry.types.js";
|
||||
|
||||
type CreateFlowRecordParams = {
|
||||
ownerKey: string;
|
||||
requesterOrigin?: TaskFlowRecord["requesterOrigin"];
|
||||
status?: TaskFlowStatus;
|
||||
notifyPolicy?: TaskNotifyPolicy;
|
||||
goal: string;
|
||||
currentStep?: string | null;
|
||||
blockedTaskId?: string | null;
|
||||
blockedSummary?: string | null;
|
||||
stateJson?: JsonValue | null;
|
||||
waitJson?: JsonValue | null;
|
||||
cancelRequestedAt?: number | null;
|
||||
createdAt?: number;
|
||||
updatedAt?: number;
|
||||
endedAt?: number | null;
|
||||
syncMode?: TaskFlowSyncMode;
|
||||
controllerId?: string | null;
|
||||
revision?: number;
|
||||
};
|
||||
|
||||
type TaskFlowRegistryTestApi = {
|
||||
createFlowRecord(params: CreateFlowRecordParams): TaskFlowRecord | null;
|
||||
resetTaskFlowRegistryForTests(opts?: { persist?: boolean }): void;
|
||||
};
|
||||
|
||||
function getTestApi(): TaskFlowRegistryTestApi {
|
||||
const api = (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.taskFlowRegistryTestApi")
|
||||
];
|
||||
if (!api) {
|
||||
throw new Error("task flow registry test API is unavailable");
|
||||
}
|
||||
return api as TaskFlowRegistryTestApi;
|
||||
}
|
||||
|
||||
export function createFlowRecord(params: CreateFlowRecordParams): TaskFlowRecord | null {
|
||||
return getTestApi().createFlowRecord(params);
|
||||
}
|
||||
|
||||
export function resetTaskFlowRegistryForTests(opts?: { persist?: boolean }): void {
|
||||
getTestApi().resetTaskFlowRegistryForTests(opts);
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
import {
|
||||
createFlowRecord as createFlowRecordOrNull,
|
||||
createTaskFlowForTask as createTaskFlowForTaskOrNull,
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
deleteTaskFlowRecordById,
|
||||
@@ -12,14 +11,17 @@ import {
|
||||
listTaskFlowRecords,
|
||||
requestFlowCancel,
|
||||
reloadTaskFlowRegistryFromStore,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resumeFlow,
|
||||
setFlowWaiting,
|
||||
syncFlowFromTaskResult,
|
||||
updateFlowRecordByIdExpectedRevision,
|
||||
} from "./task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "./task-flow-registry.store.js";
|
||||
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
|
||||
import {
|
||||
configureTaskFlowRegistryRuntime,
|
||||
createFlowRecord as createFlowRecordOrNull,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
function createFlowRecord(params: Parameters<typeof createFlowRecordOrNull>[0]): TaskFlowRecord {
|
||||
const flow = createFlowRecordOrNull(params);
|
||||
|
||||
@@ -468,7 +468,7 @@ function writeFlowRecord(next: TaskFlowRecord, previous?: TaskFlowRecord): TaskF
|
||||
return cloneFlowRecord(next);
|
||||
}
|
||||
|
||||
export function createFlowRecord(params: CreateFlowRecordParams): TaskFlowRecord | null {
|
||||
function createFlowRecord(params: CreateFlowRecordParams): TaskFlowRecord | null {
|
||||
ensureTaskFlowRegistryReady();
|
||||
const record = buildFlowRecord(params);
|
||||
return writeFlowRecord(record);
|
||||
@@ -812,7 +812,7 @@ export function deleteTaskFlowRecordById(flowId: string): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function resetTaskFlowRegistryForTests(opts?: { persist?: boolean }) {
|
||||
function resetTaskFlowRegistryForTests(opts?: { persist?: boolean }) {
|
||||
flows = new Map();
|
||||
taskFlowRegistryRestoreState = { status: "uninitialized" };
|
||||
resetTaskFlowRegistryRuntimeForTests();
|
||||
@@ -821,4 +821,11 @@ export function resetTaskFlowRegistryForTests(opts?: { persist?: boolean }) {
|
||||
}
|
||||
getTaskFlowRegistryStore().close?.();
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.taskFlowRegistryTestApi")] = {
|
||||
createFlowRecord,
|
||||
resetTaskFlowRegistryForTests,
|
||||
};
|
||||
}
|
||||
/* oxlint-disable max-lines -- TODO: split this grandfathered oversized file. */
|
||||
|
||||
@@ -8,11 +8,9 @@ import {
|
||||
getTaskByIdForOwner,
|
||||
resolveTaskForLookupTokenForOwner,
|
||||
} from "./task-owner-access.js";
|
||||
import {
|
||||
createTaskRecord as createTaskRecordOrNull,
|
||||
resetTaskRegistryForTests,
|
||||
} from "./task-registry.js";
|
||||
import { createTaskRecord as createTaskRecordOrNull } from "./task-registry.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
import { resetTaskRegistryForTests } from "./task-runtime.test-helpers.js";
|
||||
|
||||
const ORIGINAL_ENV = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
|
||||
|
||||
@@ -3,11 +3,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { AcpSessionStoreEntry } from "../acp/runtime/session-meta.js";
|
||||
import type { SessionEntry } from "../config/sessions.js";
|
||||
import type { ParsedAgentSessionKey } from "../routing/session-key.js";
|
||||
import {
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
getDetachedTaskLifecycleRuntime,
|
||||
} from "./detached-task-runtime.js";
|
||||
import { getDetachedTaskLifecycleRuntime } from "./detached-task-runtime.js";
|
||||
import {
|
||||
CRON_HISTORY_KEEP_PER_JOB,
|
||||
getInspectableActiveTaskRestartBlockers,
|
||||
@@ -20,6 +16,10 @@ import {
|
||||
stopTaskRegistryMaintenance,
|
||||
} from "./task-registry.maintenance.js";
|
||||
import type { TaskRecord } from "./task-registry.types.js";
|
||||
import {
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
const GRACE_EXPIRED_MS = 10 * 60_000;
|
||||
|
||||
|
||||
@@ -22,10 +22,7 @@ import {
|
||||
import { resolveOpenClawStateSqlitePath } from "../state/openclaw-state-db.paths.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
|
||||
import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-flow-registry.js";
|
||||
import { createManagedTaskFlow as createManagedTaskFlowOrNull } from "./task-flow-registry.js";
|
||||
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
|
||||
import {
|
||||
createTaskRecord as createTaskRecordOrNull,
|
||||
@@ -34,9 +31,7 @@ import {
|
||||
getTaskById,
|
||||
listFreshTasksForOwnerKey,
|
||||
markTaskTerminalById,
|
||||
maybeDeliverTaskStateChangeUpdate,
|
||||
reloadTaskRegistryFromStore,
|
||||
resetTaskRegistryForTests,
|
||||
updateTaskNotifyPolicyById,
|
||||
} from "./task-registry.js";
|
||||
import {
|
||||
@@ -56,6 +51,11 @@ import {
|
||||
parseTaskScopeKind,
|
||||
parseTaskStatus,
|
||||
} from "./task-registry.types.js";
|
||||
import {
|
||||
maybeDeliverTaskStateChangeUpdate,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
const ORIGINAL_ENV = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import type { TaskRegistryControlRuntime } from "./task-registry-control.types.js";
|
||||
import type { TaskEventRecord, TaskRecord } from "./task-registry.types.js";
|
||||
import "./task-registry.js";
|
||||
|
||||
type TaskRegistryDeliveryRuntime = Pick<
|
||||
typeof import("./task-registry-delivery-runtime.js"),
|
||||
"sendMessage"
|
||||
>;
|
||||
|
||||
type TaskRegistryTestApi = {
|
||||
maybeDeliverTaskStateChangeUpdate(
|
||||
taskId: string,
|
||||
latestEvent?: TaskEventRecord,
|
||||
): Promise<TaskRecord | null>;
|
||||
resetTaskRegistryForTests(opts?: { persist?: boolean }): void;
|
||||
resetTaskRegistryDeliveryRuntimeForTests(): void;
|
||||
setTaskRegistryDeliveryRuntimeForTests(runtime: TaskRegistryDeliveryRuntime): void;
|
||||
resetTaskRegistryControlRuntimeForTests(): void;
|
||||
setTaskRegistryControlRuntimeForTests(runtime: TaskRegistryControlRuntime): void;
|
||||
};
|
||||
|
||||
function getTestApi(): TaskRegistryTestApi {
|
||||
const api = (globalThis as Record<PropertyKey, unknown>)[
|
||||
Symbol.for("openclaw.taskRegistryTestApi")
|
||||
];
|
||||
if (!api) {
|
||||
throw new Error("task registry test API is unavailable");
|
||||
}
|
||||
return api as TaskRegistryTestApi;
|
||||
}
|
||||
|
||||
export async function maybeDeliverTaskStateChangeUpdate(
|
||||
taskId: string,
|
||||
latestEvent?: TaskEventRecord,
|
||||
): Promise<TaskRecord | null> {
|
||||
return await getTestApi().maybeDeliverTaskStateChangeUpdate(taskId, latestEvent);
|
||||
}
|
||||
|
||||
export function resetTaskRegistryForTests(opts?: { persist?: boolean }): void {
|
||||
getTestApi().resetTaskRegistryForTests(opts);
|
||||
}
|
||||
|
||||
export function resetTaskRegistryDeliveryRuntimeForTests(): void {
|
||||
getTestApi().resetTaskRegistryDeliveryRuntimeForTests();
|
||||
}
|
||||
|
||||
export function setTaskRegistryDeliveryRuntimeForTests(runtime: TaskRegistryDeliveryRuntime): void {
|
||||
getTestApi().setTaskRegistryDeliveryRuntimeForTests(runtime);
|
||||
}
|
||||
|
||||
export function resetTaskRegistryControlRuntimeForTests(): void {
|
||||
getTestApi().resetTaskRegistryControlRuntimeForTests();
|
||||
}
|
||||
|
||||
export function setTaskRegistryControlRuntimeForTests(runtime: TaskRegistryControlRuntime): void {
|
||||
getTestApi().setTaskRegistryControlRuntimeForTests(runtime);
|
||||
}
|
||||
@@ -32,9 +32,7 @@ import {
|
||||
createManagedTaskFlow as createManagedTaskFlowOrNull,
|
||||
getTaskFlowById,
|
||||
requestFlowCancel,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "./task-flow-registry.store.js";
|
||||
import type { TaskFlowRecord } from "./task-flow-registry.types.js";
|
||||
import {
|
||||
cancelTaskById,
|
||||
@@ -49,18 +47,12 @@ import {
|
||||
listTasksForRelatedSessionKey,
|
||||
listTaskRecords,
|
||||
linkTaskToFlowById,
|
||||
maybeDeliverTaskStateChangeUpdate,
|
||||
maybeDeliverTaskTerminalUpdate,
|
||||
markTaskRunningByRunId,
|
||||
markTaskTerminalById,
|
||||
recordTaskProgressByRunId,
|
||||
reloadTaskRegistryFromStore,
|
||||
resetTaskRegistryControlRuntimeForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
resolveTaskForLookupToken,
|
||||
setTaskRegistryControlRuntimeForTests,
|
||||
setTaskRegistryDeliveryRuntimeForTests,
|
||||
updateTaskNotifyPolicyById,
|
||||
} from "./task-registry.js";
|
||||
import {
|
||||
@@ -80,6 +72,16 @@ import {
|
||||
import { configureTaskRegistryRuntime } from "./task-registry.store.js";
|
||||
import { summarizeTaskRecords } from "./task-registry.summary.js";
|
||||
import type { TaskDeliveryState, TaskRecord } from "./task-registry.types.js";
|
||||
import {
|
||||
configureTaskFlowRegistryRuntime,
|
||||
maybeDeliverTaskStateChangeUpdate,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryControlRuntimeForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
setTaskRegistryControlRuntimeForTests,
|
||||
setTaskRegistryDeliveryRuntimeForTests,
|
||||
} from "./task-runtime.test-helpers.js";
|
||||
|
||||
const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000;
|
||||
const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000;
|
||||
|
||||
@@ -1607,7 +1607,7 @@ async function maybeDeliverTaskTerminalUpdateUnderAdmission(
|
||||
}
|
||||
}
|
||||
|
||||
export async function maybeDeliverTaskStateChangeUpdate(
|
||||
async function maybeDeliverTaskStateChangeUpdate(
|
||||
taskId: string,
|
||||
latestEvent?: TaskEventRecord,
|
||||
): Promise<TaskRecord | null> {
|
||||
@@ -2735,7 +2735,7 @@ export function deleteTaskRecordById(taskId: string): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function resetTaskRegistryForTests(opts?: { persist?: boolean }) {
|
||||
function resetTaskRegistryForTests(opts?: { persist?: boolean }) {
|
||||
clearTaskRegistryMemory();
|
||||
taskRegistryRestoreState = { status: "uninitialized" };
|
||||
resetTaskRegistryRuntimeForTests();
|
||||
@@ -2754,31 +2754,42 @@ export function resetTaskRegistryForTests(opts?: { persist?: boolean }) {
|
||||
getTaskRegistryStore().close?.();
|
||||
}
|
||||
|
||||
export function resetTaskRegistryDeliveryRuntimeForTests() {
|
||||
function resetTaskRegistryDeliveryRuntimeForTests() {
|
||||
(globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
|
||||
TASK_REGISTRY_DELIVERY_RUNTIME_OVERRIDE_KEY
|
||||
] = null;
|
||||
deliveryRuntimeLoader.clear();
|
||||
}
|
||||
|
||||
export function setTaskRegistryDeliveryRuntimeForTests(runtime: TaskRegistryDeliveryRuntime): void {
|
||||
function setTaskRegistryDeliveryRuntimeForTests(runtime: TaskRegistryDeliveryRuntime): void {
|
||||
(globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
|
||||
TASK_REGISTRY_DELIVERY_RUNTIME_OVERRIDE_KEY
|
||||
] = runtime;
|
||||
deliveryRuntimeLoader.clear();
|
||||
}
|
||||
|
||||
export function resetTaskRegistryControlRuntimeForTests() {
|
||||
function resetTaskRegistryControlRuntimeForTests() {
|
||||
(globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
|
||||
TASK_REGISTRY_CONTROL_RUNTIME_OVERRIDE_KEY
|
||||
] = null;
|
||||
controlRuntimeLoader.clear();
|
||||
}
|
||||
|
||||
export function setTaskRegistryControlRuntimeForTests(runtime: TaskRegistryControlRuntime): void {
|
||||
function setTaskRegistryControlRuntimeForTests(runtime: TaskRegistryControlRuntime): void {
|
||||
(globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
|
||||
TASK_REGISTRY_CONTROL_RUNTIME_OVERRIDE_KEY
|
||||
] = runtime;
|
||||
controlRuntimeLoader.clear();
|
||||
}
|
||||
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw.taskRegistryTestApi")] = {
|
||||
maybeDeliverTaskStateChangeUpdate,
|
||||
resetTaskRegistryControlRuntimeForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
setTaskRegistryControlRuntimeForTests,
|
||||
setTaskRegistryDeliveryRuntimeForTests,
|
||||
};
|
||||
}
|
||||
/* oxlint-disable max-lines -- TODO: split this grandfathered oversized file. */
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
// Test-only access to task registry reset and runtime-injection hooks.
|
||||
export { resetTaskFlowRegistryForTests } from "./task-flow-registry.js";
|
||||
export {
|
||||
resetDetachedTaskLifecycleRuntimeForTests,
|
||||
setDetachedTaskLifecycleRuntime,
|
||||
} from "./detached-task-runtime.test-support.js";
|
||||
export { resetGeneratedMediaTaskActivityForTests } from "./generated-media-task-activity.test-support.js";
|
||||
export { configureTaskFlowRegistryRuntime } from "./task-flow-registry.store.test-support.js";
|
||||
export {
|
||||
createFlowRecord,
|
||||
resetTaskFlowRegistryForTests,
|
||||
} from "./task-flow-registry.test-support.js";
|
||||
export {
|
||||
maybeDeliverTaskStateChangeUpdate,
|
||||
resetTaskRegistryControlRuntimeForTests,
|
||||
resetTaskRegistryDeliveryRuntimeForTests,
|
||||
resetTaskRegistryForTests,
|
||||
setTaskRegistryControlRuntimeForTests,
|
||||
setTaskRegistryDeliveryRuntimeForTests,
|
||||
} from "./task-registry.js";
|
||||
} from "./task-registry.test-support.js";
|
||||
|
||||
@@ -2,8 +2,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
clearGeneratedMediaTaskActivity,
|
||||
registerGeneratedMediaTaskActivity,
|
||||
resetGeneratedMediaTaskActivityForTests,
|
||||
} from "./generated-media-task-activity.js";
|
||||
import { resetGeneratedMediaTaskActivityForTests } from "./task-runtime.test-helpers.js";
|
||||
import {
|
||||
getGeneratedMediaTaskIdsForSessionKey,
|
||||
hasNewGeneratedMediaTaskForSessionKey,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// ACP manager task state helper resets task flow state for ACP tests.
|
||||
import { resetTaskFlowRegistryForTests } from "../../src/tasks/task-flow-registry.js";
|
||||
import { configureTaskFlowRegistryRuntime } from "../../src/tasks/task-flow-registry.store.js";
|
||||
import { findTaskByRunId, resetTaskRegistryForTests } from "../../src/tasks/task-registry.js";
|
||||
import { findTaskByRunId } from "../../src/tasks/task-registry.js";
|
||||
import {
|
||||
configureTaskFlowRegistryRuntime,
|
||||
resetTaskFlowRegistryForTests,
|
||||
resetTaskRegistryForTests,
|
||||
} from "../../src/tasks/task-runtime.test-helpers.js";
|
||||
import { withTempDir } from "../../src/test-helpers/temp-dir.js";
|
||||
import { captureEnv, setTestEnvValue } from "../../src/test-utils/env.js";
|
||||
import { installInMemoryTaskRegistryRuntime } from "../../src/test-utils/task-registry-runtime.js";
|
||||
|
||||
@@ -11,6 +11,7 @@ describe("Docker E2E client scripts", () => {
|
||||
const source = readScript("scripts/e2e/commitments-safety-docker-client.ts");
|
||||
|
||||
expect(source).toContain("../../dist/commitments/runtime.js");
|
||||
expect(source).toContain("../../dist/commitments/runtime.test-support.js");
|
||||
expect(source).toContain("../../dist/commitments/store.js");
|
||||
expect(source).toContain("verifyQueueCap()");
|
||||
expect(source).toContain("verifyExtractionStoresTypedMetadataOnly()");
|
||||
|
||||
@@ -323,6 +323,7 @@ function buildDockerE2eHarnessEntries(): Record<string, string> {
|
||||
"auto-reply/reply/commands-system-agent": "src/auto-reply/reply/commands-system-agent.ts",
|
||||
"cli/run-main": "src/cli/run-main.ts",
|
||||
"commitments/runtime": "src/commitments/runtime.ts",
|
||||
"commitments/runtime.test-support": "src/commitments/runtime.test-support.ts",
|
||||
"commitments/store": "src/commitments/store.ts",
|
||||
"config/config": "src/config/config.ts",
|
||||
"system-agent/system-agent": "src/system-agent/system-agent.ts",
|
||||
|
||||
Reference in New Issue
Block a user