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,49 @@
|
||||
---
|
||||
name: patrol-draft
|
||||
title: 起草巡检
|
||||
description: 用户用一句话描述想定期检查的事(多久一次、查什么、怎么汇报),起草成一个未启用的巡检,交给用户在计划页检查后启用。用户说「建个巡检」「每天帮我看看…」「定时检查…」时用。
|
||||
triggers:
|
||||
- (新建|创建|起草|添加|加|建|设置|设|定)(一?个)?.{0,6}(巡检|定时检查|定时任务)
|
||||
- 每(天|日|周|晚|早|小时|隔.{1,6})(早上|晚上|上午|下午)?.{0,16}(检查|看看|看一下|巡检|汇报|提醒)
|
||||
- 定期.{0,8}(检查|看看|巡检|汇报)
|
||||
- 每(天|日|周|晚|早|隔|小时)
|
||||
- \d+\s*(个)?(小时|分钟|天)(一次)?
|
||||
capabilities:
|
||||
- schedule.draft_check
|
||||
- site.list
|
||||
- downloader.list
|
||||
- download.list
|
||||
- decision.list
|
||||
- subscription.list
|
||||
sessions: [chat]
|
||||
---
|
||||
|
||||
## 适用意图
|
||||
|
||||
- 「帮我建个巡检,每天早上看看有没有失败的下载」「每隔 6 小时检查一下站点登录」「每周汇报一次订阅追更」。
|
||||
- 只负责「起草」:建成未启用的巡检,用户检查、修改后自己启用。用户只是想现在检查一次的,不走这里(那是普通巡检)。
|
||||
|
||||
## 步骤
|
||||
|
||||
1. 从用户的话里拿出四件事:检查什么、多久一次、条件(比如「有失败下载时才看」)、要不要写成待处理事项。缺「多久一次」时按常识定(每天一次 = 24 小时),不追问。
|
||||
2. 写巡检目标(goal):第二人称、一段话,写清要查哪些对象、异常怎么判断、汇报写什么、只读不改。需要当前数量时可以用占位符 {{openDecisions}}(未关闭待处理数)、{{stalledDownloads}}(卡住的下载数)、{{activeSubscriptions}}(进行中的订阅数)、{{date}}。
|
||||
3. 选能力白名单:只挑完成目标要用的只读能力(站点看 site.list、下载器 downloader.list、下载任务 download.list、待处理 decision.list、订阅 subscription.list 等);拿不准就不填,等于全部只读能力。
|
||||
4. 触发条件:只在有待处理时看选 open_decisions,只在有卡住的下载时看选 stalled_downloads,只在有进行中订阅时看选 subscriptions_active,否则 always。
|
||||
5. 调用一次 schedule.draft_check(name 十个字以内,everyHours 用小时数)。不要重复调用;被拒绝时照实告诉用户。
|
||||
|
||||
## 需要批准
|
||||
|
||||
- schedule.draft_check 只建未启用的巡检,不会自己运行,不需要批准;启用、改间隔、删除都由用户在计划页做。
|
||||
- 只在用户发起的对话里能用,定时巡检里不能再起草巡检。
|
||||
|
||||
## 汇报模板
|
||||
|
||||
两三行:建了什么、多久一次、请用户去计划页检查后启用。被去掉的能力也提一句:
|
||||
|
||||
> 已起草巡检「失败下载日报」:每天一次,检查下载器里失败或卡住的任务,有就写成一条待处理。还没启用,请到计划页检查目标和间隔,确认后打开开关。
|
||||
|
||||
## 不要做
|
||||
|
||||
- 不要替用户启用巡检,也不要说「已开始运行」。
|
||||
- 不要把写入、删除、提交下载这类能力放进白名单:巡检只读。
|
||||
- 不要为一次性的检查起草巡检。
|
||||
@@ -101,6 +101,10 @@ export const INTENT_ROUTES: readonly IntentRoute[] = [
|
||||
{ cap: "browser.solve_challenge", note: "处理页面挑战(视觉子流程)" },
|
||||
],
|
||||
},
|
||||
{
|
||||
intent: "要建定时检查 / 巡检",
|
||||
steps: [{ cap: "schedule.draft_check", note: "建成未启用的巡检,用户在计划页检查后启用" }],
|
||||
},
|
||||
{
|
||||
intent: "改收录策略",
|
||||
steps: [
|
||||
@@ -148,7 +152,8 @@ export const GENERAL_CAPABILITIES: readonly KnownCapabilityId[] = [
|
||||
/** 需要授权(持续授权或单次审批)的能力:execute / approve / propose 类,会话交互类除外 */
|
||||
export function needsApproval(id: string): boolean {
|
||||
const d = CAPABILITY_CATALOG[id as KnownCapabilityId];
|
||||
return !!d && AUTHORIZED_KINDS.includes(d.kind) && !id.startsWith("agent.");
|
||||
// 起草巡检只建未启用的草稿,对话里直接放行(agent/authorize.ts)
|
||||
return !!d && AUTHORIZED_KINDS.includes(d.kind) && !id.startsWith("agent.") && id !== "schedule.draft_check";
|
||||
}
|
||||
|
||||
/** 通用提示(参数、检索词、站点类型) */
|
||||
|
||||
@@ -97,6 +97,8 @@ const ROUTING: [string, string][] = [
|
||||
["qB 是不是掉线了", "patrol"],
|
||||
["我订的三体更新到第几集了", "subscription-check"],
|
||||
["下载进度怎么样了", "download-diagnose"],
|
||||
["帮我建个巡检,每天早上看看有没有失败的下载", "patrol-draft"],
|
||||
["每隔 6 小时检查一下站点登录", "patrol-draft"],
|
||||
];
|
||||
|
||||
describe("按意图选择", () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { MediaAsset } from "./assets.ts";
|
||||
import { BrowserController, BrowserDownloadVerification, BrowserSnapshot } from "./browser.ts";
|
||||
import { CAPABILITY_CATALOG, type CapabilitySpec, type KnownCapabilityId } from "./capability.ts";
|
||||
import { Id, JsonObject, NonNegInt } from "./common.ts";
|
||||
import { AgentCheckTrigger } from "./schedules.ts";
|
||||
import { MediaEntity, MediaKind } from "./content.ts";
|
||||
import { AcquisitionPlan, DownloadStatus, DownloadTask, Task, TaskStatus } from "./execution.ts";
|
||||
import { EnrichmentStatus, EnrichSuggestion, EnrichUsage, ExternalEntityType, ExternalIdentity } from "./identity.ts";
|
||||
@@ -909,6 +910,37 @@ export const WebSearchTestResult = z.object({
|
||||
export type WebSearchTestResult = z.infer<typeof WebSearchTestResult>;
|
||||
|
||||
/** 能力 ID → 输入/输出 schema(server 注册处理器、agent 生成工具定义时共用) */
|
||||
// ── schedule.draft_check:按自然语言需求起草巡检(建成未启用,用户在计划页检查后启用) ──
|
||||
|
||||
export const ScheduleDraftCheckInput = z.object({
|
||||
/** 巡检名称,10 字左右 */
|
||||
name: z.string().trim().min(1).max(60),
|
||||
/** 到点发给智能体的目标:写清检查什么、怎么汇报;可用占位符 {{now}} {{date}} {{openDecisions}} {{stalledDownloads}} {{activeSubscriptions}} */
|
||||
goal: z.string().trim().min(4).max(4000),
|
||||
/** 每隔多少小时跑一次(0.25–168) */
|
||||
everyHours: z.number().min(0.25).max(168),
|
||||
/** 需要的只读能力;不填 = 只读类全部 */
|
||||
capabilities: z.array(z.string()).max(40).optional(),
|
||||
/** 条件不满足时跳过、不唤醒模型 */
|
||||
triggerCondition: AgentCheckTrigger.optional(),
|
||||
maxToolCalls: z.number().int().min(1).max(100).optional(),
|
||||
maxDurationSec: z.number().int().min(30).max(1800).optional(),
|
||||
/** 结果写成一条待处理事项 */
|
||||
reportAsDecision: z.boolean().optional(),
|
||||
});
|
||||
export const ScheduleDraftCheckOutput = z.object({
|
||||
/** 建好的巡检(未启用) */
|
||||
jobId: z.string(),
|
||||
name: z.string(),
|
||||
everyHours: z.number(),
|
||||
capabilities: z.array(z.string()),
|
||||
/** 不能用的能力(非只读或不存在)已去掉 */
|
||||
dropped: z.array(z.string()),
|
||||
enabled: z.literal(false),
|
||||
/** 给用户的下一步 */
|
||||
next: z.string(),
|
||||
});
|
||||
|
||||
export const CAPABILITY_IO = {
|
||||
"catalog.lookup": { input: CatalogLookupInput, output: CatalogLookupOutput },
|
||||
"release.search": { input: ReleaseSearchInput, output: ReleaseSearchOutput },
|
||||
@@ -952,6 +984,7 @@ export const CAPABILITY_IO = {
|
||||
"web.fetch": { input: WebFetchInput, output: WebFetchOutput },
|
||||
"metadata.resolve_organize": { input: OrganizeMetadataInput, output: OrganizeMetadataOutput },
|
||||
"metadata.enrich": { input: MetadataEnrichInput, output: MetadataEnrichOutput },
|
||||
"schedule.draft_check": { input: ScheduleDraftCheckInput, output: ScheduleDraftCheckOutput },
|
||||
} as const satisfies Record<KnownCapabilityId, { input: z.ZodType; output: z.ZodType }>;
|
||||
|
||||
type CapabilityIo = typeof CAPABILITY_IO;
|
||||
|
||||
@@ -93,6 +93,7 @@ export const CAPABILITY_IDS = [
|
||||
"web.fetch",
|
||||
"metadata.enrich",
|
||||
"metadata.resolve_organize",
|
||||
"schedule.draft_check",
|
||||
] as const;
|
||||
export const KnownCapabilityId = z.enum(CAPABILITY_IDS);
|
||||
export type KnownCapabilityId = z.infer<typeof KnownCapabilityId>;
|
||||
@@ -604,6 +605,18 @@ export const CAPABILITY_CATALOG: Record<KnownCapabilityId, CapabilityDescriptor>
|
||||
false,
|
||||
"never",
|
||||
),
|
||||
"schedule.draft_check": d(
|
||||
"schedule.draft_check",
|
||||
"起草巡检",
|
||||
"按用户用自然语言描述的需求,建一个未启用的巡检(目标、间隔、能力白名单、触发条件、预算)。只在用户要新建定时检查 / 巡检时用;建好后由用户在计划页检查、修改并启用,不要替用户启用",
|
||||
"propose",
|
||||
"ScheduleDraftCheck",
|
||||
"admin",
|
||||
"low",
|
||||
false,
|
||||
false,
|
||||
"never",
|
||||
),
|
||||
"metadata.enrich": d(
|
||||
"metadata.enrich",
|
||||
"补全元数据",
|
||||
@@ -661,6 +674,7 @@ export const CAPABILITY_ACTIVITY: Record<KnownCapabilityId, CapabilityActivity>
|
||||
"site.health_check": act("检测", "站点", "个"),
|
||||
"site.refresh_login": act("刷新", "站点登录"),
|
||||
"site.user_data": act("查", "站点数据"),
|
||||
"schedule.draft_check": act("起草", "巡检", "个"),
|
||||
"browser.snapshot": act("读", "原站页面", "次"),
|
||||
"browser.navigate": act("打开", "原站页面", "次"),
|
||||
"browser.interact": act("操作", "原站页面", "次"),
|
||||
|
||||
Reference in new issue
Block a user