- snapshots only for sites with list; feed polling only for RSS kinds; user data / health checks only for sites with login; search site set only includes searchable sites; live search / snapshot skip with reason unsupported instead of hitting the site - refresh-login / credentials need login, manual snapshot needs list (400) - POST /sites accepts kind and rssUrl (site + feed in one transaction, key generated from host); RSS belongs to a site: feeds created without siteId go to the same-host custom RSS source site, siteId cannot be cleared - fix: secret name clash when a site gets a second default-named feed - command palette regrouped; agent site.list returns kind and capabilities; system prompt notes RSS lives under sites Co-Authored-By: Claude Opus 5.5 <[email protected]>
84 lines
3.9 KiB
TypeScript
84 lines
3.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { buildSystemPrompt, interactionRules, REPORT_FORMAT } from "../src/index.ts";
|
|
|
|
// AGUI-3 prompt 回归:用户在会话里看到的汇报就是模型写的文字,格式约束靠这里守住。
|
|
// 改提示词时先想清楚是否放宽了这些约束,再同步改断言。
|
|
|
|
const userPrompt = () =>
|
|
buildSystemPrompt({
|
|
role: "媒体库自动化智能体",
|
|
goal: "看看有哪些新 4K",
|
|
interaction: { plan: true, options: true, approvals: true },
|
|
});
|
|
|
|
/** 取提示词里的一节(## 标题到下一个 ## 之前) */
|
|
function section(p: string, title: string): string {
|
|
const start = p.indexOf(`## ${title}`);
|
|
if (start < 0) return "";
|
|
const rest = p.slice(start);
|
|
const next = rest.indexOf("\n## ", 3);
|
|
return next < 0 ? rest : rest.slice(0, next);
|
|
}
|
|
|
|
describe("汇报格式(AGUI-3)", () => {
|
|
it("关键约束句:结论先行、用名字不用函数名 / 字段名 / UUID、不超过 10 行、多个资源才用表格", () => {
|
|
const f = section(userPrompt(), "汇报格式");
|
|
expect(f).toMatchInlineSnapshot(`
|
|
"## 汇报格式
|
|
- 第一句写结论:做成了什么、没做成什么、为什么。
|
|
- 对象用名字:作品名、站点名、资源标题、文件名;不写函数名、工具名、字段名、参数、UUID 或 hash。
|
|
- 不超过 10 行;不复述过程,不写下一步打算,除非需要用户做什么。
|
|
- 只有列举多个资源(3 个以上的资源、任务或文件)时才用表格,其余用短句或列表。
|
|
- 可以用 Markdown 列表、表格和粗体,不写标题,不写 HTML。
|
|
"
|
|
`);
|
|
});
|
|
|
|
it("汇报格式与已有硬规则不冲突:证据写名称和数值,不再要求引用对象 ID", () => {
|
|
const p = userPrompt();
|
|
expect(p).not.toContain("对象 ID");
|
|
expect(p).toContain("写出查到的对象名称和关键数值");
|
|
// 旧的"最后用简短中文汇报…可以用 Markdown(标题…)"已换成汇报格式一节
|
|
expect(p).not.toContain("最后用简短中文汇报");
|
|
expect(REPORT_FORMAT.length).toBe(5);
|
|
});
|
|
|
|
it("子会话 / 视觉子流程汇报给父会话:不加用户汇报格式", () => {
|
|
const p = buildSystemPrompt({ role: "网页挑战处理员", goal: "过验证", audience: "agent" });
|
|
expect(p).not.toContain("## 汇报格式");
|
|
});
|
|
});
|
|
|
|
describe("工作方式(AGUI-3)", () => {
|
|
it("只在真有分歧时给方案;查询、盘点不给方案", () => {
|
|
const rules = interactionRules({ options: true }).join("\n");
|
|
expect(rules).toContain("只有真的存在分歧时");
|
|
expect(rules).toContain("只是查询、盘点或结论明确时不要给方案");
|
|
});
|
|
|
|
it("选定即批准:方案绑定计划,approvedAction 直接执行;删除、覆盖类仍单独确认;只在能审批的会话里说", () => {
|
|
const rules = interactionRules({ options: true, approvals: true }).join("\n");
|
|
expect(rules).toContain("把计划 ID 填进这个方案的 action");
|
|
expect(rules).toContain("用户选定即批准这份计划");
|
|
expect(rules).toContain("删除、覆盖类动作选定后仍会单独确认");
|
|
expect(interactionRules({ options: true }).join("\n")).not.toContain("approvedAction");
|
|
});
|
|
|
|
it("步骤标题写要做的事,不写工具名", () => {
|
|
expect(interactionRules({ plan: true }).join("\n")).toContain("不写工具名");
|
|
});
|
|
|
|
it("先看方案(/先给方案)只对本会话生效的约束句保留", () => {
|
|
expect(interactionRules({ options: true, proposeFirst: true }).join("\n")).toContain("本会话要求先看方案再执行");
|
|
});
|
|
});
|
|
|
|
describe("站点类型(IA-2)", () => {
|
|
it("RSS 属于站点,没有单独的 RSS 页;按获取方式判断能不能搜索 / 登录", () => {
|
|
const p = userPrompt();
|
|
expect(p).toContain("RSS 属于站点");
|
|
expect(p).toContain("没有单独的 RSS 页");
|
|
expect(p).toContain("自定义 RSS 源");
|
|
});
|
|
});
|