























@@ -3,6 +3,7 @@ import { LiveSessionModelSwitchError } from "../../agents/live-model-switch-erro
33import type { SessionEntry } from "../../config/sessions.js";
44import { CommandLaneClearedError, GatewayDrainingError } from "../../process/command-queue.js";
55import type { TemplateContext } from "../templating.js";
6+import { SILENT_REPLY_TOKEN } from "../tokens.js";
67import type { GetReplyOptions, ReplyPayload } from "../types.js";
78import { MAX_LIVE_SWITCH_RETRIES } from "./agent-runner-execution.js";
89import type { FollowupRun } from "./queue.js";
@@ -18,6 +19,9 @@ const state = vi.hoisted(() => ({
1819createBlockReplyDeliveryHandlerMock: vi.fn(),
1920}));
202122+const GENERIC_RUN_FAILURE_TEXT =
23+"⚠️ Something went wrong while processing your request. Please try again, or use /new to start a fresh session.";
24+2125vi.mock("../../agents/pi-embedded.js", () => ({
2226runEmbeddedPiAgent: (params: unknown) => state.runEmbeddedPiAgentMock(params),
2327}));
@@ -260,14 +264,17 @@ function createMockReplyOperation(): {
260264function createMinimalRunAgentTurnParams(overrides?: {
261265followupRun?: FollowupRun;
262266opts?: GetReplyOptions;
267+sessionCtx?: TemplateContext;
263268}) {
264269return {
265270commandBody: "fix it",
266271followupRun: overrides?.followupRun ?? createFollowupRun(),
267-sessionCtx: {
268-Provider: "whatsapp",
269-MessageSid: "msg",
270-} as unknown as TemplateContext,
272+sessionCtx:
273+overrides?.sessionCtx ??
274+({
275+Provider: "whatsapp",
276+MessageSid: "msg",
277+} as unknown as TemplateContext),
271278opts: overrides?.opts ?? ({} satisfies GetReplyOptions),
272279typingSignals: createMockTypingSignaler(),
273280blockReplyPipeline: null,
@@ -1706,9 +1713,9 @@ describe("runAgentTurnWithFallback", () => {
1706171317071714expect(result.kind).toBe("final");
17081715if (result.kind === "final") {
1709-expect(result.payload.text).toContain("Agent failed before reply");
1710-expect(result.payload.text).toContain("All models failed");
1711-expect(result.payload.text).toContain("402 (billing)");
1716+expect(result.payload.text).toBe(GENERIC_RUN_FAILURE_TEXT);
1717+expect(result.payload.text).not.toContain("All models failed");
1718+expect(result.payload.text).not.toContain("402 (billing)");
17121719expect(result.payload.text).not.toContain("Rate-limited");
17131720}
17141721});
@@ -1923,7 +1930,7 @@ describe("runAgentTurnWithFallback", () => {
19231930expect(failMock).not.toHaveBeenCalled();
19241931});
192519321926-it("forwards sanitized generic errors on external chat channels", async () => {
1933+it("uses compact generic copy for raw external chat errors when verbose is off", async () => {
19271934state.runEmbeddedPiAgentMock.mockRejectedValueOnce(
19281935new Error("INVALID_ARGUMENT: some other failure"),
19291936);
@@ -1953,6 +1960,42 @@ describe("runAgentTurnWithFallback", () => {
19531960resolvedVerboseLevel: "off",
19541961});
195519621963+expect(result.kind).toBe("final");
1964+if (result.kind === "final") {
1965+expect(result.payload.text).toBe(GENERIC_RUN_FAILURE_TEXT);
1966+}
1967+});
1968+1969+it("forwards sanitized generic errors on external chat channels when verbose is on", async () => {
1970+state.runEmbeddedPiAgentMock.mockRejectedValueOnce(
1971+new Error("INVALID_ARGUMENT: some other failure"),
1972+);
1973+1974+const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
1975+const result = await runAgentTurnWithFallback({
1976+commandBody: "hello",
1977+followupRun: createFollowupRun(),
1978+sessionCtx: {
1979+Provider: "whatsapp",
1980+MessageSid: "msg",
1981+} as unknown as TemplateContext,
1982+opts: {},
1983+typingSignals: createMockTypingSignaler(),
1984+blockReplyPipeline: null,
1985+blockStreamingEnabled: false,
1986+resolvedBlockStreamingBreak: "message_end",
1987+applyReplyToMode: (payload) => payload,
1988+shouldEmitToolResult: () => true,
1989+shouldEmitToolOutput: () => false,
1990+pendingToolTasks: new Set(),
1991+resetSessionAfterCompactionFailure: async () => false,
1992+resetSessionAfterRoleOrderingConflict: async () => false,
1993+isHeartbeat: false,
1994+sessionKey: "main",
1995+getActiveSessionEntry: () => undefined,
1996+resolvedVerboseLevel: "on",
1997+});
1998+19561999expect(result.kind).toBe("final");
19572000if (result.kind === "final") {
19582001expect(result.payload.text).toBe(
@@ -1961,7 +2004,83 @@ describe("runAgentTurnWithFallback", () => {
19612004}
19622005});
196320061964-it("formats raw Codex API payloads before forwarding external errors", async () => {
2007+it.each(["group", "channel"] as const)(
2008+"keeps raw runner failure boilerplate out of Discord %s chats",
2009+async (chatType) => {
2010+state.runEmbeddedPiAgentMock.mockRejectedValueOnce(
2011+new Error("openai-codex/gpt-5.5 ended with an incomplete terminal response"),
2012+);
2013+2014+const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
2015+const result = await runAgentTurnWithFallback(
2016+createMinimalRunAgentTurnParams({
2017+sessionCtx: {
2018+Provider: "discord",
2019+Surface: "discord",
2020+ChatType: chatType,
2021+GroupSubject: "agent group",
2022+GroupChannel: "#general",
2023+MessageSid: "msg",
2024+} as unknown as TemplateContext,
2025+}),
2026+);
2027+2028+expect(result.kind).toBe("final");
2029+if (result.kind === "final") {
2030+expect(result.payload.text).toBe(SILENT_REPLY_TOKEN);
2031+}
2032+},
2033+);
2034+2035+it("uses compact generic copy for raw runner failures in normal Discord direct chats", async () => {
2036+state.runEmbeddedPiAgentMock.mockRejectedValueOnce(
2037+new Error("openai-codex/gpt-5.5 ended with an incomplete terminal response"),
2038+);
2039+2040+const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
2041+const result = await runAgentTurnWithFallback(
2042+createMinimalRunAgentTurnParams({
2043+sessionCtx: {
2044+Provider: "discord",
2045+Surface: "discord",
2046+ChatType: "direct",
2047+MessageSid: "msg",
2048+} as unknown as TemplateContext,
2049+}),
2050+);
2051+2052+expect(result.kind).toBe("final");
2053+if (result.kind === "final") {
2054+expect(result.payload.text).toBe(GENERIC_RUN_FAILURE_TEXT);
2055+}
2056+});
2057+2058+it("keeps raw runner failure guidance visible in verbose Discord direct chats", async () => {
2059+state.runEmbeddedPiAgentMock.mockRejectedValueOnce(
2060+new Error("openai-codex/gpt-5.5 ended with an incomplete terminal response"),
2061+);
2062+2063+const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
2064+const result = await runAgentTurnWithFallback({
2065+ ...createMinimalRunAgentTurnParams({
2066+sessionCtx: {
2067+Provider: "discord",
2068+Surface: "discord",
2069+ChatType: "direct",
2070+MessageSid: "msg",
2071+} as unknown as TemplateContext,
2072+}),
2073+resolvedVerboseLevel: "on",
2074+});
2075+2076+expect(result.kind).toBe("final");
2077+if (result.kind === "final") {
2078+expect(result.payload.text).toContain("Agent failed before reply");
2079+expect(result.payload.text).toContain("incomplete terminal response");
2080+}
2081+});
2082+2083+it("formats raw Codex API payloads before forwarding verbose external errors", async () => {
19652084state.runEmbeddedPiAgentMock.mockRejectedValueOnce(
19662085new Error(
19672086'Codex error: {"type":"error","error":{"type":"server_error","message":"Something exploded"},"sequence_number":2}',
@@ -1990,7 +2109,7 @@ describe("runAgentTurnWithFallback", () => {
19902109isHeartbeat: false,
19912110sessionKey: "main",
19922111getActiveSessionEntry: () => undefined,
1993-resolvedVerboseLevel: "off",
2112+resolvedVerboseLevel: "on",
19942113});
1995211419962115expect(result.kind).toBe("final");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。