mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Deduplicate auto-review results
This commit is contained in:
parent
4bb631c309
commit
aa3ffa47aa
2 changed files with 91 additions and 2 deletions
|
|
@ -117,7 +117,8 @@ export class PanelController {
|
|||
"mcp progress",
|
||||
);
|
||||
} else if (method === "item/autoApprovalReview/started" || method === "item/autoApprovalReview/completed") {
|
||||
this.state.displayItems = upsertDisplayItem(this.state.displayItems, createAutoReviewResultItem(params));
|
||||
const reviewItem = createAutoReviewResultItem(params);
|
||||
this.state.displayItems = upsertDisplayItem(removeUnstructuredAutoReviewWarnings(this.state.displayItems), reviewItem);
|
||||
} else if (method === "thread/started") {
|
||||
if (params.thread) {
|
||||
if (!this.state.activeThreadId || this.state.activeThreadId === params.thread.id) {
|
||||
|
|
@ -143,7 +144,10 @@ export class PanelController {
|
|||
} else if (method === "thread/compacted") {
|
||||
this.addSystemMessage("Context compacted.");
|
||||
} else if (method === "guardianWarning") {
|
||||
this.state.displayItems.push(createReviewResultItem(params.message));
|
||||
const item = createReviewResultItem(params.message);
|
||||
if (!isUnstructuredAutoReviewWarning(item) || !hasStructuredAutoReviewResult(this.state.displayItems, this.state.activeTurnId)) {
|
||||
this.state.displayItems = upsertDisplayItem(this.state.displayItems, item);
|
||||
}
|
||||
} else if (method === "model/rerouted" || method === "deprecationNotice") {
|
||||
this.addSystemMessage(`${method}: ${jsonPreview(params)}`);
|
||||
} else if (method === "mcpServer/startupStatus/updated") {
|
||||
|
|
@ -381,6 +385,28 @@ function approvalTurnId(approval: PendingApproval): string | undefined {
|
|||
return typeof params.turnId === "string" ? params.turnId : undefined;
|
||||
}
|
||||
|
||||
function removeUnstructuredAutoReviewWarnings(items: DisplayItem[]): DisplayItem[] {
|
||||
return items.filter((item) => !isUnstructuredAutoReviewWarning(item));
|
||||
}
|
||||
|
||||
function hasStructuredAutoReviewResult(items: DisplayItem[], activeTurnId: string | null): boolean {
|
||||
return items.some(
|
||||
(item) =>
|
||||
item.kind === "reviewResult" &&
|
||||
Boolean(item.turnId) &&
|
||||
(!activeTurnId || item.turnId === activeTurnId) &&
|
||||
isAutoReviewText(item.text),
|
||||
);
|
||||
}
|
||||
|
||||
function isUnstructuredAutoReviewWarning(item: DisplayItem): boolean {
|
||||
return item.kind === "reviewResult" && !item.turnId && isAutoReviewText(item.text);
|
||||
}
|
||||
|
||||
function isAutoReviewText(text: string): boolean {
|
||||
return /^Auto-review\b/i.test(text.trim());
|
||||
}
|
||||
|
||||
function isUserMessage(item: DisplayItem): item is MessageDisplayItem & { role: "user" } {
|
||||
return item.kind === "message" && item.role === "user";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -603,6 +603,69 @@ describe("PanelController", () => {
|
|||
rows: expect.arrayContaining([{ key: "status", value: "approved" }]),
|
||||
});
|
||||
});
|
||||
|
||||
it("replaces guardian auto-review warnings when structured auto-review notifications arrive", () => {
|
||||
const state = createPanelState();
|
||||
state.activeThreadId = "thread-active";
|
||||
state.activeTurnId = "turn-active";
|
||||
const controller = controllerForState(state);
|
||||
|
||||
controller.handleNotification({
|
||||
method: "guardianWarning",
|
||||
params: { threadId: "thread-active", message: "Auto-review approved: npm test" },
|
||||
} satisfies Extract<ServerNotification, { method: "guardianWarning" }>);
|
||||
controller.handleNotification({
|
||||
method: "item/autoApprovalReview/completed",
|
||||
params: {
|
||||
threadId: "thread-active",
|
||||
turnId: "turn-active",
|
||||
startedAtMs: 1,
|
||||
completedAtMs: 2,
|
||||
reviewId: "review-1",
|
||||
targetItemId: "cmd-1",
|
||||
decisionSource: "agent",
|
||||
review: { status: "approved", riskLevel: "low", userAuthorization: "medium", rationale: "Allowed by policy." },
|
||||
action: { type: "command", source: "shell", command: "npm test", cwd: "/vault" },
|
||||
},
|
||||
} satisfies Extract<ServerNotification, { method: "item/autoApprovalReview/completed" }>);
|
||||
|
||||
expect(state.displayItems).toHaveLength(1);
|
||||
expect(state.displayItems[0]).toMatchObject({
|
||||
id: "review-review-1",
|
||||
kind: "reviewResult",
|
||||
text: "Auto-review approved: npm test",
|
||||
turnId: "turn-active",
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores guardian auto-review warnings after structured auto-review notifications", () => {
|
||||
const state = createPanelState();
|
||||
state.activeThreadId = "thread-active";
|
||||
state.activeTurnId = "turn-active";
|
||||
const controller = controllerForState(state);
|
||||
|
||||
controller.handleNotification({
|
||||
method: "item/autoApprovalReview/completed",
|
||||
params: {
|
||||
threadId: "thread-active",
|
||||
turnId: "turn-active",
|
||||
startedAtMs: 1,
|
||||
completedAtMs: 2,
|
||||
reviewId: "review-1",
|
||||
targetItemId: "cmd-1",
|
||||
decisionSource: "agent",
|
||||
review: { status: "approved", riskLevel: "low", userAuthorization: "medium", rationale: "Allowed by policy." },
|
||||
action: { type: "command", source: "shell", command: "npm test", cwd: "/vault" },
|
||||
},
|
||||
} satisfies Extract<ServerNotification, { method: "item/autoApprovalReview/completed" }>);
|
||||
controller.handleNotification({
|
||||
method: "guardianWarning",
|
||||
params: { threadId: "thread-active", message: "Auto-review approved: npm test" },
|
||||
} satisfies Extract<ServerNotification, { method: "guardianWarning" }>);
|
||||
|
||||
expect(state.displayItems).toHaveLength(1);
|
||||
expect(state.displayItems[0]).toMatchObject({ id: "review-review-1" });
|
||||
});
|
||||
});
|
||||
|
||||
function supportedApprovalRequests(): ServerRequest[] {
|
||||
|
|
|
|||
Loading…
Reference in a new issue