Add debug transcript components
This commit is contained in:
123
web/components/debug-transcript/TranscriptList.tsx
Normal file
123
web/components/debug-transcript/TranscriptList.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { MessageSquare } from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
import TranscriptAssistantBlock from './TranscriptAssistantBlock';
|
||||
import TranscriptItem from './TranscriptItem';
|
||||
import type { DebugTranscriptRow, DebugTranscriptTextRow, DebugTranscriptToolRow } from './types';
|
||||
|
||||
type AssistantRenderBlock = {
|
||||
kind: 'assistant-block';
|
||||
id: string;
|
||||
message?: DebugTranscriptTextRow;
|
||||
tools: DebugTranscriptToolRow[];
|
||||
};
|
||||
|
||||
type TranscriptRenderItem =
|
||||
| { kind: 'row'; id: string; row: DebugTranscriptRow }
|
||||
| AssistantRenderBlock;
|
||||
|
||||
const getCorrelationKey = (row: Pick<DebugTranscriptRow, 'turnId' | 'utteranceId' | 'responseId'>) => {
|
||||
if (row.responseId) return `response:${row.responseId}`;
|
||||
if (row.turnId && row.utteranceId) return `turn:${row.turnId}:utterance:${row.utteranceId}`;
|
||||
if (row.turnId) return `turn:${row.turnId}`;
|
||||
if (row.utteranceId) return `utterance:${row.utteranceId}`;
|
||||
return '';
|
||||
};
|
||||
|
||||
const buildRenderItems = (messages: DebugTranscriptRow[]): TranscriptRenderItem[] => {
|
||||
const items: TranscriptRenderItem[] = [];
|
||||
const assistantBlocks = new Map<string, AssistantRenderBlock>();
|
||||
|
||||
messages.forEach((row) => {
|
||||
if (row.kind === 'text' && row.role === 'assistant') {
|
||||
const correlationKey = getCorrelationKey(row);
|
||||
if (!correlationKey) {
|
||||
items.push({ kind: 'row', id: row.id, row });
|
||||
return;
|
||||
}
|
||||
|
||||
const existingBlock = assistantBlocks.get(correlationKey);
|
||||
if (existingBlock) {
|
||||
existingBlock.message = row;
|
||||
return;
|
||||
}
|
||||
|
||||
const block: AssistantRenderBlock = {
|
||||
kind: 'assistant-block',
|
||||
id: `assistant-block:${correlationKey}`,
|
||||
message: row,
|
||||
tools: [],
|
||||
};
|
||||
assistantBlocks.set(correlationKey, block);
|
||||
items.push(block);
|
||||
return;
|
||||
}
|
||||
|
||||
if (row.kind === 'tool') {
|
||||
const correlationKey = getCorrelationKey(row);
|
||||
if (!correlationKey) {
|
||||
items.push({ kind: 'row', id: row.id, row });
|
||||
return;
|
||||
}
|
||||
|
||||
const existingBlock = assistantBlocks.get(correlationKey);
|
||||
if (existingBlock) {
|
||||
existingBlock.tools.push(row);
|
||||
return;
|
||||
}
|
||||
|
||||
const block: AssistantRenderBlock = {
|
||||
kind: 'assistant-block',
|
||||
id: `assistant-block:${correlationKey}`,
|
||||
tools: [row],
|
||||
};
|
||||
assistantBlocks.set(correlationKey, block);
|
||||
items.push(block);
|
||||
return;
|
||||
}
|
||||
|
||||
items.push({ kind: 'row', id: row.id, row });
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
const TranscriptList: React.FC<{
|
||||
scrollRef: React.RefObject<HTMLDivElement | null>;
|
||||
messages: DebugTranscriptRow[];
|
||||
isLoading: boolean;
|
||||
className?: string;
|
||||
}> = ({ scrollRef, messages, isLoading, className = '' }) => {
|
||||
const renderItems = useMemo(() => buildRenderItems(messages), [messages]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className={cn(
|
||||
'flex-1 overflow-y-auto overflow-x-hidden rounded-md border border-white/5 bg-black/20 p-2 min-h-0 custom-scrollbar',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{messages.length === 0 && !isLoading ? (
|
||||
<div className="flex h-full flex-col items-center justify-center space-y-3 text-muted-foreground/60">
|
||||
<MessageSquare className="h-8 w-8 opacity-20" />
|
||||
<p className="text-xs">鏆傛棤瀵硅瘽璁板綍</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4 pb-4">
|
||||
{renderItems.map((item) =>
|
||||
item.kind === 'assistant-block' ? (
|
||||
<TranscriptAssistantBlock key={item.id} message={item.message} tools={item.tools} />
|
||||
) : (
|
||||
<TranscriptItem key={item.id} row={item.row} />
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(TranscriptList);
|
||||
Reference in New Issue
Block a user