feat: 聊天室对话渲染增强 - 思考内容Markdown渲染 + 工具调用参数卡片化
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
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 {
|
||||
@@ -20,7 +21,19 @@ function getToolState(part: ToolPartData) {
|
||||
return "input-streaming" as const;
|
||||
}
|
||||
|
||||
const FORMAT_JSON = (v: unknown) => JSON.stringify(v, null, 2);
|
||||
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;
|
||||
@@ -31,13 +44,25 @@ export function ToolPart({ part }: PartProps) {
|
||||
|
||||
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 (
|
||||
<Collapse
|
||||
ghost
|
||||
items={[
|
||||
{
|
||||
children: <Typography.Text type="danger">{toolPart.errorText}</Typography.Text>,
|
||||
children: (
|
||||
<div className="tool-call-section">
|
||||
<Typography.Text type="danger">错误</Typography.Text>
|
||||
<HighlightBlock code={toolPart.errorText!} isStreaming={false} lang="text" />
|
||||
</div>
|
||||
),
|
||||
key: toolPart.toolCallId ?? toolName,
|
||||
label: (
|
||||
<Flex align="center" component="span" gap={4}>
|
||||
@@ -59,18 +84,18 @@ export function ToolPart({ part }: PartProps) {
|
||||
items={[
|
||||
{
|
||||
children: (
|
||||
<Flex gap={4} vertical>
|
||||
<Flex gap={8} vertical>
|
||||
{toolPart.input != null && (
|
||||
<>
|
||||
<Typography.Text type="secondary">参数:</Typography.Text>
|
||||
<pre className="tool-result-pre">{FORMAT_JSON(toolPart.input)}</pre>
|
||||
</>
|
||||
<div className="tool-call-section">
|
||||
<Typography.Text type="secondary">入参</Typography.Text>
|
||||
<HighlightBlock code={formattedInput} isStreaming={isStreaming} lang={inputLang} />
|
||||
</div>
|
||||
)}
|
||||
{"output" in toolPart && toolPart.output != null && (
|
||||
<>
|
||||
<Typography.Text type="secondary">结果:</Typography.Text>
|
||||
<pre className="tool-result-pre">{FORMAT_JSON(toolPart.output)}</pre>
|
||||
</>
|
||||
{hasOutput && (
|
||||
<div className="tool-call-section">
|
||||
<Typography.Text type="secondary">出参</Typography.Text>
|
||||
<HighlightBlock code={formattedOutput} isStreaming={isStreaming} lang={outputLang} />
|
||||
</div>
|
||||
)}
|
||||
{!toolPart.input && !("output" in toolPart) && (
|
||||
<Typography.Text type="secondary">生成中...</Typography.Text>
|
||||
|
||||
Reference in New Issue
Block a user