import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { createCapabilityRegistry } from "../../src/modules/agent/capability-registry.ts"; import { registerScheduleCapabilities } from "../../src/modules/schedules/capabilities.ts"; import { createHarness, type Harness, pgAvailable } from "../sources-identity/harness.ts"; // schedule.draft_check:智能体按对话起草巡检 → 建成未启用的 agent_check;只读能力白名单;只放行用户发起的对话 const pg = await pgAvailable(); // biome-ignore lint/suspicious/noExplicitAny: 能力输出按 schema 校验过,测试里直接取字段 type Any = any; describe.skipIf(!pg)("起草巡检能力(真实 PG)", () => { let h: Harness; beforeAll(async () => { h = await createHarness("draftcheck"); const registry = createCapabilityRegistry({ logger: h.ctx.logger, db: h.db, settings: h.ctx.settings }); registerScheduleCapabilities(registry, h.ctx); (h.ctx as { capabilities: unknown }).capabilities = registry; }, 120_000); afterAll(async () => { await h?.close(); }); const run = async (trigger: "user" | "schedule") => ( await h.db .insertInto("agent_run") .values({ trigger, goal: "起草巡检", status: "running", mode: "execute" } as never) .returning("id") .executeTakeFirstOrThrow() ).id; const invoke = (input: Record, agentRunId: string) => h.ctx.capabilities.invoke("schedule.draft_check", input, { actorId: "agent", taskId: crypto.randomUUID(), agentRunId, scopeIds: [], signal: new AbortController().signal, source: "agent", }) as Promise; const input = { name: "失败下载日报", goal: "检查下载器里失败或卡住的任务,有就写一段话汇报", everyHours: 24, capabilities: ["download.list", "downloader.list", "download.submit", "not.exists"], triggerCondition: "stalled_downloads", reportAsDecision: true, }; it("对话里起草:建成未启用的巡检;写入 / 不存在的能力去掉", async () => { const out = await invoke(input, await run("user")); expect(out).toMatchObject({ enabled: false, capabilities: ["download.list", "downloader.list"], dropped: ["download.submit", "not.exists"], }); const job = await h.db .selectFrom("scheduled_job") .selectAll() .where("id", "=", out.jobId) .executeTakeFirstOrThrow(); expect(job).toMatchObject({ kind: "agent_check", enabled: false, builtin: false, name: "失败下载日报" }); expect(job.schedule).toMatchObject({ type: "interval", everyMs: 24 * 3600_000 }); expect(job.config).toMatchObject({ goalTemplate: input.goal, capabilityAllowlist: ["download.list", "downloader.list"], triggerCondition: "stalled_downloads", reportAsDecision: true, }); }); it("定时巡检的会话里不能再起草巡检", async () => { const before = await h.db.selectFrom("scheduled_job").select("id").execute(); await expect(invoke(input, await run("schedule"))).rejects.toThrow(/用户发起的对话/); expect(await h.db.selectFrom("scheduled_job").select("id").execute()).toHaveLength(before.length); }); });