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:
1 parent
0f20c19b7c
commit
21b7e8ff23
25 files changed
+1783
-149
No files matched your search
@@ -0,0 +1,76 @@
|
||||
import { CAPABILITY_IDS } from "@umt/contracts";
|
||||
|
||||
// 汇报格式的机器核对(AG-5 评测用):fake 模型评测与真实模型评测共用。
|
||||
// 只查能机械判断的项;"结论在第一句"按开头的套话与是否含状态词近似判断。
|
||||
|
||||
export interface ReportLintIssue {
|
||||
rule:
|
||||
| "too_long"
|
||||
| "uuid"
|
||||
| "hash"
|
||||
| "raw_bytes"
|
||||
| "iso_time"
|
||||
| "internal_field"
|
||||
| "capability_id"
|
||||
| "heading"
|
||||
| "no_conclusion_first"
|
||||
| "asks_user_for_id"
|
||||
| "lecture";
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export interface ReportLintOptions {
|
||||
/** 最多几行(非空行);缺省 8 */
|
||||
maxLines?: number;
|
||||
}
|
||||
|
||||
const UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
|
||||
const HASH = /\b[0-9a-f]{40}(?:[0-9a-f]{24})?\b/i;
|
||||
/** 7 位以上的裸数字(原始字节数、原始计数);年份、日期、带千分位的不算 */
|
||||
const RAW_NUMBER = /(?<![\d.:\-/])\d{7,}(?![\d.:\-/])/;
|
||||
const ISO_TIME = /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/;
|
||||
/** 内部字段名:snake_case、camelCase 与已知的内部词 */
|
||||
const INTERNAL_WORDS =
|
||||
/\b(?:adapter|healthStatus|health_status|mediaEntityId|slotId|planId|runId|taskId|downloadTaskId|sourceReleaseId|payloadHash|idempotency|capabilityId|invocationId)\b/;
|
||||
const SNAKE = /\b[a-z]+_[a-z_]+\b/;
|
||||
const CAMEL = /\b[a-z]+[A-Z][A-Za-z]+\b/;
|
||||
/** 开头套话(结论没放第一句) */
|
||||
const WEAK_OPENERS = /^(?:#|\*\*?检查结果|检查结果|结论[::]|以下|下面|好的|当然|首先|根据|经过|我(?:已|先|查)|让我)/;
|
||||
const ASK_ID = /(?:请|麻烦)?(?:提供|给(?:我)?(?:一个)?)[^。\n]{0,12}(?:ID|hash|编号|哈希)/i;
|
||||
const LECTURE = /(?:不等于|并不代表|不能证明|无证据|建议定期|值得注意的是|需要注意的是)/;
|
||||
|
||||
/** 允许出现在汇报里的英文词(技术词保留原文) */
|
||||
const ALLOWED_TOKENS = new Set(["qBittorrent", "iPhone", "macOS"]);
|
||||
|
||||
/** 核对一段汇报;返回空数组 = 通过 */
|
||||
export function lintReport(text: string, opts: ReportLintOptions = {}): ReportLintIssue[] {
|
||||
const maxLines = opts.maxLines ?? 8;
|
||||
const issues: ReportLintIssue[] = [];
|
||||
const lines = text
|
||||
.split("\n")
|
||||
.map((l) => l.trim())
|
||||
.filter((l) => l !== "" && !/^\|?\s*:?-{3,}/.test(l));
|
||||
if (lines.length > maxLines) issues.push({ rule: "too_long", detail: `${lines.length} 行,超过 ${maxLines} 行` });
|
||||
const find = (re: RegExp) => text.match(re)?.[0];
|
||||
const hit = (rule: ReportLintIssue["rule"], re: RegExp) => {
|
||||
const m = find(re);
|
||||
if (m) issues.push({ rule, detail: m });
|
||||
};
|
||||
hit("uuid", UUID);
|
||||
hit("hash", HASH);
|
||||
hit("raw_bytes", RAW_NUMBER);
|
||||
hit("iso_time", ISO_TIME);
|
||||
hit("internal_field", INTERNAL_WORDS);
|
||||
const snake = find(SNAKE);
|
||||
if (snake) issues.push({ rule: "internal_field", detail: snake });
|
||||
const camel = text.match(new RegExp(CAMEL, "g"))?.find((w) => !ALLOWED_TOKENS.has(w));
|
||||
if (camel) issues.push({ rule: "internal_field", detail: camel });
|
||||
const cap = CAPABILITY_IDS.find((id) => text.includes(id));
|
||||
if (cap) issues.push({ rule: "capability_id", detail: cap });
|
||||
if (/^#{1,6} /m.test(text)) issues.push({ rule: "heading", detail: "用了 Markdown 标题" });
|
||||
const first = lines[0] ?? "";
|
||||
if (!first || WEAK_OPENERS.test(first)) issues.push({ rule: "no_conclusion_first", detail: first.slice(0, 40) });
|
||||
hit("asks_user_for_id", ASK_ID);
|
||||
hit("lecture", LECTURE);
|
||||
return issues;
|
||||
}
|
||||
Reference in new issue
Block a user