fix: surface agentrun terminal errors in final response
This commit is contained in:
@@ -1447,6 +1447,14 @@ function agentRunResultToCodeAgentPayload({ base, result, traceStore, traceId, a
|
||||
const code = canceled ? "agentrun_canceled" : result?.failureKind ?? (terminalStatus === "blocked" ? "agentrun_blocked" : "agentrun_failed");
|
||||
const message = result?.failureMessage ?? result?.blocker?.message ?? (canceled ? "AgentRun command was canceled" : "AgentRun command failed");
|
||||
const attribution = agentRunFailureAttribution({ code, message, canceled });
|
||||
const finalResponse = agentRunTerminalFailureFinalResponse({
|
||||
base,
|
||||
traceId,
|
||||
now,
|
||||
status: canceled ? "canceled" : "failed",
|
||||
text: firstNonEmpty(message, attribution.summary, attribution.userMessage)
|
||||
});
|
||||
const traceSummary = agentRunTerminalFailureTraceSummary({ base, runnerTrace, finalResponse, traceId, terminalStatus: canceled ? "canceled" : terminalStatus || "failed" });
|
||||
if (appendResultEvent) {
|
||||
traceStore.append(traceId, {
|
||||
type: "result",
|
||||
@@ -1477,6 +1485,8 @@ function agentRunResultToCodeAgentPayload({ base, result, traceStore, traceId, a
|
||||
toolCalls: agentRunToolCalls(result, canceled ? "canceled" : "failed"),
|
||||
skills: { status: "delegated", provider: ADAPTER_ID, count: 0, items: [], valuesPrinted: false },
|
||||
providerTrace,
|
||||
finalResponse,
|
||||
traceSummary,
|
||||
error: {
|
||||
code,
|
||||
layer: "agentrun",
|
||||
@@ -1520,6 +1530,47 @@ function agentRunCompletedFinalResponse({ base, result, traceId, now }) {
|
||||
};
|
||||
}
|
||||
|
||||
function agentRunTerminalFailureFinalResponse({ base, traceId, now, status, text }) {
|
||||
const textValue = String(text ?? "").trim();
|
||||
return {
|
||||
text: textValue || "AgentRun command failed.",
|
||||
textChars: (textValue || "AgentRun command failed.").length,
|
||||
role: "assistant",
|
||||
status,
|
||||
traceId,
|
||||
messageId: base.messageId ?? base.reply?.messageId ?? `msg_${traceId.slice(4)}`,
|
||||
createdAt: base.reply?.createdAt ?? base.createdAt ?? now,
|
||||
updatedAt: now,
|
||||
valuesPrinted: false
|
||||
};
|
||||
}
|
||||
|
||||
function agentRunTerminalFailureTraceSummary({ base, runnerTrace, finalResponse, traceId, terminalStatus }) {
|
||||
const events = Array.isArray(runnerTrace?.events) ? runnerTrace.events : [];
|
||||
const lastSeq = Math.max(0, ...events.map((event) => Number(event?.seq ?? 0)).filter(Number.isFinite));
|
||||
return {
|
||||
traceId,
|
||||
source: "agentrun-command-result",
|
||||
sourceEventCount: Number(runnerTrace?.eventCount ?? events.length ?? 0),
|
||||
terminalStatus,
|
||||
finalAssistantRow: {
|
||||
role: finalResponse.role,
|
||||
status: finalResponse.status,
|
||||
textChars: finalResponse.textChars,
|
||||
textPreview: finalResponse.text.slice(0, 240),
|
||||
messageId: finalResponse.messageId,
|
||||
valuesPrinted: false
|
||||
},
|
||||
agentRun: {
|
||||
runId: base.agentRun?.runId ?? null,
|
||||
commandId: base.agentRun?.commandId ?? null,
|
||||
lastSeq,
|
||||
valuesPrinted: false
|
||||
},
|
||||
valuesPrinted: false
|
||||
};
|
||||
}
|
||||
|
||||
function agentRunCompletedTraceSummary({ base, runnerTrace, finalResponse, traceId }) {
|
||||
const events = Array.isArray(runnerTrace?.events) ? runnerTrace.events : [];
|
||||
const lastSeq = Math.max(0, ...events.map((event) => Number(event?.seq ?? 0)).filter(Number.isFinite));
|
||||
|
||||
@@ -1071,6 +1071,10 @@ test("cloud api AgentRun adapter exposes invalid tool-call attribution in result
|
||||
assert.match(payload.error.userMessage, /无效 tool-call arguments JSON/u);
|
||||
assert.match(payload.error.userMessage, /AgentRun\/provider/u);
|
||||
assert.match(payload.error.userMessage, /不是 HWPOD/u);
|
||||
assert.equal(payload.finalResponse.status, "failed");
|
||||
assert.match(payload.finalResponse.text, /invalid function arguments json string/u);
|
||||
assert.equal(payload.traceSummary.terminalStatus, "failed");
|
||||
assert.match(payload.traceSummary.finalAssistantRow.textPreview, /invalid function arguments json string/u);
|
||||
assert.equal(payload.blocker.category, "provider_invalid_tool_call");
|
||||
assert.match(payload.blocker.summary, /invalid function arguments json string/u);
|
||||
assert.equal(payload.session.status, "failed");
|
||||
|
||||
@@ -295,10 +295,11 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
if (message.traceId !== traceId || message.role !== "agent") return message;
|
||||
const runnerTrace = mergeTerminalResultTrace(message.runnerTrace, result as AgentChatResultResponse);
|
||||
const error = normalizeAgentError((result as AgentChatResultResponse).error ?? runnerTrace?.error ?? message.error);
|
||||
const errorText = agentErrorDisplayText(error);
|
||||
const agentRun = agentRunFromResult(result as AgentChatResultResponse, runnerTrace) ?? agentRunFromMessage(message);
|
||||
const replyText = agentReplyText((result as AgentChatResultResponse).reply);
|
||||
const text = terminal
|
||||
? firstNonEmptyString((result as AgentChatResultResponse).assistantText, finalResponseText((result as AgentChatResultResponse).finalResponse), replyText, (result as AgentChatResultResponse).text, (result as AgentChatResultResponse).summary, message.text, "Code Agent 已完成,但没有返回可展示的 final response。") ?? message.text
|
||||
? firstNonEmptyString((result as AgentChatResultResponse).assistantText, finalResponseText((result as AgentChatResultResponse).finalResponse), replyText, errorText, (result as AgentChatResultResponse).text, (result as AgentChatResultResponse).summary, message.text, "Code Agent 已完成,但没有返回可展示的 final response。") ?? message.text
|
||||
: message.text;
|
||||
return { ...message, status, text, runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined, updatedAt: new Date().toISOString() };
|
||||
});
|
||||
@@ -448,8 +449,9 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
const explicitStatus = normalizedStatusText(result.status);
|
||||
const status = explicitStatus ? statusFromResult(result.status) : message.status;
|
||||
const terminal = result.terminal === true || isTerminalMessageStatus(status);
|
||||
const text = terminal ? firstNonEmptyString(result.assistantText, finalResponseText(result.finalResponse), agentReplyText(result.reply), result.text, result.summary, message.text) ?? message.text : message.text;
|
||||
const error = normalizeAgentError(result.error ?? runnerTrace?.error ?? message.error);
|
||||
const errorText = agentErrorDisplayText(error);
|
||||
const text = terminal ? firstNonEmptyString(result.assistantText, finalResponseText(result.finalResponse), agentReplyText(result.reply), errorText, result.text, result.summary, message.text) ?? message.text : message.text;
|
||||
const agentRun = agentRunFromResult(result, runnerTrace) ?? agentRunFromMessage(message);
|
||||
return { ...message, status, text, runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined, updatedAt: new Date().toISOString() };
|
||||
});
|
||||
@@ -525,7 +527,7 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
}
|
||||
|
||||
function completeTrace(traceId: string, result: AgentChatResultResponse): void {
|
||||
const text = firstNonEmptyString(result.assistantText, finalResponseText(result.finalResponse), typeof result.reply === "string" ? result.reply : result.reply?.content, result.text, result.summary) ?? "Code Agent 已完成,但没有返回可展示的 final response。";
|
||||
const text = firstNonEmptyString(result.assistantText, finalResponseText(result.finalResponse), typeof result.reply === "string" ? result.reply : result.reply?.content, agentErrorDisplayText(result.error), result.text, result.summary) ?? "Code Agent 已完成,但没有返回可展示的 final response。";
|
||||
const terminalStatus = result.status === "completed" ? "completed" : statusFromResult(result.status);
|
||||
messages.value = messages.value.map((message) => {
|
||||
if (message.traceId !== traceId || message.role !== "agent") return message;
|
||||
@@ -732,11 +734,16 @@ function selectedConversationFromWorkspace(workspace: WorkspaceRecord | null): C
|
||||
}
|
||||
|
||||
function normalizeChatMessage(message: ChatMessage): ChatMessage {
|
||||
const text = firstNonEmptyString(message.text, messageText((message as Record<string, unknown>).content), messageText((message as Record<string, unknown>).message), finalResponseText((message as Record<string, unknown>).finalResponse)) ?? "";
|
||||
const runnerTrace = normalizeMessageRunnerTrace(message);
|
||||
const error = normalizeAgentError(message.error ?? runnerTrace?.error);
|
||||
const agentRun = agentRunFromMessage(message) ?? asAgentRun(runnerTrace?.agentRun);
|
||||
const status = normalizeChatMessageStatus(message.status);
|
||||
const baseText = firstNonEmptyString(message.text, messageText((message as Record<string, unknown>).content), messageText((message as Record<string, unknown>).message));
|
||||
const finalText = firstNonEmptyString(finalResponseText((message as Record<string, unknown>).finalResponse), finalResponseText(runnerTrace?.finalResponse));
|
||||
const errorText = agentErrorDisplayText(error);
|
||||
const text = message.role === "agent" && isTerminalMessageStatus(status)
|
||||
? firstNonEmptyString(finalText, errorText, baseText) ?? ""
|
||||
: firstNonEmptyString(baseText, finalText, errorText) ?? "";
|
||||
return { ...message, text, id: message.id ?? nextProtocolId("msg"), title: normalizeWorkbenchMessageTitle(message.role, message.title), createdAt: message.createdAt ?? new Date().toISOString(), status, runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined };
|
||||
}
|
||||
|
||||
@@ -847,6 +854,12 @@ function normalizeAgentError(value: unknown): ChatMessage["error"] | null {
|
||||
return { message: String(value) };
|
||||
}
|
||||
|
||||
function agentErrorDisplayText(value: unknown): string | null {
|
||||
const error = normalizeAgentError(value);
|
||||
if (!error) return null;
|
||||
return firstNonEmptyString(error.message, typeof error.userMessage === "string" ? error.userMessage : null, error.code ? `Code Agent 请求失败:${error.code}` : null);
|
||||
}
|
||||
|
||||
function isTerminalMessageStatus(value: unknown): boolean {
|
||||
return ["completed", "failed", "blocked", "timeout", "canceled", "cancelled", "stale", "thread-resume-failed"].includes(String(value ?? "").trim().toLowerCase().replace(/_/gu, "-"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user