























11/**
22 * Classifies embedded-agent run results for model fallback decisions.
33 */
4+import { GENERIC_EXTERNAL_RUN_FAILURE_TEXT } from "../../auto-reply/reply/agent-runner-failure-copy.js";
45import { isSilentReplyPayloadText } from "../../auto-reply/tokens.js";
56import { classifyFailoverReason } from "../embedded-agent-helpers/errors.js";
67import type { FailoverReason } from "../embedded-agent-helpers/types.js";
@@ -15,8 +16,9 @@ import type { EmbeddedAgentRunResult } from "./types.js";
1516/**
1617 * Classifies embedded-agent terminal results for model fallback decisions.
1718 *
18- * The classifier only flags failed invisible outcomes; delivered messages, deliberate silent
19- * replies, hook blocks, and aborts must not trigger another model attempt.
19+ * The classifier only flags failed invisible outcomes or exact generic external-runner failure
20+ * copy; delivered messages, deliberate silent replies, hook blocks, and aborts must not trigger
21+ * another model attempt.
2022 */
2123function isEmbeddedAgentRunResult(value: unknown): value is EmbeddedAgentRunResult {
2224return Boolean(
@@ -74,6 +76,47 @@ function hasDeliberateSilentTerminalReply(result: EmbeddedAgentRunResult): boole
7476);
7577}
767879+function hasNonTextVisiblePayloadContent(
80+payload: NonNullable<EmbeddedAgentRunResult["payloads"]>[number],
81+): boolean {
82+const { text: _text, ...payloadWithoutText } = payload;
83+return hasVisibleAgentPayload(
84+{ payloads: [payloadWithoutText] },
85+{
86+includeErrorPayloads: false,
87+includeReasoningPayloads: false,
88+},
89+);
90+}
91+92+function classifyGenericExternalRunFailurePayload(params: {
93+provider: string;
94+model: string;
95+result: EmbeddedAgentRunResult;
96+}): ModelFallbackResultClassification {
97+const payloads = params.result.payloads;
98+if (!Array.isArray(payloads) || payloads.length !== 1) {
99+return null;
100+}
101+const [payload] = payloads;
102+const text = payload?.text;
103+if (
104+payload?.isError === true ||
105+payload?.isReasoning === true ||
106+typeof text !== "string" ||
107+text.trim() !== GENERIC_EXTERNAL_RUN_FAILURE_TEXT ||
108+hasNonTextVisiblePayloadContent(payload)
109+) {
110+return null;
111+}
112+return {
113+message: `${params.provider}/${params.model} ended with a generic external runner failure: ${text}`,
114+reason: "format",
115+code: "generic_external_run_failure",
116+rawError: text,
117+};
118+}
119+77120function classifyHarnessResult(params: {
78121provider: string;
79122model: string;
@@ -136,11 +179,7 @@ export function classifyEmbeddedAgentRunResultForModelFallback(params: {
136179if (
137180params.result.meta.aborted ||
138181params.hasDirectlySentBlockReply === true ||
139-params.hasBlockReplyPipelineOutput === true ||
140-hasVisibleAgentPayload(params.result, {
141-includeErrorPayloads: false,
142-includeReasoningPayloads: false,
143-})
182+params.hasBlockReplyPipelineOutput === true
144183) {
145184return null;
146185}
@@ -161,6 +200,22 @@ export function classifyEmbeddedAgentRunResultForModelFallback(params: {
161200return null;
162201}
163202const payloads = params.result.payloads ?? [];
203+const genericExternalFailureClassification = classifyGenericExternalRunFailurePayload({
204+provider: params.provider,
205+model: params.model,
206+result: params.result,
207+});
208+if (genericExternalFailureClassification) {
209+return genericExternalFailureClassification;
210+}
211+if (
212+hasVisibleAgentPayload(params.result, {
213+includeErrorPayloads: false,
214+includeReasoningPayloads: false,
215+})
216+) {
217+return null;
218+}
164219165220if (fallbackSafeIncompleteTurn) {
166221const terminalErrorText = payloads.find(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。