mirror of
https://github.com/earendil-works/pi.git
synced 2026-10-02 08:44:38 +08:00
fix(coding-agent): suppress bug hints for expected failures
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed `/bug` descriptions dropping line breaks from pasted diagnostics.
|
||||
- Fixed `/bug` hints appearing for user cancellations and retryable provider failures such as service unavailability.
|
||||
|
||||
## [0.86.0] - 2026-09-19
|
||||
|
||||
|
||||
@@ -9,7 +9,14 @@ import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import type { AgentMessage, ThinkingLevel } from "@earendil-works/pi-agent-core";
|
||||
import type { AuthEvent, AuthPrompt } from "@earendil-works/pi-ai";
|
||||
import type { AssistantMessage, ImageContent, Message, Model, Usage } from "@earendil-works/pi-ai/compat";
|
||||
import {
|
||||
type AssistantMessage,
|
||||
type ImageContent,
|
||||
isRetryableAssistantError,
|
||||
type Message,
|
||||
type Model,
|
||||
type Usage,
|
||||
} from "@earendil-works/pi-ai/compat";
|
||||
import type {
|
||||
AutocompleteItem,
|
||||
AutocompleteProvider,
|
||||
@@ -2064,6 +2071,12 @@ export class InteractiveMode {
|
||||
this.ui.requestRender();
|
||||
}
|
||||
|
||||
private maybeSuggestBugReport(message: AssistantMessage): void {
|
||||
if (message.stopReason !== "error" || isRetryableAssistantError(message)) return;
|
||||
if (/\b(?:abort(?:ed)?|cancel(?:l?ed)?)\b/i.test(message.errorMessage ?? "")) return;
|
||||
this.suggestBugReport();
|
||||
}
|
||||
|
||||
private renderCurrentSessionState(): void {
|
||||
this.loadedResourcesContainer.clear();
|
||||
this.chatContainer.clear();
|
||||
@@ -3376,7 +3389,7 @@ export class InteractiveMode {
|
||||
});
|
||||
}
|
||||
this.pendingTools.clear();
|
||||
if (this.streamingMessage.stopReason === "error") this.suggestBugReport();
|
||||
this.maybeSuggestBugReport(this.streamingMessage);
|
||||
} else {
|
||||
// Args are now complete - trigger diff computation for edit tools
|
||||
for (const [, component] of this.pendingTools.entries()) {
|
||||
@@ -3546,7 +3559,6 @@ export class InteractiveMode {
|
||||
// Show error only on final failure (success shows normal response)
|
||||
if (!event.success) {
|
||||
this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || "Unknown error"}`);
|
||||
this.suggestBugReport();
|
||||
}
|
||||
this.ui.requestRender();
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { type AssistantMessage, fauxAssistantMessage } from "@earendil-works/pi-ai";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
import { InteractiveMode } from "../src/modes/interactive/interactive-mode.ts";
|
||||
|
||||
type BugReportHintContext = {
|
||||
suggestBugReport(): void;
|
||||
};
|
||||
|
||||
const maybeSuggestBugReport = Reflect.get(InteractiveMode.prototype, "maybeSuggestBugReport") as (
|
||||
this: BugReportHintContext,
|
||||
message: AssistantMessage,
|
||||
) => void;
|
||||
|
||||
function errorMessage(errorMessage: string): AssistantMessage {
|
||||
return fauxAssistantMessage("", { stopReason: "error", errorMessage });
|
||||
}
|
||||
|
||||
describe("InteractiveMode bug report hints", () => {
|
||||
test("does not suggest reports for retryable provider failures", () => {
|
||||
const context = { suggestBugReport: vi.fn() };
|
||||
const failures = [
|
||||
"500 Internal Server Error",
|
||||
"502 Bad Gateway",
|
||||
"503 Service Unavailable",
|
||||
"504 Gateway Timeout",
|
||||
"429 Too Many Requests",
|
||||
"Provider overloaded",
|
||||
"Network connection lost",
|
||||
"Request timed out",
|
||||
];
|
||||
|
||||
for (const failure of failures) maybeSuggestBugReport.call(context, errorMessage(failure));
|
||||
|
||||
expect(context.suggestBugReport).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("does not suggest reports for cancellations", () => {
|
||||
const context = { suggestBugReport: vi.fn() };
|
||||
|
||||
maybeSuggestBugReport.call(context, errorMessage("This operation was aborted"));
|
||||
maybeSuggestBugReport.call(context, errorMessage("Request cancelled"));
|
||||
maybeSuggestBugReport.call(context, fauxAssistantMessage("", { stopReason: "aborted" }));
|
||||
|
||||
expect(context.suggestBugReport).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("suggests reports for unexpected errors", () => {
|
||||
const context = { suggestBugReport: vi.fn() };
|
||||
|
||||
maybeSuggestBugReport.call(context, errorMessage("Unexpected internal state"));
|
||||
|
||||
expect(context.suggestBugReport).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user