Merge pull request #1446 from pikasTech/fix/1422-final-response-event-text
fix: 补齐 Workbench trace final response 兜底
This commit is contained in:
@@ -3,7 +3,7 @@ import test from "node:test";
|
||||
|
||||
import type { AgentRunProvenance, ChatMessage, TraceEvent } from "../src/types/index.ts";
|
||||
import { canCancelMessage, canRetryMessage, messageTraceId, renderSafeMarkdown, traceEventBody, traceEventLabel, traceIdentityText, visibleTraceEvents } from "../src/components/workbench/message-rendering.ts";
|
||||
import { mergeRunnerTrace } from "../src/composables/useTraceSubscription.ts";
|
||||
import { assistantTextFromTraceEvents, mergeRunnerTrace } from "../src/composables/useTraceSubscription.ts";
|
||||
import { traceDisplayRows, traceNoiseEventCount } from "../../../tools/src/hwlab-cli/trace-renderer.ts";
|
||||
|
||||
test("R1 markdown rendering keeps structure and strips unsafe HTML", () => {
|
||||
@@ -103,6 +103,16 @@ test("R1 trace API snapshots stay authoritative over compact result traces", ()
|
||||
assert.equal(merged.events?.[1]?.message, "OK");
|
||||
});
|
||||
|
||||
test("R1 trace event assistant text prefers authoritative final assistant message", () => {
|
||||
const events: TraceEvent[] = [
|
||||
{ seq: 1, label: "agentrun:backend:resource-bundle-materialized", message: "bundle ready" },
|
||||
{ seq: 2, label: "agentrun:assistant:message", type: "assistant", status: "running", replyAuthority: false, final: false, message: "我先检查当前状态。" },
|
||||
{ seq: 3, label: "agentrun:assistant:message", type: "assistant", status: "completed", replyAuthority: true, final: true, terminal: true, message: "OK" }
|
||||
];
|
||||
|
||||
assert.equal(assistantTextFromTraceEvents(events), "OK");
|
||||
});
|
||||
|
||||
test("R1 status summary keeps the restored 23-row floor", () => {
|
||||
const message = agentMessage({
|
||||
status: "failed",
|
||||
|
||||
@@ -347,7 +347,7 @@ function finalResponseText(value: unknown): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function assistantTextFromTraceEvents(events: TraceEvent[]): string | null {
|
||||
export function assistantTextFromTraceEvents(events: TraceEvent[]): string | null {
|
||||
const terminal = terminalAssistantTextFromTraceEvents(events);
|
||||
if (terminal) return terminal;
|
||||
for (let index = events.length - 1; index >= 0; index -= 1) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { computed, ref } from "vue";
|
||||
import { defineStore } from "pinia";
|
||||
import { api } from "@/api";
|
||||
import { connectWorkbenchEvents, type WorkbenchEventStream, type WorkbenchRealtimeEvent } from "@/api/workbench-events";
|
||||
import { mergeRunnerTrace, snapshotToRunnerTrace, type TraceSnapshot } from "@/composables/useTraceSubscription";
|
||||
import { assistantTextFromTraceEvents, mergeRunnerTrace, snapshotToRunnerTrace, type TraceSnapshot } from "@/composables/useTraceSubscription";
|
||||
import type { AgentChatResponse, AgentChatResultResponse, AgentRunProvenance, ApiResult, ChatMessage, ConversationRecord, LiveSurface, ProviderProfile, TraceEvent, WorkspaceRecord } from "@/types";
|
||||
import { DEFAULT_WORKBENCH_PROJECT_ID, firstNonEmptyString, nextProtocolId, normalizeWorkbenchConversationId, rememberWorkbenchProjectId, resolveInitialWorkbenchProjectId, workspaceProjectId } from "@/utils";
|
||||
import { failWorkbenchSessionSwitch, failWorkbenchSubmitJourney, finishWorkbenchSessionSwitchFullLoad, markWorkbenchSubmitApiAccepted, markWorkbenchTraceEventsReceived, markWorkbenchTraceProjected, startWorkbenchSessionSwitch, startWorkbenchSubmitJourney } from "@/utils/workbench-performance";
|
||||
@@ -459,8 +459,9 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
const errorText = agentErrorDisplayText(error);
|
||||
const agentRun = agentRunFromResult(result as AgentChatResultResponse, runnerTrace) ?? agentRunFromMessage(message);
|
||||
const replyText = agentReplyText((result as AgentChatResultResponse).reply);
|
||||
const traceAssistantText = assistantTextFromTraceEvents(firstArray((result as AgentChatResultResponse).events, (result as AgentChatResultResponse).traceEvents, runnerTrace?.events));
|
||||
const text = terminal
|
||||
? 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
|
||||
? firstNonEmptyString((result as AgentChatResultResponse).assistantText, finalResponseText((result as AgentChatResultResponse).finalResponse), replyText, errorText, (result as AgentChatResultResponse).text, (result as AgentChatResultResponse).summary, traceAssistantText, 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() };
|
||||
});
|
||||
@@ -660,7 +661,8 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
const terminal = result.terminal === true || isTerminalMessageStatus(status);
|
||||
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 traceAssistantText = assistantTextFromTraceEvents(events);
|
||||
const text = terminal ? firstNonEmptyString(result.assistantText, finalResponseText(result.finalResponse), agentReplyText(result.reply), errorText, result.text, result.summary, traceAssistantText, message.text) ?? message.text : message.text;
|
||||
const agentRun = agentRunFromResult(result, runnerTrace) ?? agentRunFromMessage(message);
|
||||
rememberTraceAuthority(runnerTrace);
|
||||
return { ...message, status, text, runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined, updatedAt: new Date().toISOString() };
|
||||
@@ -892,7 +894,9 @@ 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, agentErrorDisplayText(result.error), result.text, result.summary) ?? "Code Agent 已完成,但没有返回可展示的 final response。";
|
||||
const resultTrace = recordValue(result.runnerTrace);
|
||||
const traceAssistantText = assistantTextFromTraceEvents(firstArray(result.events, result.traceEvents, resultTrace?.events));
|
||||
const text = firstNonEmptyString(result.assistantText, finalResponseText(result.finalResponse), typeof result.reply === "string" ? result.reply : result.reply?.content, agentErrorDisplayText(result.error), result.text, result.summary, traceAssistantText) ?? "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;
|
||||
@@ -1230,10 +1234,11 @@ function normalizeChatMessage(message: ChatMessage): ChatMessage {
|
||||
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 traceAssistantText = assistantTextFromTraceEvents(Array.isArray(runnerTrace?.events) ? runnerTrace.events : []);
|
||||
const errorText = agentErrorDisplayText(error);
|
||||
const text = message.role === "agent" && isTerminalMessageStatus(status)
|
||||
? firstNonEmptyString(finalText, errorText, baseText) ?? ""
|
||||
: firstNonEmptyString(baseText, finalText, errorText) ?? "";
|
||||
? firstNonEmptyString(finalText, errorText, traceAssistantText, baseText) ?? ""
|
||||
: firstNonEmptyString(baseText, finalText, traceAssistantText, errorText) ?? "";
|
||||
const messageId = firstNonEmptyString((message as Record<string, unknown>).messageId, message.id) ?? nextProtocolId("msg");
|
||||
return { ...message, text, id: messageId, messageId, title: normalizeWorkbenchMessageTitle(message.role, message.title), createdAt: message.createdAt ?? new Date().toISOString(), status, runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user