mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-05-23 16:35:59 +00:00
fix(feedback): correct run_id mapping for feedback echo
The feedbackMap was keyed by run_id but looked up by LangGraph message ID. Fixed by tracking AI message ordinal index to correlate event store run_ids with LangGraph SDK messages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
|||||||
Conversation,
|
Conversation,
|
||||||
ConversationContent,
|
ConversationContent,
|
||||||
} from "@/components/ai-elements/conversation";
|
} from "@/components/ai-elements/conversation";
|
||||||
|
import type { FeedbackData } from "@/core/api/feedback";
|
||||||
import { useI18n } from "@/core/i18n/hooks";
|
import { useI18n } from "@/core/i18n/hooks";
|
||||||
import {
|
import {
|
||||||
extractContentFromMessage,
|
extractContentFromMessage,
|
||||||
@@ -18,6 +19,7 @@ import { useRehypeSplitWordsIntoSpans } from "@/core/rehype";
|
|||||||
import type { Subtask } from "@/core/tasks";
|
import type { Subtask } from "@/core/tasks";
|
||||||
import { useUpdateSubtask } from "@/core/tasks/context";
|
import { useUpdateSubtask } from "@/core/tasks/context";
|
||||||
import type { AgentThreadState } from "@/core/threads";
|
import type { AgentThreadState } from "@/core/threads";
|
||||||
|
import { useThreadFeedback } from "@/core/threads/hooks";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
import { ArtifactFileList } from "../artifacts/artifact-file-list";
|
import { ArtifactFileList } from "../artifacts/artifact-file-list";
|
||||||
@@ -46,7 +48,11 @@ export function MessageList({
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const rehypePlugins = useRehypeSplitWordsIntoSpans(thread.isLoading);
|
const rehypePlugins = useRehypeSplitWordsIntoSpans(thread.isLoading);
|
||||||
const updateSubtask = useUpdateSubtask();
|
const updateSubtask = useUpdateSubtask();
|
||||||
|
const { data: feedbackData } = useThreadFeedback(threadId);
|
||||||
const messages = thread.messages;
|
const messages = thread.messages;
|
||||||
|
|
||||||
|
// Track AI message ordinal index for feedback mapping
|
||||||
|
let aiMessageIndex = 0;
|
||||||
if (thread.isThreadLoading && messages.length === 0) {
|
if (thread.isThreadLoading && messages.length === 0) {
|
||||||
return <MessageListSkeleton />;
|
return <MessageListSkeleton />;
|
||||||
}
|
}
|
||||||
@@ -58,12 +64,23 @@ export function MessageList({
|
|||||||
{groupMessages(messages, (group) => {
|
{groupMessages(messages, (group) => {
|
||||||
if (group.type === "human" || group.type === "assistant") {
|
if (group.type === "human" || group.type === "assistant") {
|
||||||
return group.messages.map((msg) => {
|
return group.messages.map((msg) => {
|
||||||
|
let runId: string | undefined;
|
||||||
|
let feedback: FeedbackData | null = null;
|
||||||
|
if (msg.type !== "human" && feedbackData) {
|
||||||
|
runId =
|
||||||
|
feedbackData.runIdByAiIndex[aiMessageIndex] ?? undefined;
|
||||||
|
feedback = runId
|
||||||
|
? (feedbackData.feedbackByRunId[runId] ?? null)
|
||||||
|
: null;
|
||||||
|
aiMessageIndex++;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<MessageListItem
|
<MessageListItem
|
||||||
key={`${group.id}/${msg.id}`}
|
key={`${group.id}/${msg.id}`}
|
||||||
message={msg}
|
message={msg}
|
||||||
isLoading={thread.isLoading}
|
isLoading={thread.isLoading}
|
||||||
threadId={threadId}
|
runId={runId}
|
||||||
|
feedback={feedback}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -167,7 +184,7 @@ export function MessageList({
|
|||||||
results.push(
|
results.push(
|
||||||
<div
|
<div
|
||||||
key="subtask-count"
|
key="subtask-count"
|
||||||
className="text-muted-foreground pt-2 text-sm font-normal"
|
className="text-muted-foreground font-norma pt-2 text-sm"
|
||||||
>
|
>
|
||||||
{t.subtasks.executing(tasks.size)}
|
{t.subtasks.executing(tasks.size)}
|
||||||
</div>,
|
</div>,
|
||||||
|
|||||||
@@ -679,15 +679,29 @@ export function useRenameThread() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ThreadFeedbackData {
|
||||||
|
/** Maps AI message ordinal index (0-based, counting only AI messages) to run_id */
|
||||||
|
runIdByAiIndex: string[];
|
||||||
|
/** Maps run_id to feedback data */
|
||||||
|
feedbackByRunId: Record<
|
||||||
|
string,
|
||||||
|
{ feedback_id: string; rating: number; comment: string | null }
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
export function useThreadFeedback(threadId: string | null | undefined) {
|
export function useThreadFeedback(threadId: string | null | undefined) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["thread-feedback", threadId],
|
queryKey: ["thread-feedback", threadId],
|
||||||
queryFn: async () => {
|
queryFn: async (): Promise<ThreadFeedbackData> => {
|
||||||
if (!threadId) return {};
|
const empty: ThreadFeedbackData = {
|
||||||
|
runIdByAiIndex: [],
|
||||||
|
feedbackByRunId: {},
|
||||||
|
};
|
||||||
|
if (!threadId) return empty;
|
||||||
const res = await fetchWithAuth(
|
const res = await fetchWithAuth(
|
||||||
`${getBackendBaseURL()}/api/threads/${encodeURIComponent(threadId)}/messages?limit=200`,
|
`${getBackendBaseURL()}/api/threads/${encodeURIComponent(threadId)}/messages?limit=200`,
|
||||||
);
|
);
|
||||||
if (!res.ok) return {};
|
if (!res.ok) return empty;
|
||||||
const messages: Array<{
|
const messages: Array<{
|
||||||
run_id: string;
|
run_id: string;
|
||||||
event_type: string;
|
event_type: string;
|
||||||
@@ -697,16 +711,20 @@ export function useThreadFeedback(threadId: string | null | undefined) {
|
|||||||
comment: string | null;
|
comment: string | null;
|
||||||
} | null;
|
} | null;
|
||||||
}> = await res.json();
|
}> = await res.json();
|
||||||
const feedbackMap: Record<
|
const runIdByAiIndex: string[] = [];
|
||||||
|
const feedbackByRunId: Record<
|
||||||
string,
|
string,
|
||||||
{ feedback_id: string; rating: number; comment: string | null }
|
{ feedback_id: string; rating: number; comment: string | null }
|
||||||
> = {};
|
> = {};
|
||||||
for (const msg of messages) {
|
for (const msg of messages) {
|
||||||
|
if (msg.event_type === "ai_message") {
|
||||||
|
runIdByAiIndex.push(msg.run_id);
|
||||||
|
}
|
||||||
if (msg.feedback && msg.run_id) {
|
if (msg.feedback && msg.run_id) {
|
||||||
feedbackMap[msg.run_id] = msg.feedback;
|
feedbackByRunId[msg.run_id] = msg.feedback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return feedbackMap;
|
return { runIdByAiIndex, feedbackByRunId };
|
||||||
},
|
},
|
||||||
enabled: !!threadId,
|
enabled: !!threadId,
|
||||||
staleTime: 30_000,
|
staleTime: 30_000,
|
||||||
|
|||||||
Reference in New Issue
Block a user