feat(agent): layered system prompt, environment facts and intent-routed skills

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-30 18:47:15 +08:00
1 parent 0f20c19b7c
commit 21b7e8ff23
25 files changed
+1783 -149

No files matched your search

@@ -0,0 +1,113 @@
import {
accountName,
downloadStatusName,
healthName,
humanNow,
humanRelative,
kindName,
subscriptionStatusName,
} from "../format.ts";
import type { EnvironmentFacts, PromptSection } from "../types.ts";
// 第 2 层:环境事实。会话开始时服务端从业务表读出的摘要,让模型知道"有什么"再去查"怎么样":
// 反例(docs/design/agent-report-sample-bad.md)里模型只看了站点列表,就汇报"系统里没有下载器"。
// 只写名称、类型、状态和计数,不写地址、ID 与凭证;数字以会话开始时为准,细节仍以工具结果为准。
const MAX_NAMED = 6;
function names<T>(items: readonly T[], render: (x: T) => string): string {
const shown = items.slice(0, MAX_NAMED).map(render);
const more = items.length - shown.length;
return more > 0 ? `${shown.join(";")};另有 ${more} 个` : shown.join(";");
}
/** 计数表 → "追更中 3、已取消 2";全 0 返回空串 */
function counts(m: Record<string, number>, label: (k: string) => string): string {
return Object.entries(m)
.filter(([, n]) => n > 0)
.sort((a, b) => b[1] - a[1])
.map(([k, n]) => `${label(k)} ${n}`)
.join("、");
}
const total = (m: Record<string, number>) => Object.values(m).reduce((a, b) => a + b, 0);
export function renderEnvironment(f: EnvironmentFacts): string[] {
const now = new Date(f.now);
const tz = f.timeZone;
const rel = (iso: string | null) => humanRelative(iso, now, tz);
const lines: string[] = [`现在:${humanNow(now, tz)}。`];
const dl = f.downloaders.filter((d) => d.enabled);
if (dl.length === 0)
lines.push(
f.downloaders.length > 0
? `下载器:${f.downloaders.length} 个都已停用。`
: "下载器:还没有接入(设置 → 下载器)。",
);
else
lines.push(
`下载器 ${dl.length} 个:${names(dl, (d) => {
const seen = rel(d.lastSeenAt);
const t = d.tasks;
const tasks =
t.total > 0
? `,本工具管理 ${t.total} 个任务(进行中 ${t.active}、失败 ${t.failed})`
: ",没有本工具管理的任务";
return `「${d.name}」${kindName(d.kind)},${healthName(d.health)}${seen ? `(${seen})` : ""}${tasks}`;
})}。`,
);
const ms = f.mediaServers.filter((m) => m.enabled);
lines.push(
ms.length === 0
? "媒体服务器:还没有接入。"
: `媒体服务器 ${ms.length} 个:${names(ms, (m) => {
const seen = rel(m.lastSeenAt);
return `「${m.name}」${kindName(m.kind)},${healthName(m.health)}${seen ? `(${seen})` : ""}`;
})}。`,
);
const sites = f.sites.filter((s) => s.enabled);
lines.push(
sites.length === 0
? "站点:还没有启用的站点。"
: `站点 ${sites.length} 个:${names(sites, (s) => {
const at = rel(s.lastHealthAt);
const health =
s.health === "unknown" ? "还没检查过" : `上次检查${healthName(s.health)}${at ? `(${at})` : ""}`;
return `「${s.name}」${kindName(s.kind)},${health}${s.account ? `,${accountName(s.account)}` : ""}`;
})}。`,
);
const roots = f.libraryRoots.filter((r) => r.enabled);
lines.push(
roots.length === 0
? "媒体库目录:还没有登记。"
: `媒体库目录 ${roots.length} 个:${names(roots, (r) => `「${r.name}」${healthName(r.health)}`)}。`,
);
const subs = total(f.subscriptions);
lines.push(subs === 0 ? "订阅:没有。" : `订阅 ${subs} 个:${counts(f.subscriptions, subscriptionStatusName)}。`);
const dls = total(f.downloads);
lines.push(
dls === 0
? "下载任务(本工具管理):没有。"
: `下载任务(本工具管理)${dls} 个:${counts(f.downloads, downloadStatusName)}。`,
);
lines.push(f.openDecisions === 0 ? "待处理事项:没有。" : `待处理事项:${f.openDecisions} 条未关闭。`);
if (f.webSearch !== undefined) lines.push(f.webSearch ? "网页搜索:已开启。" : "网页搜索:未开启。");
return lines;
}
export function environmentLayer(f: EnvironmentFacts | null | undefined): PromptSection {
if (!f) return { layer: "environment", title: "当前环境", lines: [] };
return {
layer: "environment",
title: "当前环境",
lines: [
"会话开始时的快照,只有名称、状态和计数;要细节或最新状态用下面的能力查。这里写了「还没有接入」的就是真的没有,不用再向用户确认。",
...renderEnvironment(f).map((l) => `- ${l}`),
],
};
}