feat(agent): 用对话起草巡检(schedule.draft_check + 起草巡检 Skill + 计划页入口与对话卡片)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
8eb8a68295
commit
7c4ad901d9
14 files changed
+408
-7
No files matched your search
@@ -0,0 +1,56 @@
|
||||
import { CapabilityError, type CapabilityRegistry } from "@umt/agent";
|
||||
import { CAPABILITY_CATALOG, capabilitySpec, KnownCapabilityId } from "@umt/contracts";
|
||||
import type { ServerContext } from "../types.ts";
|
||||
import { createAgentCheck } from "./store.ts";
|
||||
|
||||
// schedule.draft_check:智能体按用户的自然语言需求起草巡检。建成「未启用」,不会自己运行;
|
||||
// 用户在计划页检查、修改后再启用(授权只放行用户发起的对话,见 agent/authorize.ts)。
|
||||
|
||||
/** 巡检只开放只读 / 预览 / 提案类能力(与计划页表单一致),且不能再起草巡检 */
|
||||
const ALLOWED = new Set(
|
||||
Object.values(CAPABILITY_CATALOG)
|
||||
.filter((c) => ["read", "preview", "propose"].includes(c.kind) && c.id !== "schedule.draft_check")
|
||||
.map((c) => c.id as string),
|
||||
);
|
||||
|
||||
export function registerScheduleCapabilities(registry: CapabilityRegistry, ctx: ServerContext): void {
|
||||
registry.register(capabilitySpec("schedule.draft_check"), async (input) => {
|
||||
const asked = [...new Set(input.capabilities ?? [])];
|
||||
const caps = asked.filter((c) => KnownCapabilityId.safeParse(c).success && ALLOWED.has(c));
|
||||
const dropped = asked.filter((c) => !caps.includes(c));
|
||||
let row: Awaited<ReturnType<typeof createAgentCheck>>;
|
||||
try {
|
||||
row = await createAgentCheck(
|
||||
ctx.db,
|
||||
{
|
||||
name: input.name,
|
||||
description: "智能体按对话起草",
|
||||
enabled: false,
|
||||
schedule: { type: "interval", everyMs: Math.round(input.everyHours * 3600_000) },
|
||||
config: {
|
||||
goalTemplate: input.goal,
|
||||
capabilityAllowlist: caps as KnownCapabilityId[],
|
||||
budget: {
|
||||
...(input.maxToolCalls ? { maxToolCalls: input.maxToolCalls } : {}),
|
||||
...(input.maxDurationSec ? { maxDurationSec: input.maxDurationSec } : {}),
|
||||
},
|
||||
triggerCondition: input.triggerCondition ?? "always",
|
||||
reportAsDecision: input.reportAsDecision ?? false,
|
||||
},
|
||||
},
|
||||
new Date(),
|
||||
);
|
||||
} catch (e) {
|
||||
throw new CapabilityError("precondition", `巡检没建成:${(e as Error).message}`);
|
||||
}
|
||||
return {
|
||||
jobId: row.id,
|
||||
name: row.name,
|
||||
everyHours: input.everyHours,
|
||||
capabilities: caps,
|
||||
dropped,
|
||||
enabled: false as const,
|
||||
next: "已建成未启用的巡检。请用户到「计划」页检查目标、间隔和能力,确认后打开开关启用。",
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ServerContext, ServerModule } from "../types.ts";
|
||||
import { builtinAgentCheckDefs } from "./agent-checks.ts";
|
||||
import { registerScheduleCapabilities } from "./capabilities.ts";
|
||||
import { registerScheduledJob, scheduleRegistry } from "./registry.ts";
|
||||
import { registerScheduleRoutes } from "./routes.ts";
|
||||
import { Scheduler, type SchedulerOptions } from "./scheduler.ts";
|
||||
@@ -30,6 +31,9 @@ export function createSchedulesModule(opts: SchedulesModuleOptions = {}): Server
|
||||
registerScheduleRoutes(app, ctx, () => scheduleRegistry(ctx));
|
||||
},
|
||||
registerTasks() {},
|
||||
registerCapabilities(registry, ctx) {
|
||||
registerScheduleCapabilities(registry, ctx);
|
||||
},
|
||||
start(ctx: ServerContext) {
|
||||
if (opts.builtinChecks !== false) for (const def of builtinAgentCheckDefs(ctx)) registerScheduledJob(ctx, def);
|
||||
// 备份目前由宿主机 scripts/backup.sh(cron / 手动)执行,这里只占位,看板上显示"未配置"
|
||||
|
||||
Reference in new issue
Block a user