From 0cdd13dcbe0ada5ddfdc98f65daf600c18e9c211 Mon Sep 17 00:00:00 2001 From: Adeniji Adekunle James Date: Tue, 19 Aug 2025 06:27:19 +0100 Subject: [PATCH] feat: add timestamp and message version to prompt (#944) (#959) ### Summary This PR implements a timestamp feature for messages in the prompt window, responding to feature request #944. **What this does:** - Prefixes each sent message with a timestamp and message version. ### Screenshot image --------- Co-authored-by: Will Chen Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> --- src/components/chat/ChatMessage.tsx | 65 ++++++++++++++++++++++++++++- src/ipc/ipc_types.ts | 1 + 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/components/chat/ChatMessage.tsx b/src/components/chat/ChatMessage.tsx index 7bb1e5a..0213f07 100644 --- a/src/components/chat/ChatMessage.tsx +++ b/src/components/chat/ChatMessage.tsx @@ -5,7 +5,12 @@ import { } from "./DyadMarkdownParser"; import { motion } from "framer-motion"; import { useStreamChat } from "@/hooks/useStreamChat"; -import { CheckCircle, XCircle } from "lucide-react"; +import { CheckCircle, XCircle, Clock, GitCommit } from "lucide-react"; +import { formatDistanceToNow, format } from "date-fns"; +import { useVersions } from "@/hooks/useVersions"; +import { useAtomValue } from "jotai"; +import { selectedAppIdAtom } from "@/atoms/appAtoms"; +import { useMemo } from "react"; interface ChatMessageProps { message: Message; @@ -14,13 +19,46 @@ interface ChatMessageProps { const ChatMessage = ({ message, isLastMessage }: ChatMessageProps) => { const { isStreaming } = useStreamChat(); + const appId = useAtomValue(selectedAppIdAtom); + const { versions: liveVersions } = useVersions(appId); + // Find the version that was active when this message was sent + const messageVersion = useMemo(() => { + if ( + message.role === "assistant" && + message.commitHash && + liveVersions.length + ) { + return ( + liveVersions.find( + (version) => + message.commitHash && + version.oid.slice(0, 7) === message.commitHash.slice(0, 7), + ) || null + ); + } + return null; + }, [message.commitHash, message.role, liveVersions]); + + // Format the message timestamp + const formatTimestamp = (timestamp: string | Date) => { + const now = new Date(); + const messageTime = new Date(timestamp); + const diffInHours = + (now.getTime() - messageTime.getTime()) / (1000 * 60 * 60); + if (diffInHours < 24) { + return formatDistanceToNow(messageTime, { addSuffix: true }); + } else { + return format(messageTime, "MMM d, yyyy 'at' h:mm a"); + } + }; + return (
-
+
{
)}
+ {/* Timestamp and commit info for assistant messages - only visible on hover */} + {message.role === "assistant" && message.createdAt && ( +
+
+ + {formatTimestamp(message.createdAt)} +
+ {messageVersion && messageVersion.message && ( +
+ + {messageVersion && messageVersion.message && ( + + { + messageVersion.message + .replace(/^\[dyad\]\s*/i, "") + .split("\n")[0] + } + + )} +
+ )} +
+ )}
); diff --git a/src/ipc/ipc_types.ts b/src/ipc/ipc_types.ts index 20c2d36..269fdd6 100644 --- a/src/ipc/ipc_types.ts +++ b/src/ipc/ipc_types.ts @@ -67,6 +67,7 @@ export interface Message { approvalState?: "approved" | "rejected" | null; commitHash?: string | null; dbTimestamp?: string | null; + createdAt?: Date | string; } export interface Chat {