debug: add console logs to diagnose search-result card rendering issue

Add [thread-ui], [ui-debug], [tool-ui-match] console logs to trace
why searcher search-result cards show only skeleton after search completes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gongzhiyong
2026-04-13 13:15:32 +08:00
co-authored by Claude Sonnet 4.6
parent ffdb88677b
commit bb013af19f
2 changed files with 80 additions and 6 deletions
+19 -2
View File
@@ -246,13 +246,13 @@ function ToolCallRow({
</div>
</div>
)}
{expanded && !isFailed && !uiItem && (isPartial || isFallback) && (
{expanded && !isDone && !isFailed && !uiItem && (isPartial || isFallback) && (
<div className="mt-2 ml-7 space-y-2 animate-pulse">
<div className="h-3 bg-muted rounded w-3/4" />
<div className="h-3 bg-muted rounded w-1/2" />
</div>
)}
{expanded && !isFailed && !uiItem && !isPartial && !isFallback && (
{expanded && !isDone && !isFailed && !uiItem && !isPartial && !isFallback && (
<div className="mt-2 ml-7 space-y-2 animate-pulse">
<div className="h-3 bg-muted rounded w-3/4" />
<div className="h-3 bg-muted rounded w-1/2" />
@@ -284,8 +284,17 @@ export default function ToolCallStatus({
ticket_list: "ticket-summary",
ticket_detail: "ticket-detail",
web_search: "search-result",
google_search: "search-result",
web_search_deep: "search-result",
sandbox_run: "sandbox-result",
code_execute: "sandbox-result",
web_read: "web-read-progress",
doc_create: "canvas-doc",
doc_edit: "canvas-doc",
doc_translate: "canvas-doc",
report_generate: "canvas-doc",
reply_draft: "reply-draft",
chart_generate: "chart-result",
};
// Track how many times each ui component name has been matched, so multiple
@@ -344,6 +353,14 @@ export default function ToolCallStatus({
matchCounters[uiName] = (matchCounters[uiName] ?? 0) + 1;
}
console.log('[tool-ui-match]', {
toolName: tc.name,
uiName: tc.name ? UI_NAME_MAP[tc.name] : undefined,
uiItemsCount: uiItems.length,
uiItemNames: uiItems.map(u => u.name),
matched: !!uiItem,
});
// 优先按 toolCallId 精确匹配,降级按 index
const logEntry = executionLog
? (tc.id && executionLog.find(e => e.toolCallId === tc.id))
+61 -4
View File
@@ -233,6 +233,17 @@ function App() {
};
}, []);
// DEBUG: log all ui items in thread.values whenever they change
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ui = (thread.values as any)?.ui ?? [];
console.log('[thread-ui]', {
count: ui.length,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
items: ui.map((u: any) => ({ name: u.name, msgId: u.metadata?.message_id?.slice(0,8), cardId: u.props?.card_id })),
});
}, [thread.values]);
// Listen for prefill-input events from ActionBar
useEffect(() => {
const handler = (e: Event) => {
@@ -752,11 +763,48 @@ function App() {
const allUi: UIMsgLocal[] = thread.messages.length > 0
? ((thread.values as any)?.ui ?? [])
: historicalUi;
const uiItemsRaw = deduplicateUiItems(
allUi.filter(
(ui: UIMsgLocal) => ui.metadata?.message_id === message.id,
) as UIMsgLocal[]
// Match UI items by message_id; for subgraph messages where IDs
// may not align, fallback: attach orphaned items to the last AI message.
let matchedUi = allUi.filter(
(ui: UIMsgLocal) => ui.metadata?.message_id === message.id,
);
// Also adopt orphaned UI cards (no message_id or message_id not matching
// any activeMessage) — these come from subgraph tool-executors whose
// internal AIMessage IDs are not in the parent graph's message list.
if (
matchedUi.length === 0 &&
message.type === "ai" &&
idx === activeMessages.length - 1
) {
// Collect IDs already claimed by exact message_id match on other messages
const claimedIds = new Set(
activeMessages
.filter((_, i) => i !== idx)
.flatMap((m) =>
allUi
.filter((ui: UIMsgLocal) => ui.metadata?.message_id === m.id)
.map((ui: UIMsgLocal) => ui.id),
),
);
// Orphans: cards whose message_id is missing or doesn't match ANY message
const allMessageIds = new Set(activeMessages.map((m) => m.id));
matchedUi = allUi.filter(
(ui: UIMsgLocal) =>
!claimedIds.has(ui.id) &&
(!ui.metadata?.message_id || !allMessageIds.has(ui.metadata.message_id)),
);
}
console.log('[ui-debug]', {
messageId: message.id,
messageType: message.type,
allUiCount: allUi.length,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
allUiNames: allUi.map((u: any) => `${u.name}:${u.metadata?.message_id?.slice(0,8)}`),
matchedCount: matchedUi.length,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
toolCalls: (message as any).tool_calls?.map((tc: any) => tc.name),
});
const uiItemsRaw = deduplicateUiItems(matchedUi as UIMsgLocal[]);
// Sort by card type priority first, then by sort_key for deterministic order
const CARD_TYPE_PRIORITY: Record<string, number> = {
"error-result": 100,
@@ -885,8 +933,17 @@ function App() {
ticket_list: "ticket-summary",
ticket_detail: "ticket-detail",
web_search: "search-result",
google_search: "search-result",
web_search_deep: "search-result",
sandbox_run: "sandbox-result",
code_execute: "sandbox-result",
web_read: "web-read-progress",
doc_create: "canvas-doc",
doc_edit: "canvas-doc",
doc_translate: "canvas-doc",
report_generate: "canvas-doc",
reply_draft: "reply-draft",
chart_generate: "chart-result",
};
return tc.name && ui.name === nameMap[tc.name];
}));