mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:20:43 +00:00
perf(test): slim subagent lifecycle imports
This commit is contained in:
@@ -10,6 +10,16 @@ vi.mock("../gateway/call.js", () => ({
|
||||
callGateway: (opts: unknown) => callGatewayMock(opts),
|
||||
}));
|
||||
|
||||
vi.mock("../tasks/task-executor.js", () => ({
|
||||
completeTaskRunByRunId: vi.fn(),
|
||||
createQueuedTaskRun: vi.fn(),
|
||||
createRunningTaskRun: vi.fn(),
|
||||
failTaskRunByRunId: vi.fn(),
|
||||
recordTaskRunProgressByRunId: vi.fn(),
|
||||
setDetachedTaskDeliveryStatusByRunId: vi.fn(),
|
||||
startTaskRunByRunId: vi.fn(),
|
||||
}));
|
||||
|
||||
let storeTemplatePath = "";
|
||||
let configOverride: Record<string, unknown> = {
|
||||
session: createPerSenderSessionConfig(),
|
||||
@@ -20,13 +30,9 @@ let subagentRegistryTesting: typeof import("./subagent-registry.js").__testing;
|
||||
let setSubagentSpawnDepsForTest: typeof import("./subagent-spawn.js").__testing.setDepsForTest;
|
||||
let createSessionsSpawnTool: typeof import("./tools/sessions-spawn-tool.js").createSessionsSpawnTool;
|
||||
|
||||
vi.mock("../config/config.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("../config/config.js")>("../config/config.js");
|
||||
return {
|
||||
...actual,
|
||||
loadConfig: () => configOverride,
|
||||
};
|
||||
});
|
||||
vi.mock("../config/config.js", () => ({
|
||||
loadConfig: () => configOverride,
|
||||
}));
|
||||
|
||||
function writeStore(agentId: string, store: Record<string, unknown>) {
|
||||
const storePath = storeTemplatePath.replaceAll("{agentId}", agentId);
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
setSessionsSpawnHookRunnerOverride,
|
||||
setupSessionsSpawnGatewayMock,
|
||||
setSessionsSpawnConfigOverride,
|
||||
waitForSessionsSpawnEvent,
|
||||
} from "./openclaw-tools.subagents.sessions-spawn.test-harness.js";
|
||||
import {
|
||||
getLatestSubagentRunByChildSessionKey,
|
||||
@@ -61,15 +62,6 @@ function buildDiscordCleanupHooks(onDelete: (key: string | undefined) => void) {
|
||||
};
|
||||
}
|
||||
|
||||
const waitFor = async (label: string, predicate: () => boolean, timeoutMs = 30_000) => {
|
||||
await vi.waitFor(
|
||||
() => {
|
||||
expect(predicate(), label).toBe(true);
|
||||
},
|
||||
{ timeout: timeoutMs, interval: 1 },
|
||||
);
|
||||
};
|
||||
|
||||
async function getDiscordGroupSpawnTool() {
|
||||
return await getSessionsSpawnTool({
|
||||
agentSessionKey: "discord:group:req",
|
||||
@@ -152,7 +144,7 @@ async function emitLifecycleEndAndFlush(params: {
|
||||
}
|
||||
|
||||
async function waitForRunCleanup(childSessionKey: string) {
|
||||
await waitFor("run cleanup bookkeeping", () => {
|
||||
await waitForSessionsSpawnEvent("run cleanup bookkeeping", () => {
|
||||
const run = getLatestSubagentRunByChildSessionKey(childSessionKey);
|
||||
return run?.cleanupCompletedAt != null;
|
||||
});
|
||||
@@ -232,7 +224,7 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
|
||||
if (!child.runId) {
|
||||
throw new Error("missing child runId");
|
||||
}
|
||||
await waitFor(
|
||||
await waitForSessionsSpawnEvent(
|
||||
"subagent wait, label patch, and main agent trigger",
|
||||
() =>
|
||||
ctx.waitCalls.some((call) => call.runId === child.runId) &&
|
||||
@@ -295,7 +287,7 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
|
||||
endedAt: 2345,
|
||||
});
|
||||
|
||||
await waitFor(
|
||||
await waitForSessionsSpawnEvent(
|
||||
"lifecycle cleanup",
|
||||
() => ctx.calls.filter((call) => call.method === "agent").length >= 2 && Boolean(deletedKey),
|
||||
);
|
||||
@@ -358,14 +350,14 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
|
||||
if (!child.runId) {
|
||||
throw new Error("missing child runId");
|
||||
}
|
||||
await waitFor("agent.wait called for child run", () =>
|
||||
await waitForSessionsSpawnEvent("agent.wait called for child run", () =>
|
||||
ctx.waitCalls.some((call) => call.runId === child.runId),
|
||||
);
|
||||
await waitFor(
|
||||
await waitForSessionsSpawnEvent(
|
||||
"main agent cleanup trigger",
|
||||
() => ctx.calls.filter((call) => call.method === "agent").length >= 2,
|
||||
);
|
||||
await waitFor("delete cleanup", () => Boolean(deletedKey));
|
||||
await waitForSessionsSpawnEvent("delete cleanup", () => Boolean(deletedKey));
|
||||
|
||||
const childWait = ctx.waitCalls.find((call) => call.runId === child.runId);
|
||||
expect(childWait?.timeoutMs).toBe(1000);
|
||||
@@ -416,12 +408,11 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
|
||||
}
|
||||
const childSessionKey = child.sessionKey;
|
||||
|
||||
await waitFor(
|
||||
await waitForSessionsSpawnEvent(
|
||||
"timeout outcome",
|
||||
() =>
|
||||
ctx.waitCalls.some((call) => call.runId === child.runId) &&
|
||||
getLatestSubagentRunByChildSessionKey(childSessionKey)?.outcome?.status === "timeout",
|
||||
20_000,
|
||||
);
|
||||
await waitForRunCleanup(childSessionKey);
|
||||
|
||||
@@ -488,7 +479,7 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
|
||||
endedAt: 2000,
|
||||
});
|
||||
|
||||
await waitFor(
|
||||
await waitForSessionsSpawnEvent(
|
||||
"account-aware lifecycle announce",
|
||||
() => ctx.calls.filter((call) => call.method === "agent").length >= 2,
|
||||
);
|
||||
|
||||
@@ -23,6 +23,13 @@ type SessionsSpawnGatewayMockOptions = {
|
||||
onSessionsDelete?: (params: unknown) => void;
|
||||
agentWaitResult?: { status: "ok" | "timeout"; startedAt: number; endedAt: number };
|
||||
};
|
||||
type EventWaiter = {
|
||||
label: string;
|
||||
predicate: () => boolean;
|
||||
resolve: () => void;
|
||||
reject: (error: Error) => void;
|
||||
timer: ReturnType<typeof setTimeout>;
|
||||
};
|
||||
|
||||
const hoisted = vi.hoisted(() => {
|
||||
const callGatewayMock = vi.fn();
|
||||
@@ -90,9 +97,23 @@ const hoisted = vi.hoisted(() => {
|
||||
defaultRunSubagentAnnounceFlow,
|
||||
runSubagentAnnounceFlowOverride: defaultRunSubagentAnnounceFlow,
|
||||
};
|
||||
const eventWaiters: EventWaiter[] = [];
|
||||
const notifyEventWaiters = () => {
|
||||
for (let index = eventWaiters.length - 1; index >= 0; index -= 1) {
|
||||
const waiter = eventWaiters[index];
|
||||
if (!waiter?.predicate()) {
|
||||
continue;
|
||||
}
|
||||
clearTimeout(waiter.timer);
|
||||
eventWaiters.splice(index, 1);
|
||||
waiter.resolve();
|
||||
}
|
||||
};
|
||||
return {
|
||||
callGatewayMock,
|
||||
defaultConfigOverride,
|
||||
eventWaiters,
|
||||
notifyEventWaiters,
|
||||
nextRunId: () => {
|
||||
nextRunId += 1;
|
||||
return `run-${nextRunId}`;
|
||||
@@ -122,6 +143,26 @@ export function findGatewayRequest(method: string): GatewayRequest | undefined {
|
||||
return getGatewayRequests().find((request) => request.method === method);
|
||||
}
|
||||
|
||||
export async function waitForSessionsSpawnEvent(
|
||||
label: string,
|
||||
predicate: () => boolean,
|
||||
timeoutMs = 5_000,
|
||||
): Promise<void> {
|
||||
if (predicate()) {
|
||||
return;
|
||||
}
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const timer = setTimeout(() => {
|
||||
const index = hoisted.eventWaiters.findIndex((waiter) => waiter.timer === timer);
|
||||
if (index >= 0) {
|
||||
hoisted.eventWaiters.splice(index, 1);
|
||||
}
|
||||
reject(new Error(`Timed out waiting for ${label}`));
|
||||
}, timeoutMs);
|
||||
hoisted.eventWaiters.push({ label, predicate, resolve, reject, timer });
|
||||
});
|
||||
}
|
||||
|
||||
export function resetSessionsSpawnConfigOverride(): void {
|
||||
hoisted.state.configOverride = hoisted.defaultConfigOverride;
|
||||
}
|
||||
@@ -165,6 +206,10 @@ export async function getSessionsSpawnTool(opts: CreateOpenClawToolsOpts) {
|
||||
cleanupBrowserSessionsForLifecycleEnd: async () => {},
|
||||
ensureContextEnginesInitialized: () => {},
|
||||
ensureRuntimePluginsLoaded: () => {},
|
||||
persistSubagentRunsToDisk: () => {
|
||||
hoisted.notifyEventWaiters();
|
||||
},
|
||||
restoreSubagentRunsFromDisk: () => 0,
|
||||
resolveContextEngine: async () => ({
|
||||
info: { id: "test", name: "Test" },
|
||||
assemble: async ({ messages }) => ({ messages, estimatedTokens: 0 }),
|
||||
@@ -195,6 +240,7 @@ export function setupSessionsSpawnGatewayMock(setupOpts: SessionsSpawnGatewayMoc
|
||||
getCallGatewayMock().mockImplementation(async (optsUnknown: unknown) => {
|
||||
const request = optsUnknown as GatewayRequest;
|
||||
calls.push(request);
|
||||
hoisted.notifyEventWaiters();
|
||||
|
||||
if (request.method === "sessions.list" && setupOpts.includeSessionsList) {
|
||||
return {
|
||||
@@ -233,6 +279,7 @@ export function setupSessionsSpawnGatewayMock(setupOpts: SessionsSpawnGatewayMoc
|
||||
if (request.method === "agent.wait") {
|
||||
const params = request.params as AgentWaitCall | undefined;
|
||||
waitCalls.push(params ?? {});
|
||||
hoisted.notifyEventWaiters();
|
||||
const waitResult = setupOpts.agentWaitResult ?? {
|
||||
status: "ok",
|
||||
startedAt: 1000,
|
||||
@@ -246,11 +293,13 @@ export function setupSessionsSpawnGatewayMock(setupOpts: SessionsSpawnGatewayMoc
|
||||
|
||||
if (request.method === "sessions.patch") {
|
||||
setupOpts.onSessionsPatch?.(request.params);
|
||||
hoisted.notifyEventWaiters();
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
if (request.method === "sessions.delete") {
|
||||
setupOpts.onSessionsDelete?.(request.params);
|
||||
hoisted.notifyEventWaiters();
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ChatType } from "../channels/chat-type.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { resolveFirstBoundAccountId } from "../routing/bound-account-read.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js";
|
||||
|
||||
// Delivery targets often carry a transport wrapper (e.g. Matrix `room:<id>` or
|
||||
// LINE `line:group:<id>`), while route bindings commonly store raw peer ids on
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { type QueueDropPolicy, type QueueMode } from "../auto-reply/reply/queue.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import {
|
||||
type DeliveryContext,
|
||||
deliveryContextKey,
|
||||
normalizeDeliveryContext,
|
||||
} from "../utils/delivery-context.js";
|
||||
import { deliveryContextKey, normalizeDeliveryContext } from "../utils/delivery-context.shared.js";
|
||||
import type { DeliveryContext } from "../utils/delivery-context.types.js";
|
||||
import {
|
||||
applyQueueRuntimeSettings,
|
||||
applyQueueDropPolicy,
|
||||
|
||||
@@ -159,6 +159,9 @@ beforeEach(() => {
|
||||
cleanupBrowserSessionsForLifecycleEnd: async () => {},
|
||||
ensureContextEnginesInitialized: () => {},
|
||||
ensureRuntimePluginsLoaded: () => {},
|
||||
getSubagentRunsSnapshotForRead: (runs) => new Map(runs),
|
||||
persistSubagentRunsToDisk: () => {},
|
||||
restoreSubagentRunsFromDisk: () => 0,
|
||||
resolveContextEngine: async () => ({
|
||||
info: { id: "test", name: "Test" },
|
||||
assemble: async ({ messages }) => ({ messages, estimatedTokens: 0 }),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type DeliveryContext, normalizeDeliveryContext } from "../utils/delivery-context.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js";
|
||||
import type { DeliveryContext } from "../utils/delivery-context.types.js";
|
||||
import { subagentRuns } from "./subagent-registry-memory.js";
|
||||
import {
|
||||
countPendingDescendantRunsExcludingRunFromRuns,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
|
||||
import { cleanupBrowserSessionsForLifecycleEnd } from "../browser-lifecycle-cleanup.js";
|
||||
import type { cleanupBrowserSessionsForLifecycleEnd } from "../browser-lifecycle-cleanup.js";
|
||||
import { formatErrorMessage, readErrorName } from "../infra/errors.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import { emitSessionLifecycleEvent } from "../sessions/session-lifecycle-events.js";
|
||||
@@ -8,13 +8,8 @@ import {
|
||||
failTaskRunByRunId,
|
||||
setDetachedTaskDeliveryStatusByRunId,
|
||||
} from "../tasks/detached-task-runtime.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.js";
|
||||
import { withSubagentOutcomeTiming } from "./subagent-announce-output.js";
|
||||
import {
|
||||
captureSubagentCompletionReply,
|
||||
runSubagentAnnounceFlow,
|
||||
type SubagentRunOutcome,
|
||||
} from "./subagent-announce.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js";
|
||||
import { type SubagentRunOutcome, withSubagentOutcomeTiming } from "./subagent-announce-output.js";
|
||||
import {
|
||||
SUBAGENT_ENDED_REASON_COMPLETE,
|
||||
type SubagentLifecycleEndedReason,
|
||||
@@ -37,6 +32,23 @@ import {
|
||||
} from "./subagent-registry-helpers.js";
|
||||
import type { SubagentRunRecord } from "./subagent-registry.types.js";
|
||||
|
||||
type CaptureSubagentCompletionReply =
|
||||
(typeof import("./subagent-announce.js"))["captureSubagentCompletionReply"];
|
||||
type RunSubagentAnnounceFlow = (typeof import("./subagent-announce.js"))["runSubagentAnnounceFlow"];
|
||||
type BrowserCleanupModule = Pick<
|
||||
typeof import("../browser-lifecycle-cleanup.js"),
|
||||
"cleanupBrowserSessionsForLifecycleEnd"
|
||||
>;
|
||||
|
||||
let browserCleanupPromise: Promise<BrowserCleanupModule> | null = null;
|
||||
|
||||
async function loadCleanupBrowserSessionsForLifecycleEnd(): Promise<
|
||||
BrowserCleanupModule["cleanupBrowserSessionsForLifecycleEnd"]
|
||||
> {
|
||||
browserCleanupPromise ??= import("../browser-lifecycle-cleanup.js");
|
||||
return (await browserCleanupPromise).cleanupBrowserSessionsForLifecycleEnd;
|
||||
}
|
||||
|
||||
export function createSubagentRegistryLifecycleController(params: {
|
||||
runs: Map<string, SubagentRunRecord>;
|
||||
resumedRuns: Set<string>;
|
||||
@@ -61,9 +73,9 @@ export function createSubagentRegistryLifecycleController(params: {
|
||||
workspaceDir?: string;
|
||||
}): Promise<void>;
|
||||
resumeSubagentRun(runId: string): void;
|
||||
captureSubagentCompletionReply: typeof captureSubagentCompletionReply;
|
||||
captureSubagentCompletionReply: CaptureSubagentCompletionReply;
|
||||
cleanupBrowserSessionsForLifecycleEnd?: typeof cleanupBrowserSessionsForLifecycleEnd;
|
||||
runSubagentAnnounceFlow: typeof runSubagentAnnounceFlow;
|
||||
runSubagentAnnounceFlow: RunSubagentAnnounceFlow;
|
||||
warn(message: string, meta?: Record<string, unknown>): void;
|
||||
}) {
|
||||
const scheduledResumeTimers = new Set<ReturnType<typeof setTimeout>>();
|
||||
@@ -223,7 +235,7 @@ export function createSubagentRegistryLifecycleController(params: {
|
||||
|
||||
let captured: string | undefined;
|
||||
try {
|
||||
captured = await captureSubagentCompletionReply(sessionKey);
|
||||
captured = await params.captureSubagentCompletionReply(sessionKey);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
@@ -658,7 +670,10 @@ export function createSubagentRegistryLifecycleController(params: {
|
||||
return;
|
||||
}
|
||||
|
||||
await (params.cleanupBrowserSessionsForLifecycleEnd ?? cleanupBrowserSessionsForLifecycleEnd)({
|
||||
const cleanupBrowserSessions =
|
||||
params.cleanupBrowserSessionsForLifecycleEnd ??
|
||||
(await loadCleanupBrowserSessionsForLifecycleEnd());
|
||||
await cleanupBrowserSessions({
|
||||
sessionKeys: [entry.childSessionKey],
|
||||
onWarn: (msg) => params.warn(msg, { runId: entry.runId }),
|
||||
});
|
||||
|
||||
@@ -4,7 +4,8 @@ import { callGateway } from "../gateway/call.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
|
||||
import { createRunningTaskRun } from "../tasks/detached-task-runtime.js";
|
||||
import { type DeliveryContext, normalizeDeliveryContext } from "../utils/delivery-context.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js";
|
||||
import type { DeliveryContext } from "../utils/delivery-context.types.js";
|
||||
import { waitForAgentRun } from "./run-wait.js";
|
||||
import type { ensureRuntimePluginsLoaded as ensureRuntimePluginsLoadedFn } from "./runtime-plugins.js";
|
||||
import { type SubagentRunOutcome, withSubagentOutcomeTiming } from "./subagent-announce-output.js";
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from "node:path";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import { loadJsonFile, saveJsonFile } from "../infra/json-file.js";
|
||||
import { readStringValue } from "../shared/string-coerce.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js";
|
||||
import type { SubagentRunRecord } from "./subagent-registry.types.js";
|
||||
|
||||
export type PersistedSubagentRegistryVersion = 1 | 2;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cleanupBrowserSessionsForLifecycleEnd } from "../browser-lifecycle-cleanup.js";
|
||||
import type { cleanupBrowserSessionsForLifecycleEnd } from "../browser-lifecycle-cleanup.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { ContextEngine, SubagentEndReason } from "../context-engine/types.js";
|
||||
@@ -6,11 +6,11 @@ import { callGateway } from "../gateway/call.js";
|
||||
import { onAgentEvent } from "../infra/agent-events.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { importRuntimeModule } from "../shared/runtime-import.js";
|
||||
import { type DeliveryContext, normalizeDeliveryContext } from "../utils/delivery-context.js";
|
||||
import { normalizeDeliveryContext } from "../utils/delivery-context.shared.js";
|
||||
import type { DeliveryContext } from "../utils/delivery-context.types.js";
|
||||
import type { ensureRuntimePluginsLoaded as ensureRuntimePluginsLoadedFn } from "./runtime-plugins.js";
|
||||
import type { SubagentRunOutcome } from "./subagent-announce-output.js";
|
||||
import { resetAnnounceQueuesForTests } from "./subagent-announce-queue.js";
|
||||
import * as subagentAnnounceModule from "./subagent-announce.js";
|
||||
import {
|
||||
SUBAGENT_ENDED_REASON_COMPLETE,
|
||||
SUBAGENT_ENDED_REASON_ERROR,
|
||||
@@ -67,9 +67,18 @@ export {
|
||||
} from "./subagent-registry-helpers.js";
|
||||
const log = createSubsystemLogger("agents/subagent-registry");
|
||||
|
||||
type SubagentAnnounceModule = Pick<
|
||||
typeof import("./subagent-announce.js"),
|
||||
"captureSubagentCompletionReply" | "runSubagentAnnounceFlow"
|
||||
>;
|
||||
type BrowserCleanupModule = Pick<
|
||||
typeof import("../browser-lifecycle-cleanup.js"),
|
||||
"cleanupBrowserSessionsForLifecycleEnd"
|
||||
>;
|
||||
|
||||
type SubagentRegistryDeps = {
|
||||
callGateway: typeof callGateway;
|
||||
captureSubagentCompletionReply: typeof subagentAnnounceModule.captureSubagentCompletionReply;
|
||||
captureSubagentCompletionReply: SubagentAnnounceModule["captureSubagentCompletionReply"];
|
||||
cleanupBrowserSessionsForLifecycleEnd: typeof cleanupBrowserSessionsForLifecycleEnd;
|
||||
getSubagentRunsSnapshotForRead: typeof getSubagentRunsSnapshotForRead;
|
||||
loadConfig: typeof loadConfig;
|
||||
@@ -77,24 +86,41 @@ type SubagentRegistryDeps = {
|
||||
persistSubagentRunsToDisk: typeof persistSubagentRunsToDisk;
|
||||
resolveAgentTimeoutMs: typeof resolveAgentTimeoutMs;
|
||||
restoreSubagentRunsFromDisk: typeof restoreSubagentRunsFromDisk;
|
||||
runSubagentAnnounceFlow: typeof subagentAnnounceModule.runSubagentAnnounceFlow;
|
||||
runSubagentAnnounceFlow: SubagentAnnounceModule["runSubagentAnnounceFlow"];
|
||||
ensureContextEnginesInitialized?: () => void;
|
||||
ensureRuntimePluginsLoaded?: typeof ensureRuntimePluginsLoadedFn;
|
||||
resolveContextEngine?: (cfg: OpenClawConfig) => Promise<ContextEngine>;
|
||||
};
|
||||
|
||||
let subagentAnnouncePromise: Promise<SubagentAnnounceModule> | null = null;
|
||||
let browserCleanupPromise: Promise<BrowserCleanupModule> | null = null;
|
||||
|
||||
async function loadSubagentAnnounceModule(): Promise<SubagentAnnounceModule> {
|
||||
subagentAnnouncePromise ??= import("./subagent-announce.js");
|
||||
return await subagentAnnouncePromise;
|
||||
}
|
||||
|
||||
async function loadCleanupBrowserSessionsForLifecycleEnd(): Promise<
|
||||
BrowserCleanupModule["cleanupBrowserSessionsForLifecycleEnd"]
|
||||
> {
|
||||
browserCleanupPromise ??= import("../browser-lifecycle-cleanup.js");
|
||||
return (await browserCleanupPromise).cleanupBrowserSessionsForLifecycleEnd;
|
||||
}
|
||||
|
||||
const defaultSubagentRegistryDeps: SubagentRegistryDeps = {
|
||||
callGateway,
|
||||
captureSubagentCompletionReply: (sessionKey) =>
|
||||
subagentAnnounceModule.captureSubagentCompletionReply(sessionKey),
|
||||
cleanupBrowserSessionsForLifecycleEnd,
|
||||
captureSubagentCompletionReply: async (sessionKey) =>
|
||||
(await loadSubagentAnnounceModule()).captureSubagentCompletionReply(sessionKey),
|
||||
cleanupBrowserSessionsForLifecycleEnd: async (params) =>
|
||||
(await loadCleanupBrowserSessionsForLifecycleEnd())(params),
|
||||
getSubagentRunsSnapshotForRead,
|
||||
loadConfig,
|
||||
onAgentEvent,
|
||||
persistSubagentRunsToDisk,
|
||||
resolveAgentTimeoutMs,
|
||||
restoreSubagentRunsFromDisk,
|
||||
runSubagentAnnounceFlow: (params) => subagentAnnounceModule.runSubagentAnnounceFlow(params),
|
||||
runSubagentAnnounceFlow: async (params) =>
|
||||
(await loadSubagentAnnounceModule()).runSubagentAnnounceFlow(params),
|
||||
};
|
||||
|
||||
let subagentRegistryDeps: SubagentRegistryDeps = defaultSubagentRegistryDeps;
|
||||
@@ -744,6 +770,8 @@ export function resetSubagentRegistryForTests(opts?: { persist?: boolean }) {
|
||||
contextEngineInitPromise = null;
|
||||
contextEngineRegistryPromise = null;
|
||||
runtimePluginsPromise = null;
|
||||
subagentAnnouncePromise = null;
|
||||
browserCleanupPromise = null;
|
||||
resetAnnounceQueuesForTests();
|
||||
stopSweeper();
|
||||
sweepInProgress = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { callGateway } from "../../gateway/call.js";
|
||||
import { normalizeDeliveryContext } from "../../utils/delivery-context.js";
|
||||
import { normalizeDeliveryContext } from "../../utils/delivery-context.shared.js";
|
||||
import type { GatewayMessageChannel } from "../../utils/message-channel.js";
|
||||
import { optionalStringEnum } from "../schema/typebox.js";
|
||||
import type { SpawnedToolContext } from "../spawned-context.js";
|
||||
|
||||
Reference in New Issue
Block a user