diff --git a/src/cron/isolated-agent/run.ts b/src/cron/isolated-agent/run.ts index c97369cad50..f0db9a6f1ee 100644 --- a/src/cron/isolated-agent/run.ts +++ b/src/cron/isolated-agent/run.ts @@ -424,7 +424,7 @@ async function prepareCronRunContext(params: { } commandBody = appendCronDeliveryInstruction({ commandBody, deliveryRequested }); - const skillsSnapshot = resolveCronSkillsSnapshot({ + const skillsSnapshot = await resolveCronSkillsSnapshot({ workspaceDir, config: cfgWithAgentDefaults, agentId, diff --git a/src/cron/isolated-agent/skills-snapshot.runtime.ts b/src/cron/isolated-agent/skills-snapshot.runtime.ts new file mode 100644 index 00000000000..6f9439c103c --- /dev/null +++ b/src/cron/isolated-agent/skills-snapshot.runtime.ts @@ -0,0 +1,6 @@ +export { canExecRequestNode } from "../../agents/exec-defaults.js"; +export { + buildWorkspaceSkillSnapshot, + getRemoteSkillEligibility, + getSkillsSnapshotVersion, +} from "./run.runtime.js"; diff --git a/src/cron/isolated-agent/skills-snapshot.test.ts b/src/cron/isolated-agent/skills-snapshot.test.ts index 3e0db14515a..234750ca51c 100644 --- a/src/cron/isolated-agent/skills-snapshot.test.ts +++ b/src/cron/isolated-agent/skills-snapshot.test.ts @@ -2,20 +2,26 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const { buildWorkspaceSkillSnapshotMock, + canExecRequestNodeMock, getRemoteSkillEligibilityMock, getSkillsSnapshotVersionMock, resolveAgentSkillsFilterMock, } = vi.hoisted(() => ({ buildWorkspaceSkillSnapshotMock: vi.fn(), + canExecRequestNodeMock: vi.fn().mockReturnValue(false), getRemoteSkillEligibilityMock: vi.fn(), getSkillsSnapshotVersionMock: vi.fn(), resolveAgentSkillsFilterMock: vi.fn(), })); -vi.mock("./run.runtime.js", () => ({ +vi.mock("./skills-snapshot.runtime.js", () => ({ buildWorkspaceSkillSnapshot: buildWorkspaceSkillSnapshotMock, + canExecRequestNode: canExecRequestNodeMock, getRemoteSkillEligibility: getRemoteSkillEligibilityMock, getSkillsSnapshotVersion: getSkillsSnapshotVersionMock, +})); + +vi.mock("./run.runtime.js", () => ({ resolveAgentSkillsFilter: resolveAgentSkillsFilterMock, })); @@ -34,10 +40,10 @@ describe("resolveCronSkillsSnapshot", () => { buildWorkspaceSkillSnapshotMock.mockReturnValue({ prompt: "fresh", skills: [] }); }); - it("refreshes when the cached skill filter changes", () => { + it("refreshes when the cached skill filter changes", async () => { resolveAgentSkillsFilterMock.mockReturnValue(["docs-search", "github"]); - const result = resolveCronSkillsSnapshot({ + const result = await resolveCronSkillsSnapshot({ workspaceDir: "/tmp/workspace", config: {} as never, agentId: "writer", @@ -58,10 +64,10 @@ describe("resolveCronSkillsSnapshot", () => { expect(result).toEqual({ prompt: "fresh", skills: [] }); }); - it("refreshes when the process version resets to 0 but the cached snapshot is stale", () => { + it("refreshes when the process version resets to 0 but the cached snapshot is stale", async () => { getSkillsSnapshotVersionMock.mockReturnValue(0); - resolveCronSkillsSnapshot({ + await resolveCronSkillsSnapshot({ workspaceDir: "/tmp/workspace", config: {} as never, agentId: "writer", diff --git a/src/cron/isolated-agent/skills-snapshot.ts b/src/cron/isolated-agent/skills-snapshot.ts index c66825c9204..9bd6d2ced13 100644 --- a/src/cron/isolated-agent/skills-snapshot.ts +++ b/src/cron/isolated-agent/skills-snapshot.ts @@ -1,27 +1,31 @@ -import { canExecRequestNode } from "../../agents/exec-defaults.js"; import type { SkillSnapshot } from "../../agents/skills.js"; import { matchesSkillFilter } from "../../agents/skills/filter.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; -import { - buildWorkspaceSkillSnapshot, - getRemoteSkillEligibility, - getSkillsSnapshotVersion, - resolveAgentSkillsFilter, -} from "./run.runtime.js"; +import { resolveAgentSkillsFilter } from "./run.runtime.js"; -export function resolveCronSkillsSnapshot(params: { +let skillsSnapshotRuntimePromise: + | Promise + | undefined; + +async function loadSkillsSnapshotRuntime() { + skillsSnapshotRuntimePromise ??= import("./skills-snapshot.runtime.js"); + return await skillsSnapshotRuntimePromise; +} + +export async function resolveCronSkillsSnapshot(params: { workspaceDir: string; config: OpenClawConfig; agentId: string; existingSnapshot?: SkillSnapshot; isFastTestEnv: boolean; -}): SkillSnapshot { +}): Promise { if (params.isFastTestEnv) { // Fast unit-test mode skips filesystem scans and snapshot refresh writes. return params.existingSnapshot ?? { prompt: "", skills: [] }; } - const snapshotVersion = getSkillsSnapshotVersion(params.workspaceDir); + const runtime = await loadSkillsSnapshotRuntime(); + const snapshotVersion = runtime.getSkillsSnapshotVersion(params.workspaceDir); const skillFilter = resolveAgentSkillsFilter(params.config, params.agentId); const existingSnapshot = params.existingSnapshot; const shouldRefresh = @@ -32,13 +36,13 @@ export function resolveCronSkillsSnapshot(params: { return existingSnapshot; } - return buildWorkspaceSkillSnapshot(params.workspaceDir, { + return runtime.buildWorkspaceSkillSnapshot(params.workspaceDir, { config: params.config, agentId: params.agentId, skillFilter, eligibility: { - remote: getRemoteSkillEligibility({ - advertiseExecNode: canExecRequestNode({ + remote: runtime.getRemoteSkillEligibility({ + advertiseExecNode: runtime.canExecRequestNode({ cfg: params.config, agentId: params.agentId, }),