@zephyrdeng/pi-review 0.9.1 → 0.10.0
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/json-events.d.ts +1 -0
- package/dist/json-events.d.ts.map +1 -1
- package/dist/json-events.js +12 -2
- package/dist/json-events.js.map +1 -1
- package/dist/json-events.test.js +22 -0
- package/dist/json-events.test.js.map +1 -1
- package/dist/meta-footer.d.ts.map +1 -1
- package/dist/meta-footer.js +6 -1
- package/dist/meta-footer.js.map +1 -1
- package/dist/meta-footer.test.js +42 -1
- package/dist/meta-footer.test.js.map +1 -1
- package/dist/panel-aggregate.d.ts +7 -0
- package/dist/panel-aggregate.d.ts.map +1 -1
- package/dist/panel-aggregate.js +19 -1
- package/dist/panel-aggregate.js.map +1 -1
- package/dist/panel-aggregate.test.js +56 -1
- package/dist/panel-aggregate.test.js.map +1 -1
- package/dist/panel-cli.test.js +42 -0
- package/dist/panel-cli.test.js.map +1 -1
- package/dist/panel-view.d.ts.map +1 -1
- package/dist/panel-view.js +9 -3
- package/dist/panel-view.js.map +1 -1
- package/dist/panel-view.test.js +62 -0
- package/dist/panel-view.test.js.map +1 -1
- package/dist/panel.d.ts.map +1 -1
- package/dist/panel.js +9 -4
- package/dist/panel.js.map +1 -1
- package/dist/review-events.d.ts +1 -0
- package/dist/review-events.d.ts.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/extensions/panel-tool.test.ts +42 -0
- package/extensions/panel-tool.ts +3 -1
- package/extensions/rv-interactive.test.ts +179 -8
- package/extensions/rv-interactive.ts +64 -61
- package/package.json +1 -1
- package/skills/pi-review/SKILL.md +7 -6
- package/skills/pi-review/references/codex-tools.md +3 -3
- package/skills/pi-review/references/model-selection.md +2 -2
package/dist/types.d.ts
CHANGED
|
@@ -160,7 +160,10 @@ export type PanelHealth = "healthy" | "needs_human" | "blocked";
|
|
|
160
160
|
export interface ReviewerOutcome {
|
|
161
161
|
reviewerId: string;
|
|
162
162
|
role?: string;
|
|
163
|
+
/** Model explicitly configured for this reviewer (CLI flag, preset, or override). */
|
|
163
164
|
model?: string | null;
|
|
165
|
+
/** Model the provider actually reported for this reviewer's response, when known. */
|
|
166
|
+
responseModel?: string;
|
|
164
167
|
thinking?: string;
|
|
165
168
|
usage?: TokenUsage;
|
|
166
169
|
durationMs: number;
|
|
@@ -197,7 +200,10 @@ export interface PanelReviewMeta extends ReviewMeta, PanelFields {
|
|
|
197
200
|
export interface ReviewerSubmission {
|
|
198
201
|
reviewerId: string;
|
|
199
202
|
role?: string;
|
|
203
|
+
/** Model explicitly configured for this reviewer (CLI flag, preset, or override). */
|
|
200
204
|
model?: string | null;
|
|
205
|
+
/** Model the provider actually reported for this reviewer's response, when known. */
|
|
206
|
+
responseModel?: string;
|
|
201
207
|
thinking?: string;
|
|
202
208
|
usage?: TokenUsage;
|
|
203
209
|
durationMs: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -275,6 +275,48 @@ test("Pi panel result content includes duration, token, and cost metrics", () =>
|
|
|
275
275
|
assert.match(content, /\$0\.0617/);
|
|
276
276
|
});
|
|
277
277
|
|
|
278
|
+
test("panel tool reviewer summary falls back to the response model when a reviewer has no configured model", () => {
|
|
279
|
+
const content = buildPanelResultContent({
|
|
280
|
+
...createPanelViewState(),
|
|
281
|
+
meta: {
|
|
282
|
+
strategy: "panel",
|
|
283
|
+
reviewMode: "code",
|
|
284
|
+
status: "clean",
|
|
285
|
+
verdict: "approve",
|
|
286
|
+
verdictSource: "parsed",
|
|
287
|
+
findings: [],
|
|
288
|
+
actionableCount: 0,
|
|
289
|
+
durationMs: 100,
|
|
290
|
+
model: "actual/reported-model",
|
|
291
|
+
configuredReviewers: 1,
|
|
292
|
+
successfulReviewers: 1,
|
|
293
|
+
consensusPolicy: "quorum",
|
|
294
|
+
consensusThreshold: 1,
|
|
295
|
+
panelHealth: "healthy",
|
|
296
|
+
confirmedClusters: [],
|
|
297
|
+
advisories: [],
|
|
298
|
+
reviewers: [
|
|
299
|
+
{
|
|
300
|
+
reviewerId: "r1",
|
|
301
|
+
role: "Independent reviewer",
|
|
302
|
+
model: null,
|
|
303
|
+
responseModel: "actual/reported-model",
|
|
304
|
+
durationMs: 90,
|
|
305
|
+
status: "clean",
|
|
306
|
+
verdict: "approve",
|
|
307
|
+
verdictSource: "parsed",
|
|
308
|
+
contributed: true,
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
adjudicationUsed: false,
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
// Panel-level Model line (meta-footer.ts) and the reviewer summary line
|
|
315
|
+
// (panel-tool.ts fromMeta branch) both fall back to the response model.
|
|
316
|
+
assert.match(content, /Model\s+actual\/reported-model/);
|
|
317
|
+
assert.match(content, /- r1 · Independent reviewer · actual\/reported-model · clean · approve/);
|
|
318
|
+
});
|
|
319
|
+
|
|
278
320
|
test("panel tool updates and clears ambient footer status during execute", async () => {
|
|
279
321
|
const statuses: Array<string | undefined> = [];
|
|
280
322
|
let registered: { execute: (...args: any[]) => Promise<any> } | undefined;
|
package/extensions/panel-tool.ts
CHANGED
|
@@ -112,7 +112,9 @@ function reviewerSummaryLines(state: PanelViewState): string[] {
|
|
|
112
112
|
return fromMeta.map((reviewer) => {
|
|
113
113
|
const live = state.reviewers[reviewer.reviewerId];
|
|
114
114
|
const role = reviewer.role ? ` · ${reviewer.role}` : "";
|
|
115
|
-
|
|
115
|
+
// Effective model: configured model when set, else the provider-reported model.
|
|
116
|
+
const effectiveModel = reviewer.model ?? reviewer.responseModel;
|
|
117
|
+
const model = effectiveModel ? ` · ${effectiveModel}` : "";
|
|
116
118
|
const thinking = reviewer.thinking ? ` · ${reviewer.thinking}` : "";
|
|
117
119
|
const usage = reviewer.usage ? ` · ${formatTokens(reviewer.usage.totalTokens)} tok · ${formatUsage(reviewer.usage)}` : "";
|
|
118
120
|
const cost = reviewer.usage ? ` · cost ${typeof reviewer.usage.costTotal === "number" ? formatCost(reviewer.usage.costTotal) : "n/a"}` : "";
|
|
@@ -63,22 +63,28 @@ function seed(over: Partial<RvParsed> = {}): RvParsed {
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/** Push this into `selects` to simulate the user pressing Esc on that select step. */
|
|
67
|
+
const SELECT_CANCEL = "__cancel__";
|
|
68
|
+
|
|
66
69
|
function scriptedUi(answers: {
|
|
67
70
|
selects?: string[];
|
|
68
71
|
inputs?: string[];
|
|
69
72
|
confirms?: boolean[];
|
|
70
73
|
customModelPickerResults?: (string | "__skip__" | undefined)[];
|
|
71
|
-
}): InteractiveUi & { log: string[] } {
|
|
74
|
+
}): InteractiveUi & { log: string[]; confirmMessages: string[] } {
|
|
72
75
|
const selects = [...(answers.selects ?? [])];
|
|
73
76
|
const inputs = [...(answers.inputs ?? [])];
|
|
74
77
|
const confirms = [...(answers.confirms ?? [])];
|
|
75
78
|
const pickerResults = [...(answers.customModelPickerResults ?? [])];
|
|
76
79
|
const log: string[] = [];
|
|
80
|
+
const confirmMessages: string[] = [];
|
|
77
81
|
return {
|
|
78
82
|
log,
|
|
83
|
+
confirmMessages,
|
|
79
84
|
async select(title, options) {
|
|
80
85
|
log.push(`select:${title} :: ${options.slice(0, 3).join(" | ")}`);
|
|
81
|
-
|
|
86
|
+
const next = selects.length > 0 ? selects.shift() : options[0];
|
|
87
|
+
return next === SELECT_CANCEL ? undefined : next;
|
|
82
88
|
},
|
|
83
89
|
async input(title) {
|
|
84
90
|
log.push(`input:${title}`);
|
|
@@ -87,6 +93,7 @@ function scriptedUi(answers: {
|
|
|
87
93
|
async confirm(title, message) {
|
|
88
94
|
log.push(`confirm:${title}`);
|
|
89
95
|
log.push(message.split("\n")[0] ?? "");
|
|
96
|
+
confirmMessages.push(message);
|
|
90
97
|
return confirms.shift() ?? true;
|
|
91
98
|
},
|
|
92
99
|
notify(message) {
|
|
@@ -152,7 +159,7 @@ test("wizard assigns per-reviewer models through select dialogs", async () => {
|
|
|
152
159
|
"1 · host fix point (recommended)",
|
|
153
160
|
"Custom reviewer count 2–8 (r1..rN, pick models)",
|
|
154
161
|
"3",
|
|
155
|
-
"Pick
|
|
162
|
+
"Pick a model for each reviewer",
|
|
156
163
|
"openai-codex/gpt-5.6-sol",
|
|
157
164
|
"xhigh",
|
|
158
165
|
"anthropic/claude-sonnet-4-5",
|
|
@@ -162,7 +169,7 @@ test("wizard assigns per-reviewer models through select dialogs", async () => {
|
|
|
162
169
|
"quorum · at least min-agree agree (default)",
|
|
163
170
|
"2",
|
|
164
171
|
],
|
|
165
|
-
confirms: [true
|
|
172
|
+
confirms: [true],
|
|
166
173
|
});
|
|
167
174
|
|
|
168
175
|
const result = await runRvInteractiveWizard(ui, {
|
|
@@ -184,6 +191,9 @@ test("wizard assigns per-reviewer models through select dialogs", async () => {
|
|
|
184
191
|
"r2=anthropic/claude-sonnet-4-5:high",
|
|
185
192
|
"r3=openai-codex/gpt-5.6-sol:xhigh",
|
|
186
193
|
]);
|
|
194
|
+
// Confirm summary shows every reviewer's resolved model, not a raw reviewer-models dump.
|
|
195
|
+
const summary = ui.confirmMessages.at(-1) ?? "";
|
|
196
|
+
assert.match(summary, /reviewer models: r1=openai-codex\/gpt-5\.6-sol:xhigh, r2=anthropic\/claude-sonnet-4-5:high, r3=openai-codex\/gpt-5\.6-sol:xhigh/);
|
|
187
197
|
});
|
|
188
198
|
|
|
189
199
|
test("wizard keeps an explicit single-reviewer non-panel choice", async () => {
|
|
@@ -208,6 +218,9 @@ test("wizard keeps an explicit single-reviewer non-panel choice", async () => {
|
|
|
208
218
|
assert.equal(result!.reviewers, 1);
|
|
209
219
|
assert.equal(result!.panel, undefined);
|
|
210
220
|
assert.equal(result!.consensus, undefined);
|
|
221
|
+
// Single-reviewer summary keeps the `model:` line and shows the Pi default placeholder.
|
|
222
|
+
const summary = ui.confirmMessages.at(-1) ?? "";
|
|
223
|
+
assert.match(summary, /model: Pi default/);
|
|
211
224
|
});
|
|
212
225
|
|
|
213
226
|
test("wizard can use code-experts preset and shared model", async () => {
|
|
@@ -224,7 +237,7 @@ test("wizard can use code-experts preset and shared model", async () => {
|
|
|
224
237
|
"quorum · at least min-agree agree (default)",
|
|
225
238
|
"2",
|
|
226
239
|
],
|
|
227
|
-
confirms: [true
|
|
240
|
+
confirms: [true],
|
|
228
241
|
});
|
|
229
242
|
|
|
230
243
|
const result = await runRvInteractiveWizard(ui, {
|
|
@@ -241,6 +254,62 @@ test("wizard can use code-experts preset and shared model", async () => {
|
|
|
241
254
|
"security=openai-codex/gpt-5.6-sol:xhigh",
|
|
242
255
|
"testing=openai-codex/gpt-5.6-sol:xhigh",
|
|
243
256
|
]);
|
|
257
|
+
const summary = ui.confirmMessages.at(-1) ?? "";
|
|
258
|
+
assert.match(summary, /reviewer models: correctness=openai-codex\/gpt-5\.6-sol:xhigh, security=openai-codex\/gpt-5\.6-sol:xhigh, testing=openai-codex\/gpt-5\.6-sol:xhigh/);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("wizard can skip model assignment and use Pi's default model for every reviewer", async () => {
|
|
262
|
+
const ui = scriptedUi({
|
|
263
|
+
inputs: ["review auth"],
|
|
264
|
+
selects: [
|
|
265
|
+
"code review (code)",
|
|
266
|
+
"Single gate (fix then re-run /rv-loop) · recommended",
|
|
267
|
+
"1 · host fix point (recommended)",
|
|
268
|
+
"Preset code-experts (correctness/security/testing)",
|
|
269
|
+
"Use Pi's default model (resolved at runtime)",
|
|
270
|
+
"quorum · at least min-agree agree (default)",
|
|
271
|
+
"2",
|
|
272
|
+
],
|
|
273
|
+
confirms: [true],
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const result = await runRvInteractiveWizard(ui, {
|
|
277
|
+
strategy: "loop",
|
|
278
|
+
seed: seed(),
|
|
279
|
+
models,
|
|
280
|
+
locale: "en",
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
assert.ok(result);
|
|
284
|
+
assert.equal(result!.panel, "code-experts");
|
|
285
|
+
// No per-reviewer overrides and no shared --model: every reviewer resolves at runtime.
|
|
286
|
+
assert.equal(result!.reviewerModels, undefined);
|
|
287
|
+
assert.equal(result!.model, undefined);
|
|
288
|
+
const summary = ui.confirmMessages.at(-1) ?? "";
|
|
289
|
+
assert.match(summary, /reviewer models: correctness=Pi default, security=Pi default, testing=Pi default/);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("wizard cancels when the user escapes the model-assignment select", async () => {
|
|
293
|
+
const ui = scriptedUi({
|
|
294
|
+
inputs: ["review auth"],
|
|
295
|
+
selects: [
|
|
296
|
+
"code review (code)",
|
|
297
|
+
"Single gate (fix then re-run /rv-loop) · recommended",
|
|
298
|
+
"1 · host fix point (recommended)",
|
|
299
|
+
"Preset code-experts (correctness/security/testing)",
|
|
300
|
+
SELECT_CANCEL,
|
|
301
|
+
],
|
|
302
|
+
confirms: [true],
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const result = await runRvInteractiveWizard(ui, {
|
|
306
|
+
strategy: "loop",
|
|
307
|
+
seed: seed(),
|
|
308
|
+
models,
|
|
309
|
+
locale: "en",
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
assert.equal(result, undefined);
|
|
244
313
|
});
|
|
245
314
|
|
|
246
315
|
test("wizard can select until-clean with a hard budget", async () => {
|
|
@@ -257,7 +326,7 @@ test("wizard can select until-clean with a hard budget", async () => {
|
|
|
257
326
|
"quorum · at least min-agree agree (default)",
|
|
258
327
|
"2",
|
|
259
328
|
],
|
|
260
|
-
confirms: [true
|
|
329
|
+
confirms: [true],
|
|
261
330
|
});
|
|
262
331
|
|
|
263
332
|
const result = await runRvInteractiveWizard(ui, {
|
|
@@ -527,7 +596,7 @@ test("inline picker: per-reviewer models resolve through repeated picker calls",
|
|
|
527
596
|
"1 · host fix point (recommended)",
|
|
528
597
|
"Custom reviewer count 2–8 (r1..rN, pick models)",
|
|
529
598
|
"3",
|
|
530
|
-
"Pick
|
|
599
|
+
"Pick a model for each reviewer",
|
|
531
600
|
// thinking selects for r1, r2, r3
|
|
532
601
|
"xhigh",
|
|
533
602
|
"high",
|
|
@@ -535,7 +604,7 @@ test("inline picker: per-reviewer models resolve through repeated picker calls",
|
|
|
535
604
|
"quorum · at least min-agree agree (default)",
|
|
536
605
|
"2",
|
|
537
606
|
],
|
|
538
|
-
confirms: [true
|
|
607
|
+
confirms: [true],
|
|
539
608
|
customModelPickerResults: [
|
|
540
609
|
"openai/gpt-5.6-luna",
|
|
541
610
|
"anthropic/claude-opus-4",
|
|
@@ -560,3 +629,105 @@ test("inline picker: per-reviewer models resolve through repeated picker calls",
|
|
|
560
629
|
const pickerCalls = uiPanel.log.filter((e) => e.startsWith("customModelPicker:"));
|
|
561
630
|
assert.equal(pickerCalls.length, 3, uiPanel.log.join("\n"));
|
|
562
631
|
});
|
|
632
|
+
|
|
633
|
+
test("wizard (zh) per-reviewer branch routes on the exact zh option label", async () => {
|
|
634
|
+
const ui = scriptedUi({
|
|
635
|
+
inputs: ["@src"],
|
|
636
|
+
selects: [
|
|
637
|
+
"代码审查 (code)",
|
|
638
|
+
"预设 code-experts(正确性/安全/测试)",
|
|
639
|
+
"每位 reviewer 分别选择模型",
|
|
640
|
+
"openai-codex/gpt-5.6-sol",
|
|
641
|
+
"xhigh",
|
|
642
|
+
"anthropic/claude-sonnet-4-5",
|
|
643
|
+
"high",
|
|
644
|
+
"openai-codex/gpt-5.6-sol",
|
|
645
|
+
"xhigh",
|
|
646
|
+
"quorum · 至少 min-agree 人同意(默认)",
|
|
647
|
+
"2",
|
|
648
|
+
],
|
|
649
|
+
confirms: [true],
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
const result = await runRvInteractiveWizard(ui, {
|
|
653
|
+
strategy: "panel",
|
|
654
|
+
seed: seed({ strategy: "panel" }),
|
|
655
|
+
models,
|
|
656
|
+
locale: "zh",
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
assert.ok(result);
|
|
660
|
+
assert.equal(result!.panel, "code-experts");
|
|
661
|
+
assert.deepEqual(result!.reviewerModels, [
|
|
662
|
+
"correctness=openai-codex/gpt-5.6-sol:xhigh",
|
|
663
|
+
"security=anthropic/claude-sonnet-4-5:high",
|
|
664
|
+
"testing=openai-codex/gpt-5.6-sol:xhigh",
|
|
665
|
+
]);
|
|
666
|
+
const summary = ui.confirmMessages.at(-1) ?? "";
|
|
667
|
+
assert.match(summary, /reviewer 模型: correctness=openai-codex\/gpt-5\.6-sol:xhigh, security=anthropic\/claude-sonnet-4-5:high, testing=openai-codex\/gpt-5\.6-sol:xhigh/);
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
test("wizard (zh) Pi-default branch skips model prompts and shows the zh placeholder per reviewer", async () => {
|
|
671
|
+
const ui = scriptedUi({
|
|
672
|
+
inputs: ["@src"],
|
|
673
|
+
selects: [
|
|
674
|
+
"代码审查 (code)",
|
|
675
|
+
"预设 code-experts(正确性/安全/测试)",
|
|
676
|
+
"使用 Pi 默认模型(运行时解析实际模型)",
|
|
677
|
+
"quorum · 至少 min-agree 人同意(默认)",
|
|
678
|
+
"2",
|
|
679
|
+
],
|
|
680
|
+
confirms: [true],
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
const result = await runRvInteractiveWizard(ui, {
|
|
684
|
+
strategy: "panel",
|
|
685
|
+
seed: seed({ strategy: "panel" }),
|
|
686
|
+
models,
|
|
687
|
+
locale: "zh",
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
assert.ok(result);
|
|
691
|
+
assert.equal(result!.panel, "code-experts");
|
|
692
|
+
assert.equal(result!.reviewerModels, undefined);
|
|
693
|
+
assert.equal(result!.model, undefined);
|
|
694
|
+
const summary = ui.confirmMessages.at(-1) ?? "";
|
|
695
|
+
assert.match(summary, /reviewer 模型: correctness=Pi 默认, security=Pi 默认, testing=Pi 默认/);
|
|
696
|
+
// No model picker step ran: the wizard never offered a model list select.
|
|
697
|
+
assert.ok(!ui.log.some((entry) => entry.startsWith("select:共用模型") || entry.startsWith("select:模型 · ")), ui.log.join("\n"));
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
test("wizard (zh) shared-model branch writes the same token for every reviewer id", async () => {
|
|
701
|
+
const ui = scriptedUi({
|
|
702
|
+
inputs: ["@src"],
|
|
703
|
+
selects: [
|
|
704
|
+
"代码审查 (code)",
|
|
705
|
+
"预设 code-experts(正确性/安全/测试)",
|
|
706
|
+
"所有 reviewer 使用同一模型",
|
|
707
|
+
"openai-codex/gpt-5.6-sol",
|
|
708
|
+
"xhigh",
|
|
709
|
+
"quorum · 至少 min-agree 人同意(默认)",
|
|
710
|
+
"2",
|
|
711
|
+
],
|
|
712
|
+
confirms: [true],
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
const result = await runRvInteractiveWizard(ui, {
|
|
716
|
+
strategy: "panel",
|
|
717
|
+
seed: seed({ strategy: "panel" }),
|
|
718
|
+
models,
|
|
719
|
+
locale: "zh",
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
assert.ok(result);
|
|
723
|
+
assert.equal(result!.panel, "code-experts");
|
|
724
|
+
assert.deepEqual(result!.reviewerModels, [
|
|
725
|
+
"correctness=openai-codex/gpt-5.6-sol:xhigh",
|
|
726
|
+
"security=openai-codex/gpt-5.6-sol:xhigh",
|
|
727
|
+
"testing=openai-codex/gpt-5.6-sol:xhigh",
|
|
728
|
+
]);
|
|
729
|
+
const summary = ui.confirmMessages.at(-1) ?? "";
|
|
730
|
+
assert.match(summary, /reviewer 模型: correctness=openai-codex\/gpt-5\.6-sol:xhigh, security=openai-codex\/gpt-5\.6-sol:xhigh, testing=openai-codex\/gpt-5\.6-sol:xhigh/);
|
|
731
|
+
// The shared-model picker (zh title) actually ran.
|
|
732
|
+
assert.ok(ui.log.some((entry) => entry.startsWith("select:共用模型")), ui.log.join("\n"));
|
|
733
|
+
});
|
|
@@ -430,77 +430,60 @@ export async function runRvInteractiveWizard(
|
|
|
430
430
|
const labels = rankedModelLabels(models, mode);
|
|
431
431
|
|
|
432
432
|
if (ids.length > 0) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
433
|
+
// Branch on stable keys, not display-label substrings, so copy edits in
|
|
434
|
+
// either language can never silently reroute the wizard.
|
|
435
|
+
const assignmentOptions: Array<{ key: "per-reviewer" | "shared" | "pi-default"; label: string }> = [
|
|
436
|
+
{ key: "per-reviewer", label: zh ? "每位 reviewer 分别选择模型" : "Pick a model for each reviewer" },
|
|
437
|
+
{ key: "shared", label: zh ? "所有 reviewer 使用同一模型" : "Same model for all reviewers" },
|
|
438
|
+
{ key: "pi-default", label: zh ? "使用 Pi 默认模型(运行时解析实际模型)" : "Use Pi's default model (resolved at runtime)" },
|
|
439
|
+
];
|
|
440
|
+
const assignmentChoice = await mustSelect(
|
|
441
|
+
ui,
|
|
442
|
+
zh ? "模型分配方式" : "Model assignment",
|
|
443
|
+
assignmentOptions.map((option) => option.label),
|
|
438
444
|
);
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
zh ? `思考强度(${pick})` : `Thinking (${pick})`,
|
|
462
|
-
thinkingOptions(m, locale),
|
|
463
|
-
);
|
|
464
|
-
if (thinkingPick === CANCEL) return undefined;
|
|
465
|
-
const thinking = stripSkip(thinkingPick, locale);
|
|
466
|
-
const token = thinking ? `${pick}:${thinking}` : pick;
|
|
467
|
-
for (const id of ids) reviewerModels.push(`${id}=${token}`);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
445
|
+
if (assignmentChoice === CANCEL) return undefined;
|
|
446
|
+
const assignment = assignmentOptions.find((option) => option.label === assignmentChoice)?.key ?? "pi-default";
|
|
447
|
+
|
|
448
|
+
if (assignment === "per-reviewer") {
|
|
449
|
+
for (const id of ids) {
|
|
450
|
+
if (labels.length === 0) break;
|
|
451
|
+
const pick = await pickModelLabel(ui, models, mode, locale, zh ? `模型 · ${id}` : `Model · ${id}`, false);
|
|
452
|
+
if (pick === CANCEL) return undefined;
|
|
453
|
+
if (pick === undefined) continue; // defensive: allowSkip=false never returns undefined here
|
|
454
|
+
const m = modelByLabel(models, pick);
|
|
455
|
+
const thinkingPick = await mustSelect(
|
|
456
|
+
ui,
|
|
457
|
+
zh ? `思考强度 · ${id}` : `Thinking · ${id}`,
|
|
458
|
+
thinkingOptions(m, locale),
|
|
459
|
+
);
|
|
460
|
+
if (thinkingPick === CANCEL) return undefined;
|
|
461
|
+
const thinking = stripSkip(thinkingPick, locale);
|
|
462
|
+
reviewerModels.push(`${id}=${thinking ? `${pick}:${thinking}` : pick}`);
|
|
463
|
+
}
|
|
464
|
+
} else if (assignment === "shared") {
|
|
465
|
+
if (labels.length === 0) {
|
|
466
|
+
ui.notify(zh ? "当前没有可用模型目录,请先 /rv-models" : "No model catalog available; run /rv-models first", "warning");
|
|
470
467
|
} else {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
if (pick === CANCEL) return undefined;
|
|
475
|
-
if (pick === undefined) continue; // defensive: allowSkip=false never returns undefined here
|
|
468
|
+
const pick = await pickModelLabel(ui, models, mode, locale, zh ? "共用模型" : "Shared model", false);
|
|
469
|
+
if (pick === CANCEL) return undefined;
|
|
470
|
+
if (pick !== undefined) {
|
|
476
471
|
const m = modelByLabel(models, pick);
|
|
477
472
|
const thinkingPick = await mustSelect(
|
|
478
473
|
ui,
|
|
479
|
-
zh ?
|
|
474
|
+
zh ? `思考强度(${pick})` : `Thinking (${pick})`,
|
|
480
475
|
thinkingOptions(m, locale),
|
|
481
476
|
);
|
|
482
477
|
if (thinkingPick === CANCEL) return undefined;
|
|
483
478
|
const thinking = stripSkip(thinkingPick, locale);
|
|
484
|
-
|
|
479
|
+
const token = thinking ? `${pick}:${thinking}` : pick;
|
|
480
|
+
for (const id of ids) reviewerModels.push(`${id}=${token}`);
|
|
485
481
|
}
|
|
486
482
|
}
|
|
487
|
-
} else if (!seed.model && labels.length > 0) {
|
|
488
|
-
// Shared default model when not assigning per-reviewer
|
|
489
|
-
const pick = await pickModelLabel(ui, models, mode, locale, zh ? "默认模型(全体 reviewer)" : "Default model (all reviewers)", true);
|
|
490
|
-
if (pick === CANCEL) return undefined;
|
|
491
|
-
if (pick !== undefined) {
|
|
492
|
-
const m = modelByLabel(models, pick);
|
|
493
|
-
const thinkingPick = await mustSelect(
|
|
494
|
-
ui,
|
|
495
|
-
zh ? "默认思考强度" : "Default thinking",
|
|
496
|
-
thinkingOptions(m, locale),
|
|
497
|
-
);
|
|
498
|
-
if (thinkingPick === CANCEL) return undefined;
|
|
499
|
-
const thinking = stripSkip(thinkingPick, locale);
|
|
500
|
-
seed.model = pick;
|
|
501
|
-
if (thinking) seed.thinking = thinking;
|
|
502
|
-
}
|
|
503
483
|
}
|
|
484
|
+
// else: Pi default for every reviewer — no reviewerModels, no further prompt.
|
|
485
|
+
// The confirm summary below still shows each reviewer's resolved model
|
|
486
|
+
// (falling back to the shared --model flag, then a "Pi default" placeholder).
|
|
504
487
|
} else if (!seed.model && labels.length > 0) {
|
|
505
488
|
// Single-reviewer path
|
|
506
489
|
const pick = await pickModelLabel(ui, models, mode, locale, zh ? "模型" : "Model", true);
|
|
@@ -543,6 +526,23 @@ export async function runRvInteractiveWizard(
|
|
|
543
526
|
}
|
|
544
527
|
|
|
545
528
|
// 7) Confirm summary
|
|
529
|
+
// Per-reviewer effective model for the confirm summary: explicit override →
|
|
530
|
+
// shared --model (if set) → "Pi default" placeholder. Mirrors what the CLI
|
|
531
|
+
// actually resolves at runtime (resolveReviewerModelThinking).
|
|
532
|
+
const piDefaultLabel = zh ? "Pi 默认" : "Pi default";
|
|
533
|
+
const reviewerModelOverrides = new Map(
|
|
534
|
+
reviewerModels.map((entry) => {
|
|
535
|
+
const eq = entry.indexOf("=");
|
|
536
|
+
return [entry.slice(0, eq), entry.slice(eq + 1)] as const;
|
|
537
|
+
}),
|
|
538
|
+
);
|
|
539
|
+
const reviewerModelSummary = ids.map((id) => {
|
|
540
|
+
const override = reviewerModelOverrides.get(id);
|
|
541
|
+
if (override) return `${id}=${override}`;
|
|
542
|
+
if (seed.model) return `${id}=${seed.model}${seed.thinking ? `:${seed.thinking}` : ""}`;
|
|
543
|
+
return `${id}=${piDefaultLabel}`;
|
|
544
|
+
});
|
|
545
|
+
|
|
546
546
|
const summaryLines = [
|
|
547
547
|
`${zh ? "策略" : "Strategy"}: ${strategy}`,
|
|
548
548
|
`${zh ? "目标" : "Target"}: ${target}`,
|
|
@@ -559,8 +559,11 @@ export async function runRvInteractiveWizard(
|
|
|
559
559
|
: zh
|
|
560
560
|
? "单 reviewer"
|
|
561
561
|
: "single reviewer",
|
|
562
|
-
|
|
563
|
-
|
|
562
|
+
// Multi-reviewer paths show one resolved model per reviewer id; single-reviewer
|
|
563
|
+
// and shared-model paths keep the existing single `model:` line.
|
|
564
|
+
ids.length > 0
|
|
565
|
+
? `${zh ? "reviewer 模型" : "reviewer models"}: ${reviewerModelSummary.join(", ")}`
|
|
566
|
+
: `model: ${seed.model ? `${seed.model}${seed.thinking ? `:${seed.thinking}` : ""}` : piDefaultLabel}`,
|
|
564
567
|
consensus ? `consensus: ${consensus}${minAgree ? ` min-agree=${minAgree}` : ""}` : "",
|
|
565
568
|
].filter(Boolean);
|
|
566
569
|
|
package/package.json
CHANGED
|
@@ -27,12 +27,12 @@ node ../../bin/pi-review.js --help
|
|
|
27
27
|
|------|-------------------------|
|
|
28
28
|
| **Pi** (`/rv`) | New panel reviews call the native `pi_review` API tool, shown to users as **Pi Review Panel**, which launches the packaged CLI in event mode and renders live reviewer state. Continuations, kept sessions, `/rv-loop`, and explicit `--no-stream` use the shell CLI. |
|
|
29
29
|
| **Pi terminal** | Foreground `pi-review`; text deltas stream live by default. |
|
|
30
|
-
| **Claude Code / Codex / Cursor** and similar agent hosts | These hosts buffer a shell tool's output until the command exits, so a foreground run looks like a silent wait. **Panel review (`--reviewers`/`--panel`) default: `--ui web --ui-url-file <path>` + background run** —
|
|
30
|
+
| **Claude Code / Codex / Cursor** and similar agent hosts | These hosts buffer a shell tool's output until the command exits, so a foreground run looks like a silent wait. **Panel review (`--reviewers`/`--panel`) default: `--ui web --ui-url-file <path>` + background run** — get the dashboard in front of the user: on Claude Code the CLI auto-open lands in the system default browser; on Codex open the `--ui-url-file` URL in the host's built-in browser (the CLI cannot reach a GUI there); hand over the URL as fallback either way. **Single review / `loop` default: `--progress-log <path>` + background run + tail the log** (`--ui web` requires an active panel and rejects `loop`). See [references/codex-tools.md](./references/codex-tools.md). Map skill mentions of `Bash` to your host shell tool. |
|
|
31
31
|
| Scripts / CI | Foreground is fine; add `--no-stream` only when the caller must buffer until exit (cannot combine with `--progress-log`). |
|
|
32
32
|
|
|
33
33
|
`--progress-log <path>` tees the raw `--mode json` event stream to a file for outside observation and debugging; it is never a prerequisite for metrics. Token usage accumulates by default, and `pi-review` writes milestone notices (`pi-review: review started`, `pi-review: tool <name> started/finished`, `pi-review: review finished`) to stderr.
|
|
34
34
|
|
|
35
|
-
`--ui web` starts a loopback-only browser dashboard for panel review and auto-opens it in the default browser (`--no-ui-open` disables the auto-open); `--ui-url-file <path>` writes its URL atomically so a buffered-output host can read it without parsing stderr. After completion the page counts down 60s, then closes itself and stops the dashboard server (any interaction cancels the countdown). It never substitutes for panel semantics — findings, gate status, and exit code come from the same `PI_REVIEW_META_JSON` as always.
|
|
35
|
+
`--ui web` starts a loopback-only browser dashboard for panel review and auto-opens it in the default browser (`--no-ui-open` disables the auto-open); `--ui-url-file <path>` writes its URL atomically so a buffered-output host can read it without parsing stderr. Open the dashboard as wide as the host allows: Claude Code rides the auto-open (system default browser), Codex opens the url-file URL in its built-in browser, and Pi renders panels natively so `/rv` needs no `--ui web`. After completion the page counts down 60s, then closes itself and stops the dashboard server (any interaction cancels the countdown). It never substitutes for panel semantics — findings, gate status, and exit code come from the same `PI_REVIEW_META_JSON` as always.
|
|
36
36
|
|
|
37
37
|
## Run metrics
|
|
38
38
|
|
|
@@ -40,7 +40,7 @@ Quote metrics from the run output; never estimate or invent them.
|
|
|
40
40
|
|
|
41
41
|
- **ASCII footer** (the `── pi-review` / `── pi-review panel` block): Duration, Tokens as `in · out · cache · reason` plus total, and Cost — the provider-reported value, or `n/a` when the provider reports none. On Pi `/rv` the panel tool result is **plain text / ASCII only** (Pi does not render markdown in tool results) — same classic chrome as the CLI, no `###` headings or fenced code blocks.
|
|
42
42
|
- **Pi Review Panel**: each reviewer row shows **role persona · lifecycle · model · thinking · elapsed · tokens**. Lifecycle is `queued` / `running` / `completed` / `failed` / `cancelled`. Expanded view adds bounded activity, plain-text findings, and the ASCII footer.
|
|
43
|
-
- Machine output: parse `PI_REVIEW_META_JSON:` from **stderr** (or set `PI_REVIEW_META_STDOUT=1` to emit it on stdout). Show users the plain review text and ASCII footer, not raw JSON, unless they ask for machine output. Do **not** rewrap the tool result into markdown tables or `###` report sections.
|
|
43
|
+
- Machine output: parse `PI_REVIEW_META_JSON:` from **stderr** (or set `PI_REVIEW_META_STDOUT=1` to emit it on stdout). Show users the plain review text and ASCII footer, not raw JSON, unless they ask for machine output. Do **not** rewrap the tool result into markdown tables or `###` report sections. On panel runs the top-level `model` is the reviewers' shared effective model (configured, else provider-reported) or the literal sentinel `"mixed"` when reviewers ran on different models; per-reviewer entries carry their own `model`/`responseModel`.
|
|
44
44
|
|
|
45
45
|
## Pi host (`/rv*`)
|
|
46
46
|
|
|
@@ -185,11 +185,12 @@ pi-review --reviewers 3 --ui web --ui-url-file /tmp/pi-review-ui-url.txt -- @src
|
|
|
185
185
|
```
|
|
186
186
|
Rules:
|
|
187
187
|
- Run this before building the review command. **Never invent a `provider/model` id** — only ids from the catalog output.
|
|
188
|
-
-
|
|
188
|
+
- **Cross-model review**: identify the model this host session itself runs on (its id is in your session context), then prefer reviewer models from a different model family — same-family reviewers share the author model's blind spots. On a panel, keep the host's family to a minority of reviewers.
|
|
189
|
+
- Follow **[references/model-selection.md](./references/model-selection.md)** for everything else: profile inference (code / frontend / plan), priority lists, cross-model resolution, user-named-model resolution, and thinking aliases (`max`/`最高` → `xhigh`, with fallback to the nearest supported level).
|
|
189
190
|
- Ambiguous match across model families: show the top candidates and ask; do not guess.
|
|
190
|
-
-
|
|
191
|
+
- User named no model: propose 2–3 exact catalog ids (cross-model first, one line of why each, "Pi default" as an explicit option) and ask the user to pick before running.
|
|
191
192
|
- On **Claude Code / Codex / Cursor**, state the chosen model in one line (match the user's language) before running the review command.
|
|
192
|
-
Completion criterion: exact listed `provider/model[:thinking]` or
|
|
193
|
+
Completion criterion: an exact listed `provider/model[:thinking]` (or Pi default) that the user named or picked from your proposal; never invented ids.
|
|
193
194
|
|
|
194
195
|
2. Choose one mode:
|
|
195
196
|
- default `code` — code, diff, MR, file, or repository review.
|
|
@@ -8,7 +8,7 @@ Skills may use Claude Code tool names. On **Codex** or **Claude Code**, map them
|
|
|
8
8
|
| `Read`, `Write`, `Edit` | Native file tools |
|
|
9
9
|
| `Skill` | Load and follow the skill instructions directly |
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
This file is **pi-review–specific** and ships with the pi-review package.
|
|
12
12
|
|
|
13
13
|
## Long-running `pi-review` (default on Codex / Claude Code)
|
|
14
14
|
|
|
@@ -18,8 +18,8 @@ Native shell tools on these hosts **buffer stdout/stderr until the command exits
|
|
|
18
18
|
|
|
19
19
|
`--reviewers <n>` or `--panel <name>` activates panel review. On Codex, Claude Code, or Cursor, default to the dashboard instead of a tailed log:
|
|
20
20
|
|
|
21
|
-
1. Run `pi-review --reviewers <n> --ui web --ui-url-file <path> -- <target>` (or `--panel <name>`) in the **background**.
|
|
22
|
-
2. Read `<path>` shortly after launch — it is written atomically as soon as the dashboard server is ready, well before reviewers finish (poll a few times a second for a couple of seconds if the file is not there yet).
|
|
21
|
+
1. Run `pi-review --reviewers <n> --ui web --ui-url-file <path> -- <target>` (or `--panel <name>`) in the **background**. Pass `--no-ui-open` only when the user asked not to open a browser (CI, remote shells).
|
|
22
|
+
2. Read `<path>` shortly after launch — it is written atomically as soon as the dashboard server is ready, well before reviewers finish (poll a few times a second for a couple of seconds if the file is not there yet). Then get the dashboard in front of the user: on **Claude Code** the CLI auto-open already lands in the system default browser; on **Codex** the CLI cannot reach a GUI browser, so open the URL from `<path>` in the host's built-in browser yourself. Share the URL either way as a fallback: *"Dashboard opened in your browser (URL: `<url>`). I'll report back when the review completes."*
|
|
23
23
|
3. Wait for the background job. On exit, show the Markdown review body and ASCII `── pi-review` footer as usual (skill step 4) — the dashboard is a presentation layer only; findings, gate status, and exit code always come from `PI_REVIEW_META_JSON`.
|
|
24
24
|
4. `--ui web` requires an active panel and rejects `loop` — for a single review or a panel `loop`, fall back to the progress-log workflow below.
|
|
25
25
|
|