diff --git a/packages/ui/src/components/message-item.tsx b/packages/ui/src/components/message-item.tsx index 3a1b6357..719d660d 100644 --- a/packages/ui/src/components/message-item.tsx +++ b/packages/ui/src/components/message-item.tsx @@ -1,5 +1,5 @@ import { For, Show, createSignal } from "solid-js" -import { Copy, Split, Trash2, Undo } from "lucide-solid" +import { Copy, ExternalLink, Split, Trash2, Undo } from "lucide-solid" import type { MessageInfo, ClientPart } from "../types/message" import { partHasRenderableText } from "../types/message" import type { MessageRecord } from "../stores/message-v2/types" @@ -8,6 +8,7 @@ import { copyToClipboard } from "../lib/clipboard" import { useI18n } from "../lib/i18n" import { showAlertDialog } from "../stores/alerts" import { deleteMessagePart } from "../stores/session-actions" +import { isTauriHost } from "../lib/runtime-env" interface MessageItemProps { record: MessageRecord @@ -45,6 +46,15 @@ export default function MessageItem(props: MessageItemProps) { const messageParts = () => props.parts + // User messages can temporarily include synthetic helper parts (e.g. tool traces / file reads). + // We only want to display the primary prompt text for the user message; other synthetic text + // parts should be hidden. + const primaryUserTextPartId = () => { + if (!isUser()) return null + const firstText = messageParts().find((part) => part?.type === "text") as { id?: string } | undefined + return typeof firstText?.id === "string" ? firstText.id : null + } + const fileAttachments = () => messageParts().filter((part): part is FilePart => part?.type === "file" && typeof (part as FilePart).url === "string") @@ -96,7 +106,8 @@ export default function MessageItem(props: MessageItemProps) { } if (url.startsWith("file://")) { - window.open(url, "_blank", "noopener") + // Local filesystem URLs are not reliably downloadable from the message stream. + // We hide the download action for these chips. return } @@ -373,6 +384,7 @@ export default function MessageItem(props: MessageItemProps) { messageType={props.record.role} instanceId={props.instanceId} sessionId={props.sessionId} + primaryUserTextPartId={primaryUserTextPartId()} onRendered={props.onContentRendered} /> )} @@ -399,17 +411,20 @@ export default function MessageItem(props: MessageItemProps) { {name} {name} - + + +