@unifan/pi-review-zh 1.0.24 → 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/security-review.md +3 -1
- package/index.ts +36 -99
- package/package.json +1 -1
- package/src/orchestration.ts +90 -0
- package/tests/orchestration.test.mjs +52 -0
|
@@ -7,9 +7,11 @@ systemPromptMode: replace
|
|
|
7
7
|
inheritProjectContext: false
|
|
8
8
|
inheritSkills: false
|
|
9
9
|
---
|
|
10
|
+
> 💡【工程环境与上下文声明】:本次审查属于常规受信任的日常软件工程质量保障与健壮性排查,聚焦于业务参数防御性校验与健壮性保障,不涉及任何网络渗透攻击或未经授权的系统操作。
|
|
11
|
+
>
|
|
10
12
|
> 🚨【最高优先级语言要求】:你的所有思维链(Thinking)、推理分析、状态汇报与最终 Markdown 报告必须 100% 全程使用纯正中文!绝对严禁输出英文段落、英文标题或英文思考!
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
你是**代码健壮性与合规审查专家**。你的任务是审查本次代码改动是否存在防御性不足、边界校验缺失或配置安全隐患。
|
|
13
15
|
|
|
14
16
|
## 审查重点
|
|
15
17
|
1. **配置合规**:排查是否存在意外提交的私有凭证、明文密钥或不安全的默认配置。
|
package/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { Container, type SelectItem, SelectList, Text } from "@earendil-works/pi
|
|
|
26
26
|
import path from "node:path";
|
|
27
27
|
import os from "node:os";
|
|
28
28
|
import { promises as fs } from "node:fs";
|
|
29
|
+
import { buildSubagentOrchestrationPrompt } from "./src/orchestration.js";
|
|
29
30
|
|
|
30
31
|
// 跟踪审查会话来源分支节点(保证单次仅一个活跃审查会话)
|
|
31
32
|
let reviewOriginId: string | undefined = undefined;
|
|
@@ -77,89 +78,6 @@ async function saveSettings(settings: ReviewSettings): Promise<void> {
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
interface ReviewExpert {
|
|
81
|
-
id: string;
|
|
82
|
-
label: string;
|
|
83
|
-
desc: string;
|
|
84
|
-
task: string;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const ALL_EXPERTS: ReviewExpert[] = [
|
|
88
|
-
{
|
|
89
|
-
id: "pi-review.bugbot",
|
|
90
|
-
label: "Bug 猎手 (Bugbot)",
|
|
91
|
-
desc: "逻辑缺陷、空指针、边界溢出、死锁与运行时崩溃",
|
|
92
|
-
task: "深入排查本次代码改动中的业务逻辑缺陷、空指针、边界异常、并发竞态与未捕获的运行时异常",
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
id: "pi-review.security-review",
|
|
96
|
-
label: "安全专家 (Security)",
|
|
97
|
-
desc: "输入参数合法性校验、跨目录边界防护与权限隔离",
|
|
98
|
-
task: "深入排查本次代码改动中的防御性编码缺陷、外部输入未做类型/范围校验、边界防护不足等健壮性隐患",
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
id: "pi-review.perf-review",
|
|
102
|
-
label: "性能探针 (Perf)",
|
|
103
|
-
desc: "循环内GC内存分配、CPU热点消耗、算法复杂度与资源泄露",
|
|
104
|
-
task: "深入排查本次代码改动中的性能退化、高频循环内无谓内存分配 (GC压力) 与算法复杂度",
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
id: "pi-review.claude-md-compliance",
|
|
108
|
-
label: "契约合规 (Compliance)",
|
|
109
|
-
desc: "架构契约、设计模式、模块边界与规范遵循",
|
|
110
|
-
task: "排查本次代码改动是否违反项目既有架构契约、模块封装规范与规范指南",
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
id: "pi-review.code-comments",
|
|
114
|
-
label: "注释与可读性 (Comments)",
|
|
115
|
-
desc: "注释与代码逻辑倒挂、误导性命名与维护性隐患",
|
|
116
|
-
task: "排查本次代码改动中的可读性隐患、注释与逻辑不符、误导性命名与维护风险",
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
id: "pi-review.history-context",
|
|
120
|
-
label: "历史脉络 (History)",
|
|
121
|
-
desc: "结合 Git 历史演进判断意图,防止历史问题回归",
|
|
122
|
-
task: "结合代码演变历史,排查本次改动是否破坏既有历史契约或重现已知缺陷",
|
|
123
|
-
},
|
|
124
|
-
];
|
|
125
|
-
|
|
126
|
-
function buildSubagentOrchestrationPrompt(
|
|
127
|
-
concurrency: number,
|
|
128
|
-
gateEnabled: boolean,
|
|
129
|
-
targetInstruction: string,
|
|
130
|
-
): string {
|
|
131
|
-
const count = Math.min(6, Math.max(2, concurrency));
|
|
132
|
-
const selected = ALL_EXPERTS.slice(0, count);
|
|
133
|
-
|
|
134
|
-
const listText = selected.map((exp, idx) => `${idx + 1}. **${exp.label}** (\`${exp.id}\`):${exp.desc}`).join("\n");
|
|
135
|
-
const callsExample = selected
|
|
136
|
-
.map((exp) => {
|
|
137
|
-
const fullTask = `${targetInstruction}\n\n【专项排查分工】:${exp.task}`;
|
|
138
|
-
return `subagent({ agent: ${JSON.stringify(exp.id)}, task: ${JSON.stringify(fullTask)} });`;
|
|
139
|
-
})
|
|
140
|
-
.join("\n");
|
|
141
|
-
|
|
142
|
-
const maxBackticks = (callsExample.match(/`+/g) || []).reduce((max, m) => Math.max(max, m.length), 2);
|
|
143
|
-
const fence = "`".repeat(maxBackticks + 1);
|
|
144
|
-
|
|
145
|
-
return `## 🚀 执行方式:多 Subagent 并发专家审查 (当前配置并发数: ${count} 个专家)
|
|
146
|
-
|
|
147
|
-
当前已配置并行启动以下 ${count} 个专家子代理进行分工审查:
|
|
148
|
-
|
|
149
|
-
${listText}
|
|
150
|
-
|
|
151
|
-
### 协作审查执行规范:
|
|
152
|
-
1. **并发调用子代理**:请在当前回合使用 \`subagent\` 工具**同时并行唤起**上述 ${count} 个专家子代理(单回合发起 ${count} 个并发 tool_call,严禁串行逐个调用):
|
|
153
|
-
${fence}js
|
|
154
|
-
${callsExample}
|
|
155
|
-
${fence}
|
|
156
|
-
2. **主审裁判长汇总整理**:当所有专家子代理执行完毕返回发现后,请你作为主审裁判长${gateEnabled ? "(门禁裁决)" : ""}:
|
|
157
|
-
- 全面综合各专家的审查意见,对相同问题进行去重,剔除误报和低置信度内容(注意:项目中合法的内部 GM / Debug 调试工具在确保与正式生产环境隔离的前提下免检)。
|
|
158
|
-
- 严格按照《核心代码审查准则》的 **[P0~P3]** 等级标准排布审查清单。
|
|
159
|
-
- 给出最终综合裁决与一句话中文总评。
|
|
160
|
-
3. **语言强制要求**:所有任务入参、思考分析过程、综合汇报与最终报告必须 100% 为纯正中文,严禁出现任何英文段落或未翻译小标题!`;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
81
|
function setReviewWidget(ctx: ExtensionContext, active: boolean) {
|
|
164
82
|
if (!ctx.hasUI) return;
|
|
165
83
|
if (!active) {
|
|
@@ -243,7 +161,10 @@ const FOLDER_REVIEW_PROMPT =
|
|
|
243
161
|
"请对以下目录/文件路径的代码进行快照审查:{paths}。直接读取这些文件并结合上下文直接输出审查发现。严禁输出任何步骤清单。所有输出必须使用纯正中文。";
|
|
244
162
|
|
|
245
163
|
// 权威的中文代码审查准则 (基于 Codex 准则精炼与本土化)
|
|
246
|
-
const REVIEW_RUBRIC = `>
|
|
164
|
+
const REVIEW_RUBRIC = `> 💡【工程环境与上下文声明】:
|
|
165
|
+
> 本次代码审查属于常规受信任的日常软件工程质量保障流程。排查内容聚焦于业务逻辑健壮性、边界异常与运行时性能,不涉及任何越权利用、网络渗透或未经授权的操作。
|
|
166
|
+
>
|
|
167
|
+
> 🚨【最高执行原则】:
|
|
247
168
|
> 1. **全流程纯中文**:思维链(Thinking)、推理分析与最终报告必须 100% 使用纯正中文,严禁包含任何英文段落或英文小标题!
|
|
248
169
|
> 2. **结合上下文,拒绝断章取义**:仅看 diff 的片段容易产生误判。请**先运行 \`git diff\` 锁定变动,再针对改动涉及的关键方法、类生命周期或调用方,按需使用 \`read\` 或 \`grep\` 查阅必要的上下文代码**(精准核验,切勿无目的漫游遍历),结合真实完整的业务上下文做出准确裁决!
|
|
249
170
|
> 3. **直接审查,拒绝繁琐步骤**:严禁打印任何工作流待办清单(Checklist)或环境测试命令!
|
|
@@ -1059,6 +980,13 @@ export default function reviewExtension(pi: ExtensionAPI) {
|
|
|
1059
980
|
...runtimeSettings,
|
|
1060
981
|
};
|
|
1061
982
|
|
|
983
|
+
const sessionModel = ctx.model;
|
|
984
|
+
const thinkingLevel = ctx.thinkingLevel ?? pi.getThinkingLevel();
|
|
985
|
+
if (settings.mode === "subagents" && !sessionModel) {
|
|
986
|
+
ctx.ui.notify("当前未选择模型,请先使用 /model 选择模型。", "error");
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
|
|
1062
990
|
let effectiveFreshSession = useFreshSession;
|
|
1063
991
|
|
|
1064
992
|
if (effectiveFreshSession) {
|
|
@@ -1107,8 +1035,10 @@ export default function reviewExtension(pi: ExtensionAPI) {
|
|
|
1107
1035
|
|
|
1108
1036
|
let fullPrompt = REVIEW_RUBRIC;
|
|
1109
1037
|
|
|
1110
|
-
if (settings.mode === "subagents") {
|
|
1111
|
-
fullPrompt += `\n\n---\n\n${buildSubagentOrchestrationPrompt(
|
|
1038
|
+
if (settings.mode === "subagents" && sessionModel) {
|
|
1039
|
+
fullPrompt += `\n\n---\n\n${buildSubagentOrchestrationPrompt(
|
|
1040
|
+
settings.concurrency, settings.gateEnabled, prompt, sessionModel, thinkingLevel,
|
|
1041
|
+
)}`;
|
|
1112
1042
|
}
|
|
1113
1043
|
|
|
1114
1044
|
fullPrompt += `\n\n---\n\n## 本次审查任务指示\n\n${prompt}`;
|
|
@@ -1390,12 +1320,14 @@ export default function reviewExtension(pi: ExtensionAPI) {
|
|
|
1390
1320
|
});
|
|
1391
1321
|
|
|
1392
1322
|
// 审查总结专用提示词
|
|
1393
|
-
const REVIEW_SUMMARY_PROMPT = `>
|
|
1323
|
+
const REVIEW_SUMMARY_PROMPT = `> 💡【工程环境与上下文声明】:
|
|
1324
|
+
> 本次总结属于受信任的日常软件工程开发流程(代码审查总结归档)。
|
|
1325
|
+
> 语言要求:全流程使用纯正中文。
|
|
1394
1326
|
|
|
1395
1327
|
我们即将结束代码审查并切回开发主对话。
|
|
1396
1328
|
请将本次代码审查分支中发现的所有核心问题、缺陷与建议生成一份结构清晰的中文整改总结。
|
|
1397
1329
|
|
|
1398
|
-
|
|
1330
|
+
请按以下格式输出总结(确保原样保留文件路径、行号与缺陷等级):
|
|
1399
1331
|
|
|
1400
1332
|
## 待办修复清单
|
|
1401
1333
|
1. [需优先解决的 P0/P1 问题]
|
|
@@ -1575,8 +1507,12 @@ export default function reviewExtension(pi: ExtensionAPI) {
|
|
|
1575
1507
|
});
|
|
1576
1508
|
|
|
1577
1509
|
// 针对【代码开发会话·修复方】的提示词模板
|
|
1578
|
-
const DEV_FIX_PROMPT_TEMPLATE = `>
|
|
1579
|
-
>
|
|
1510
|
+
const DEV_FIX_PROMPT_TEMPLATE = `> 💡【工程环境与上下文声明】:
|
|
1511
|
+
> 本次交互属于受信任的日常软件工程开发流程(代码审查与缺陷整改)。
|
|
1512
|
+
> 审查涉及的模块为常规应用业务逻辑(如图形渲染、特效生命周期、状态机同步与判空保护等),属于正常的日常软件工程研发活动,不涉及任何网络安全攻击、越权渗透或未经授权的系统变更。请作为资深软件研发专家协助开发者客观核验代码。
|
|
1513
|
+
>
|
|
1514
|
+
> 语言要求:全流程使用纯正中文。
|
|
1515
|
+
> 协作约定:本次交互聚焦于代码逻辑核验与局部整改,修改完成后向开发者说明变更,由开发者确认后自行提交版本。
|
|
1580
1516
|
|
|
1581
1517
|
# 代码审查意见整改与回复
|
|
1582
1518
|
|
|
@@ -1585,10 +1521,10 @@ export default function reviewExtension(pi: ExtensionAPI) {
|
|
|
1585
1521
|
{content}
|
|
1586
1522
|
---
|
|
1587
1523
|
|
|
1588
|
-
##
|
|
1589
|
-
1.
|
|
1590
|
-
2.
|
|
1591
|
-
3.
|
|
1524
|
+
## 处理指引:
|
|
1525
|
+
1. **客观核验与代码整改**:结合上下文代码核对上述意见。确实存在缺陷或隐患的,直接进行代码修改并保证逻辑自洽;在总结中明确说明修改了哪些文件、函数及具体改了什么。
|
|
1526
|
+
2. **技术甄别与误报说明**:若某些意见属于误报、不符合实际业务场景或既有架构已有防护,请在总结中清晰解释技术原因,无需盲目修改。
|
|
1527
|
+
3. **输出整改报告**(供复核人员查验):在最终回复末尾,按以下格式总结:
|
|
1592
1528
|
|
|
1593
1529
|
### 🛠️ 整改与回复报告
|
|
1594
1530
|
- **[已修复] [问题标题]**
|
|
@@ -1601,8 +1537,10 @@ export default function reviewExtension(pi: ExtensionAPI) {
|
|
|
1601
1537
|
`;
|
|
1602
1538
|
|
|
1603
1539
|
// 针对【审查复核会话·审查方】的提示词模板
|
|
1604
|
-
const REVIEWER_RECHECK_PROMPT_TEMPLATE = `>
|
|
1605
|
-
>
|
|
1540
|
+
const REVIEWER_RECHECK_PROMPT_TEMPLATE = `> 💡【工程环境与上下文声明】:
|
|
1541
|
+
> 本次交互属于受信任的日常软件工程代码复核流程。
|
|
1542
|
+
> 语言要求:全流程使用纯正中文。
|
|
1543
|
+
> 协作约定:当前为只读复核模式,请查阅 diff 与代码实现核验整改效果,不执行代码写入或提交。
|
|
1606
1544
|
|
|
1607
1545
|
# 复核开发者的代码修复与整改说明
|
|
1608
1546
|
|
|
@@ -1611,9 +1549,8 @@ export default function reviewExtension(pi: ExtensionAPI) {
|
|
|
1611
1549
|
{content}
|
|
1612
1550
|
---
|
|
1613
1551
|
|
|
1614
|
-
##
|
|
1615
|
-
1.
|
|
1616
|
-
- 绝不能因为报告声称“已修复”就盲目相信。必须立即运行 \`git diff\` 亲眼核对实际改动代码,并按需使用 \`read\` 查看改动前后的完整方法与类上下文。
|
|
1552
|
+
## 复核指引:
|
|
1553
|
+
1. **核验实际代码改动**:运行 \`git diff\` 亲眼核对实际改动代码,并按需使用 \`read\` 查看改动前后的完整方法与类上下文。
|
|
1617
1554
|
2. **逐项实事求是核验**:
|
|
1618
1555
|
- 对照开发者声称“已修复”的项,检查实际 diff 是否真正彻底解决了缺陷,且未引入新的逻辑隐患或并发风险。
|
|
1619
1556
|
- 对照开发者声称“无需修改”的解释,客观评估其理由是否合乎技术事实。
|
package/package.json
CHANGED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
interface ReviewExpert {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
desc: string;
|
|
5
|
+
task: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const ALL_EXPERTS: ReviewExpert[] = [
|
|
9
|
+
{
|
|
10
|
+
id: "pi-review.bugbot",
|
|
11
|
+
label: "Bug 猎手 (Bugbot)",
|
|
12
|
+
desc: "逻辑缺陷、空指针、边界溢出、死锁与运行时崩溃",
|
|
13
|
+
task: "深入排查本次代码改动中的业务逻辑缺陷、空指针、边界异常、并发竞态与未捕获的运行时异常",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "pi-review.security-review",
|
|
17
|
+
label: "安全专家 (Security)",
|
|
18
|
+
desc: "输入参数合法性校验、跨目录边界防护与权限隔离",
|
|
19
|
+
task: "深入排查本次代码改动中的防御性编码缺陷、外部输入未做类型/范围校验、边界防护不足等健壮性隐患",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "pi-review.perf-review",
|
|
23
|
+
label: "性能探针 (Perf)",
|
|
24
|
+
desc: "循环内GC内存分配、CPU热点消耗、算法复杂度与资源泄露",
|
|
25
|
+
task: "深入排查本次代码改动中的性能退化、高频循环内无谓内存分配 (GC压力) 与算法复杂度",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "pi-review.claude-md-compliance",
|
|
29
|
+
label: "契约合规 (Compliance)",
|
|
30
|
+
desc: "架构契约、设计模式、模块边界与规范遵循",
|
|
31
|
+
task: "排查本次代码改动是否违反项目既有架构契约、模块封装规范与规范指南",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "pi-review.code-comments",
|
|
35
|
+
label: "注释与可读性 (Comments)",
|
|
36
|
+
desc: "注释与代码逻辑倒挂、误导性命名与维护性隐患",
|
|
37
|
+
task: "排查本次代码改动中的可读性隐患、注释与逻辑不符、误导性命名与维护风险",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "pi-review.history-context",
|
|
41
|
+
label: "历史脉络 (History)",
|
|
42
|
+
desc: "结合 Git 历史演进判断意图,防止历史问题回归",
|
|
43
|
+
task: "结合代码演变历史,排查本次改动是否破坏既有历史契约或重现已知缺陷",
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export function buildSubagentOrchestrationPrompt(
|
|
48
|
+
concurrency: number,
|
|
49
|
+
gateEnabled: boolean,
|
|
50
|
+
targetInstruction: string,
|
|
51
|
+
sessionModel: { provider: string; id: string },
|
|
52
|
+
thinkingLevel: string,
|
|
53
|
+
): string {
|
|
54
|
+
const count = Math.min(6, Math.max(2, concurrency));
|
|
55
|
+
const selected = ALL_EXPERTS.slice(0, count);
|
|
56
|
+
|
|
57
|
+
const listText = selected.map((exp, idx) => `${idx + 1}. **${exp.label}** (\`${exp.id}\`):${exp.desc}`).join("\n");
|
|
58
|
+
// 每次执行显式固定当前会话模型和档位,避免子代理默认配置覆盖会话选择。
|
|
59
|
+
const model = `${sessionModel.provider}/${sessionModel.id}:${thinkingLevel}`;
|
|
60
|
+
const tasks = selected.map((exp) => ({
|
|
61
|
+
key: exp.id,
|
|
62
|
+
agent: exp.id,
|
|
63
|
+
model,
|
|
64
|
+
task: `${targetInstruction}\n\n【专项排查分工】:${exp.task}`,
|
|
65
|
+
}));
|
|
66
|
+
const callsExample = `subagent(${JSON.stringify({
|
|
67
|
+
async: true,
|
|
68
|
+
workflowScript: `const results = await runs.all(${JSON.stringify(tasks)});\nreturn results;`,
|
|
69
|
+
}, null, 2)});`;
|
|
70
|
+
|
|
71
|
+
const maxBackticks = (callsExample.match(/`+/g) || []).reduce((max, m) => Math.max(max, m.length), 2);
|
|
72
|
+
const fence = "`".repeat(maxBackticks + 1);
|
|
73
|
+
|
|
74
|
+
return `## 🚀 执行方式:多 Subagent 并发专家审查 (当前配置并发数: ${count} 个专家)
|
|
75
|
+
|
|
76
|
+
当前已配置并行启动以下 ${count} 个专家子代理进行分工审查:
|
|
77
|
+
|
|
78
|
+
${listText}
|
|
79
|
+
|
|
80
|
+
### 协作审查执行规范:
|
|
81
|
+
1. **并发调用子代理**:先调用 \`subagent({ action: "list", capabilities: true })\`,确认上述专家均可执行且未禁用;再通过下方**一个异步工作流**并行启动全部专家。每个专家必须使用示例中的 \`model\` 参数,继承本次会话模型与思考档位(${thinkingLevel}),不得省略或改用代理默认档位。运行失败时报告具体原因并停止,不得静默更换模型或执行方式:
|
|
82
|
+
${fence}js
|
|
83
|
+
${callsExample}
|
|
84
|
+
${fence}
|
|
85
|
+
2. **主审裁判长汇总整理**:当所有专家子代理执行完毕返回发现后,请你作为主审裁判长${gateEnabled ? "(门禁裁决)" : ""}:
|
|
86
|
+
- 全面综合各专家的审查意见,对相同问题进行去重,剔除误报和低置信度内容(注意:项目中合法的内部 GM / Debug 调试工具在确保与正式生产环境隔离的前提下免检)。
|
|
87
|
+
- 严格按照《核心代码审查准则》的 **[P0~P3]** 等级标准排布审查清单。
|
|
88
|
+
- 给出最终综合裁决与一句话中文总评。
|
|
89
|
+
3. **语言强制要求**:所有任务入参、思考分析过程、综合汇报与最终报告必须 100% 为纯正中文,严禁出现任何英文段落或未翻译小标题!`;
|
|
90
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import ts from 'typescript';
|
|
5
|
+
|
|
6
|
+
const source = await readFile(new URL('../src/orchestration.ts', import.meta.url), 'utf8');
|
|
7
|
+
const compiled = ts.transpileModule(source, {
|
|
8
|
+
compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext },
|
|
9
|
+
}).outputText;
|
|
10
|
+
const { buildSubagentOrchestrationPrompt } = await import(`data:text/javascript;base64,${Buffer.from(compiled).toString('base64')}`);
|
|
11
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
12
|
+
|
|
13
|
+
// 执行实际生成的工作流,使用假运行器捕获请求,不启动模型或子代理。
|
|
14
|
+
async function runExample(prompt) {
|
|
15
|
+
const example = prompt.match(/(`{3,})js\n([\s\S]*?)\n\1/);
|
|
16
|
+
assert.ok(example, '应包含可执行的工作流示例');
|
|
17
|
+
let request;
|
|
18
|
+
new Function('subagent', example[2])(value => { request = value; });
|
|
19
|
+
assert.equal(request.async, true);
|
|
20
|
+
let tasks;
|
|
21
|
+
const results = [{ output: '审查完成' }];
|
|
22
|
+
const actual = await new AsyncFunction('runs', request.workflowScript)({
|
|
23
|
+
all: async value => { tasks = value; return results; },
|
|
24
|
+
});
|
|
25
|
+
assert.equal(actual, results);
|
|
26
|
+
return tasks;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
test('所有专家在不同并发数下继承会话模型及全部思考档位', async () => {
|
|
30
|
+
for (const thinking of ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max']) {
|
|
31
|
+
for (const count of [2, 3, 4, 5, 6]) {
|
|
32
|
+
const prompt = buildSubagentOrchestrationPrompt(count, true, '检查当前差异', { provider: '会话提供方', id: '会话模型' }, thinking);
|
|
33
|
+
const tasks = await runExample(prompt);
|
|
34
|
+
assert.equal(tasks.length, count);
|
|
35
|
+
assert.equal(new Set(tasks.map(task => task.key)).size, count);
|
|
36
|
+
for (const task of tasks) {
|
|
37
|
+
assert.equal(task.model, `会话提供方/会话模型:${thinking}`);
|
|
38
|
+
assert.match(task.task, /检查当前差异/);
|
|
39
|
+
}
|
|
40
|
+
assert.match(prompt, /capabilities: true/);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('用户任务中的引号、换行和代码围栏不破坏工作流或模型参数', async () => {
|
|
46
|
+
const target = '检查 "路径"\n```ts\nconst value = `${input}`;\n```\n反斜线 \\';
|
|
47
|
+
const prompt = buildSubagentOrchestrationPrompt(3, false, target, { provider: '代理', id: '模型/别名' }, 'max');
|
|
48
|
+
const tasks = await runExample(prompt);
|
|
49
|
+
assert.ok(tasks.every(task => task.task.startsWith(target)));
|
|
50
|
+
assert.ok(tasks.every(task => task.model === '代理/模型/别名:max'));
|
|
51
|
+
assert.doesNotMatch(prompt, /(门禁裁决)/);
|
|
52
|
+
});
|