From d787e2b2b7a53c046c106076bb5b04d976abc0c1 Mon Sep 17 00:00:00 2001 From: Ida Date: Fri, 12 Jun 2026 14:26:14 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20paste-as-a-file=20wurde=20korregiert,=20?= =?UTF-8?q?dass=20lange=20prompt=20dennoch=20in=20prompt=20fenster=20einge?= =?UTF-8?q?f=C3=BCgt=20wird=20und=20somit=20als=20prompt=20erkannt=20werde?= =?UTF-8?q?n;=20stattdessen=20anzeige=20als=20truncated=20nachricht=20(ab?= =?UTF-8?q?=201000=20w=C3=B6rter)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/views/workspace/ChatStream.tsx | 155 +++++++++++++------ src/pages/views/workspace/WorkspaceInput.tsx | 14 -- src/pages/views/workspace/WorkspacePage.tsx | 1 - 3 files changed, 108 insertions(+), 62 deletions(-) diff --git a/src/pages/views/workspace/ChatStream.tsx b/src/pages/views/workspace/ChatStream.tsx index 1146aab..c8295c1 100644 --- a/src/pages/views/workspace/ChatStream.tsx +++ b/src/pages/views/workspace/ChatStream.tsx @@ -33,6 +33,108 @@ interface ChatStreamProps { onOpenEditor?: () => void; } +const LONG_MESSAGE_WORD_LIMIT = 1000; +const COLLAPSED_PREVIEW_WORDS = 200; + +function _countWords(text: string): number { + const trimmed = text.trim(); + if (!trimmed) return 0; + return trimmed.split(/\s+/).length; +} + +function _truncateToWords(text: string, maxWords: number): string { + const words = text.trim().split(/\s+/); + if (words.length <= maxWords) return text; + return `${words.slice(0, maxWords).join(' ')}…`; +} + +const _MARKDOWN_COMPONENTS = { + code: _CodeBlock, + table: ({ children }: { children?: React.ReactNode }) => ( +
+ + {children} +
+
+ ), + th: ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ), + td: ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ), + a: ({ href, children }: { href?: string; children?: React.ReactNode }) => ( + + {children} + + ), + img: ({ src, alt, ...rest }: React.ImgHTMLAttributes) => + src ? {alt : null, +}; + +function _CollapsibleMessageMarkdown({ + text, + allowCollapse, +}: { + text: string; + allowCollapse: boolean; +}) { + const { t } = useLanguage(); + const [expanded, setExpanded] = useState(false); + const wordCount = _countWords(text); + const isLong = wordCount > LONG_MESSAGE_WORD_LIMIT; + const shouldTruncate = isLong && allowCollapse && !expanded; + const displayText = shouldTruncate ? _truncateToWords(text, COLLAPSED_PREVIEW_WORDS) : text; + + return ( + <> + + {displayText} + + {isLong && allowCollapse && ( + + )} + + ); +} + export const ChatStream: React.FC = ({ messages, agentProgress, isProcessing, @@ -49,6 +151,8 @@ export const ChatStream: React.FC = ({ messages, const enqueuedIdsRef = useRef>(new Set()); const [copiedId, setCopiedId] = useState(null); + const lastMessageId = messages.length > 0 ? messages[messages.length - 1].id : null; + const _handleCopy = useCallback((msgId: string, text: string) => { navigator.clipboard.writeText(text).then(() => { setCopiedId(msgId); @@ -157,53 +261,10 @@ export const ChatStream: React.FC = ({ messages, )} {msg.message && ( - ( -
- - {children} -
-
- ), - th: ({ children }) => ( - - {children} - - ), - td: ({ children }) => ( - - {children} - - ), - a: ({ href, children }) => ( - - {children} - - ), - img: ({ src, alt, ...rest }) => - src ? {alt : null, - }} - > - {msg.message} -
+ <_CollapsibleMessageMarkdown + text={msg.message} + allowCollapse={!(isProcessing && msg.id === lastMessageId && msg.role === 'assistant')} + /> )} {msg.documents && msg.documents.length > 0 && (
diff --git a/src/pages/views/workspace/WorkspaceInput.tsx b/src/pages/views/workspace/WorkspaceInput.tsx index 843a3bf..e953015 100644 --- a/src/pages/views/workspace/WorkspaceInput.tsx +++ b/src/pages/views/workspace/WorkspaceInput.tsx @@ -68,7 +68,6 @@ interface WorkspaceInputProps { onPendingAttachDsConsumed?: () => void; pendingAttachFdsId?: string; onPendingAttachFdsConsumed?: () => void; - onPasteAsFile?: (file: File) => void; draftAppend?: string; onDraftAppendConsumed?: () => void; workflowId?: string | null; @@ -136,7 +135,6 @@ export const WorkspaceInput = forwardRef) => { - if (!onPasteAsFile) return; - const text = e.clipboardData.getData('text/plain'); - if (text && text.length >= 1000) { - e.preventDefault(); - const blob = new Blob([text], { type: 'text/plain' }); - const file = new File([blob], `pasted-text-${Date.now()}.txt`, { type: 'text/plain' }); - onPasteAsFile(file); - } - }, [onPasteAsFile]); - const _isTreeMimeDrag = useCallback((e: React.DragEvent) => { const types = e.dataTransfer.types; return ( @@ -768,7 +755,6 @@ export const WorkspaceInput = forwardRef = ({ persistentInstance onPendingAttachDsConsumed={() => { setPendingAttachDsId(''); setPendingAttachDsLabel(''); }} pendingAttachFdsId={pendingAttachFdsId} onPendingAttachFdsConsumed={() => setPendingAttachFdsId('')} - onPasteAsFile={_uploadAndAttach} draftAppend={draftAppend} onDraftAppendConsumed={() => setDraftAppend('')} workflowId={workspace.workflowId}