evOo-local/packages/adapter-kit/src/background-jobs.test.ts
Claude 044669edfc
Add a media library: owner folders that bots can search and import from
The deployment owner adds folders of photos and videos in the media settings. A per-folder
background job indexes them (relative path, kind, size, capture date, dimensions, duration),
re-indexes every six hours, and drops files that are gone. The owner's own runs get two tools:
search_media (words in folder and file names, kind, capture date range, newest first) and
import_media (copies one file into the conversation as an artifact). Files are never changed;
hidden entries and symlinks are skipped, and an import must resolve inside its folder.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs
2026-10-05 08:45:30 +00:00

159 lines
5.7 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import {
dispatchBackgroundJob,
historyCompactJob,
historyCompactJobKey,
MEDIA_JOB_QUEUE,
MEDIA_LIBRARY_JOB_QUEUE,
mediaLibrarySyncJob,
mediaLibrarySyncJobKey,
mediaRunJob,
mediaRunJobKey,
messagingDeliverJob,
parseBackgroundJob,
profileConsolidateJob,
profileConsolidateJobKey,
} from "./background-jobs.js";
import type { BackgroundJobHandlers } from "./types.js";
function handlers(): BackgroundJobHandlers {
return {
"run.continue": vi.fn(async () => undefined),
"routine.wakeup": vi.fn(async () => undefined),
"computer.update": vi.fn(async () => undefined),
"computer.sleep": vi.fn(async () => undefined),
"computer.control-expire": vi.fn(async () => undefined),
"skill.teaching-expire": vi.fn(async () => undefined),
"history.compact": vi.fn(async () => undefined),
"messaging.deliver": vi.fn(async () => undefined),
"cloud_agent.poll": vi.fn(async () => undefined),
"profile.consolidate": vi.fn(async () => undefined),
"media.run": vi.fn(async () => undefined),
"media.library.sync": vi.fn(async () => undefined),
};
}
describe("background job contracts", () => {
it("validates and dispatches messaging.deliver", async () => {
const target = handlers();
await dispatchBackgroundJob(target, "messaging.deliver", { runId: "run-1" });
expect(target["messaging.deliver"]).toHaveBeenCalledWith({ runId: "run-1" });
expect(messagingDeliverJob("run-1")).toEqual({
name: "messaging.deliver",
payload: { runId: "run-1" },
replaceKey: "messaging.deliver:run-1",
});
expect(messagingDeliverJob()).toEqual({
name: "messaging.deliver",
payload: {},
replaceKey: "messaging.deliver:drain",
});
});
it("validates and dispatches a typed job", async () => {
const target = handlers();
await dispatchBackgroundJob(target, "routine.wakeup", {
routineId: "routine-1",
scheduledFor: "2026-08-15T12:00:00.000Z",
});
expect(target["routine.wakeup"]).toHaveBeenCalledWith({
routineId: "routine-1",
scheduledFor: "2026-08-15T12:00:00.000Z",
});
});
it("rejects unknown names and malformed deliveries", () => {
expect(() => parseBackgroundJob("unknown", {})).toThrow("Unknown background job");
expect(() =>
parseBackgroundJob("routine.wakeup", {
routineId: "routine-1",
scheduledFor: "not-a-date",
}),
).toThrow();
expect(() => parseBackgroundJob("run.continue", { runId: "" })).toThrow();
expect(() =>
parseBackgroundJob("computer.control-expire", {
computerId: "computer-1",
leaseId: "",
}),
).toThrow();
});
it("validates and dispatches a control-expiry job", async () => {
const target = handlers();
await dispatchBackgroundJob(target, "computer.control-expire", {
computerId: "computer-1",
leaseId: "lease-1",
});
expect(target["computer.control-expire"]).toHaveBeenCalledWith({
computerId: "computer-1",
leaseId: "lease-1",
});
});
});
describe("historyCompactJob", () => {
it("builds a job with a replace key scoped to the thread", () => {
expect(historyCompactJob("thread-1")).toEqual({
name: "history.compact",
payload: { threadId: "thread-1" },
replaceKey: historyCompactJobKey("thread-1"),
});
});
it("keys different threads differently", () => {
expect(historyCompactJobKey("thread-1")).not.toBe(historyCompactJobKey("thread-2"));
});
});
describe("profileConsolidateJob", () => {
it("validates, dispatches, and keys one pending consolidation per user", async () => {
const target = handlers();
await dispatchBackgroundJob(target, "profile.consolidate", { userId: "user-1" });
expect(target["profile.consolidate"]).toHaveBeenCalledWith({ userId: "user-1" });
expect(() => parseBackgroundJob("profile.consolidate", { userId: "" })).toThrow();
expect(profileConsolidateJob("user-1")).toEqual({
name: "profile.consolidate",
payload: { userId: "user-1" },
replaceKey: profileConsolidateJobKey("user-1"),
});
expect(profileConsolidateJobKey("user-1")).not.toBe(profileConsolidateJobKey("user-2"));
});
});
describe("mediaRunJob", () => {
it("validates, dispatches, and runs every media job on the shared media queue", async () => {
const target = handlers();
await dispatchBackgroundJob(target, "media.run", { jobId: "job-1" });
expect(target["media.run"]).toHaveBeenCalledWith({ jobId: "job-1" });
expect(() => parseBackgroundJob("media.run", { jobId: "" })).toThrow();
expect(mediaRunJob("job-1")).toEqual({
name: "media.run",
payload: { jobId: "job-1" },
replaceKey: mediaRunJobKey("job-1"),
queue: MEDIA_JOB_QUEUE,
});
const at = new Date("2026-10-03T12:00:00.000Z");
expect(mediaRunJob("job-1", at).availableAt).toBe(at);
expect(mediaRunJobKey("job-1")).not.toBe(mediaRunJobKey("job-2"));
});
});
describe("mediaLibrarySyncJob", () => {
it("validates, dispatches, and keeps one pending sync per folder on the library queue", async () => {
const target = handlers();
await dispatchBackgroundJob(target, "media.library.sync", { sourceId: "source-1" });
expect(target["media.library.sync"]).toHaveBeenCalledWith({ sourceId: "source-1" });
expect(() => parseBackgroundJob("media.library.sync", { sourceId: "" })).toThrow();
const at = new Date("2026-10-05T12:00:00.000Z");
expect(mediaLibrarySyncJob("source-1", at)).toEqual({
name: "media.library.sync",
payload: { sourceId: "source-1" },
replaceKey: mediaLibrarySyncJobKey("source-1"),
queue: MEDIA_LIBRARY_JOB_QUEUE,
availableAt: at,
});
expect(mediaLibrarySyncJob("source-1").availableAt).toBeUndefined();
});
});