import { CheckCircleFilled, CloseCircleFilled, LoadingOutlined } from "@ant-design/icons"; import { Collapse, Flex, Typography } from "antd"; import { HighlightBlock } from "./HighlightBlock"; import type { PartProps } from "./types"; interface ToolPartData { errorText?: string; input?: unknown; output?: unknown; toolCallId?: string; toolMetadata?: Record; toolName?: string; type?: string; } function getToolState(part: ToolPartData) { if ("errorText" in part && part.errorText) return "output-error" as const; if ("output" in part) return "output-available" as const; if ("input" in part) return "input-available" as const; return "input-streaming" as const; } function getInputLang(value: unknown): string { return typeof value === "object" && value !== null ? "json" : "text"; } function getOutputLang(value: unknown): string { return typeof value === "object" && value !== null ? "json" : "text"; } function formatContent(value: unknown): string { if (typeof value === "object" && value !== null) return JSON.stringify(value, null, 2); if (typeof value === "string") return value; return String(value); } export function ToolPart({ part }: PartProps) { const toolPart = part as unknown as ToolPartData; const state = getToolState(toolPart); const rawToolName = toolPart.toolName ?? (toolPart.type ?? "unknown").replace(/^tool-/, ""); const toolName = typeof toolPart.toolMetadata?.["displayName"] === "string" ? toolPart.toolMetadata["displayName"] : rawToolName; const isStreaming = state === "input-streaming" || state === "input-available"; const formattedInput = toolPart.input != null ? formatContent(toolPart.input) : ""; const inputLang = toolPart.input != null ? getInputLang(toolPart.input) : "text"; const hasOutput = "output" in toolPart && toolPart.output != null; const formattedOutput = hasOutput ? formatContent(toolPart.output) : ""; const outputLang = hasOutput ? getOutputLang(toolPart.output) : "text"; if (state === "output-error") { return ( 错误 ), key: toolPart.toolCallId ?? toolName, label: ( {toolName} 失败 ), }, ]} size="small" /> ); } return ( {toolPart.input != null && (
入参
)} {hasOutput && (
出参
)} {!toolPart.input && !("output" in toolPart) && ( 生成中... )} ), key: toolPart.toolCallId ?? toolName, label: isStreaming ? ( {state === "input-streaming" ? "生成参数" : `调用 ${toolName}`} ) : ( {toolName} ), }, ]} size="small" /> ); }