fix(web): show live agent work progress and fail truncated rectification answers
Rectification dropped tool.activity started events and treated length finishes as completed. Share generation settings with consultation, keep the activity line through streaming, and name multi-domain chart calculation. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,7 +4,12 @@ import { ArrowUp, Square } from "lucide-react";
|
||||
import { useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { parseAgentReply } from "@/lib/agent-reply";
|
||||
import type { ChatMessage, ChatMessageView } from "@/lib/chat-message-view";
|
||||
import { nextActivityView, type ChatMessage, type ChatMessageView } from "@/lib/chat-message-view";
|
||||
import {
|
||||
RECTIFICATION_TOOL_PROGRESS_LABELS,
|
||||
rectificationCompletedTrail,
|
||||
rectificationToolActivityPhase,
|
||||
} from "@/lib/rectification-activity-labels";
|
||||
import {
|
||||
createRectificationActivityReceiptState,
|
||||
receiptFromRectificationActivityState,
|
||||
@@ -348,7 +353,11 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
...(action === "message"
|
||||
? [{ role: "user", text: trimmed, renderKey: userRenderKey, state: "settled" } satisfies RenderMessage]
|
||||
: []),
|
||||
{ role: "assistant", text: "", renderKey: assistantRenderKey, state: "thinking" },
|
||||
{ role: "assistant", text: "", renderKey: assistantRenderKey, state: "thinking", activity: {
|
||||
phase: "evidence-validation",
|
||||
label: "正在处理…",
|
||||
startedAt: Date.now(),
|
||||
} },
|
||||
]);
|
||||
setDraft("");
|
||||
|
||||
@@ -426,7 +435,15 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
raw += event.text;
|
||||
const parsed = parseAgentReply(raw);
|
||||
setMessages((current) => current.map((message) => message.renderKey === assistantRenderKey
|
||||
? { ...message, text: parsed.text, state: "streaming" }
|
||||
? {
|
||||
...message,
|
||||
text: parsed.text,
|
||||
state: "streaming",
|
||||
activity: nextActivityView(message.activity, {
|
||||
phase: "answer-composition",
|
||||
label: "正在组织回答…",
|
||||
}),
|
||||
}
|
||||
: message));
|
||||
} else if (event.type === "attempt.reset") {
|
||||
raw = "";
|
||||
@@ -434,7 +451,18 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
completedReceipt = receiptFromRectificationActivityState(activityReceiptState);
|
||||
completedTurnId = undefined;
|
||||
setMessages((current) => current.map((message) => message.renderKey === assistantRenderKey
|
||||
? { ...message, text: "", state: "thinking", completedReceipt: undefined, failed: false, turnId: undefined }
|
||||
? {
|
||||
...message,
|
||||
text: "",
|
||||
state: "thinking",
|
||||
completedReceipt: undefined,
|
||||
failed: false,
|
||||
turnId: undefined,
|
||||
activity: nextActivityView(undefined, {
|
||||
phase: "evidence-validation",
|
||||
label: "正在处理…",
|
||||
}),
|
||||
}
|
||||
: message));
|
||||
} else if (event.type === "run.failed") {
|
||||
streamFailed = true;
|
||||
@@ -447,7 +475,19 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
} else if (event.type === "tool.activity") {
|
||||
const tool = isPublicRectificationTool(event.tool) ? event.tool : null;
|
||||
if (!tool) continue;
|
||||
if (event.status === "started") continue;
|
||||
if (event.status === "started") {
|
||||
setMessages((current) => current.map((message) => message.renderKey === assistantRenderKey
|
||||
? {
|
||||
...message,
|
||||
activity: nextActivityView(message.activity, {
|
||||
phase: rectificationToolActivityPhase(tool),
|
||||
label: RECTIFICATION_TOOL_PROGRESS_LABELS[tool],
|
||||
completedTrail: rectificationCompletedTrail(activityReceiptState.completedSteps),
|
||||
}),
|
||||
}
|
||||
: message));
|
||||
continue;
|
||||
}
|
||||
if (event.status !== "completed" && event.status !== "failed") continue;
|
||||
activityReceiptState = reduceRectificationActivityReceipt(activityReceiptState, {
|
||||
tool,
|
||||
@@ -473,20 +513,24 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
completedReceipt,
|
||||
failed: false,
|
||||
turnId: completedTurnId,
|
||||
activity: undefined,
|
||||
}];
|
||||
}
|
||||
if (streamFailed || hasActivityReceipt(completedReceipt)) {
|
||||
if (streamFailed || hasActivityReceipt(completedReceipt) || parsed.text) {
|
||||
return [{
|
||||
...message,
|
||||
text: "",
|
||||
text: parsed.text,
|
||||
state: "settled",
|
||||
completedReceipt,
|
||||
failed: true,
|
||||
activity: undefined,
|
||||
}];
|
||||
}
|
||||
return [];
|
||||
}));
|
||||
if (!succeeded && completedReceipt.failedTool) {
|
||||
if (!succeeded && parsed.text) {
|
||||
setError((current) => current || "回答未完成,已保留现有内容;本次不会扣点。");
|
||||
} else if (!succeeded && completedReceipt.failedTool) {
|
||||
setError(completedReceipt.failedTool === "rectification-compare-candidates"
|
||||
? "候选比较未完成,当前进度已保留。"
|
||||
: "本轮处理未完成,当前进度已保留。请稍后再试。");
|
||||
@@ -719,7 +763,15 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
&& !readonly
|
||||
&& regeneratingMessageKey === null;
|
||||
const displayedMessage = regenerating
|
||||
? { ...message, text: "", state: "thinking" as const }
|
||||
? {
|
||||
...message,
|
||||
text: "",
|
||||
state: "thinking" as const,
|
||||
activity: nextActivityView(undefined, {
|
||||
phase: "answer-composition",
|
||||
label: "正在组织回答…",
|
||||
}),
|
||||
}
|
||||
: message;
|
||||
const vargaSentence = message.state === "settled" && !message.failed
|
||||
? vargaSentenceFromMethods(message.completedReceipt?.methods)
|
||||
@@ -728,13 +780,15 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
<div key={message.renderKey} className="rectification-message-wrap rectification-message-entry">
|
||||
{message.state === "settled" && message.failed && (
|
||||
<p className="rectification-activity-failure" role="status">
|
||||
本轮处理未完成,已保留服务端记录的执行进度。
|
||||
{message.text
|
||||
? "回答未完成,已保留现有内容;本次不会扣点。"
|
||||
: "本轮处理未完成,已保留服务端记录的执行进度。"}
|
||||
</p>
|
||||
)}
|
||||
{(!message.failed || Boolean(displayedMessage.text) || regenerating) && (
|
||||
<ChatMessageRow
|
||||
message={displayedMessage}
|
||||
showActivity={displayedMessage.state === "thinking"}
|
||||
showActivity={displayedMessage.state !== "settled"}
|
||||
vargaSentence={vargaSentence}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user