mirror of
https://github.com/basketikun/infinite-canvas.git
synced 2026-08-05 00:34:22 +08:00
feat(agent): implement streamdown for real-time message rendering in chat
This commit is contained in:
+2
-1
@@ -35,6 +35,7 @@
|
||||
"react-router": "^7.12.0",
|
||||
"react-router-dom": "^7.12.0",
|
||||
"shadcn": "^4.7.0",
|
||||
"streamdown": "^2.5.0",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"tailwindcss": "^4",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
@@ -42,11 +43,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@vitejs/plugin-react": "^5.2.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "19.1.12",
|
||||
"@types/react-dom": "19.1.9",
|
||||
"@vitejs/plugin-react": "^5.2.0",
|
||||
"prettier": "^3.8.3",
|
||||
"typescript": "^5",
|
||||
"vite": "^7.3.0"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState, type ReactNode } from "react";
|
||||
import { Button, Tooltip } from "antd";
|
||||
import { ArrowUp, CheckCircle2, CircleAlert, ImagePlus, LoaderCircle, Square, UserRound, Wrench, X, XCircle } from "lucide-react";
|
||||
import { Streamdown } from "streamdown";
|
||||
|
||||
import { isPlainEnterKey } from "@/lib/keyboard-event";
|
||||
import { canvasThemes } from "@/lib/canvas-theme";
|
||||
@@ -15,6 +16,8 @@ export type CanvasAgentChatMessage = {
|
||||
meta?: string;
|
||||
detail?: unknown;
|
||||
attachments?: CanvasAgentChatAttachment[];
|
||||
/** Present while the message is actively streaming; cleared on completion. */
|
||||
streamId?: string;
|
||||
};
|
||||
|
||||
const WORKING_TEXT = "working...";
|
||||
@@ -46,7 +49,11 @@ export function AgentChatMessage({ item, theme, user, onRejectTool, onApproveToo
|
||||
<div className={`flex items-start gap-3 ${isUser ? "justify-end" : "justify-start"}`}>
|
||||
{!isUser ? <AgentAvatar theme={theme} /> : null}
|
||||
<div className={`min-w-0 max-w-[82%] text-sm leading-6 ${isUser ? "text-right" : "text-left"}`} style={{ color }}>
|
||||
<div className="whitespace-pre-wrap break-words text-left">{item.text}</div>
|
||||
{isUser ? (
|
||||
<div className="whitespace-pre-wrap break-words text-left">{item.text}</div>
|
||||
) : (
|
||||
<Streamdown animated isAnimating={!!item.streamId}>{item.text}</Streamdown>
|
||||
)}
|
||||
{item.attachments?.length ? <AgentMessageAttachments attachments={item.attachments} /> : null}
|
||||
{item.meta ? <div className="mt-1 text-[11px] opacity-45">{item.meta}</div> : null}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "antd/dist/reset.css";
|
||||
import "streamdown/styles.css";
|
||||
import "./styles/globals.css";
|
||||
import { RouterProvider } from "react-router-dom";
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
@source "../../../node_modules/streamdown/dist/*.js";
|
||||
@import "shadcn/tailwind.css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
Reference in New Issue
Block a user