Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions frontend/app/chat/_components/assistant-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ const MarkdownRenderer = dynamic(
{ ssr: false },
);

import { trackButton } from "@/lib/analytics";
import { cn } from "@/lib/utils";
import type {
FunctionCall,
TokenUsage as TokenUsageType,
} from "../_types/types";
import { FunctionCalls } from "./function-calls";
import { Message } from "./message";
import MessageActions from "./message-actions";
import { TokenUsage } from "./token-usage";

interface AssistantMessageProps {
Expand All @@ -35,6 +37,8 @@ interface AssistantMessageProps {
delay?: number;
isInitialGreeting?: boolean;
usage?: TokenUsageType;
timestamp?: Date;
showFeedback?: boolean;
}

export function AssistantMessage({
Expand All @@ -52,7 +56,19 @@ export function AssistantMessage({
delay = 0.2,
isInitialGreeting = false,
usage,
timestamp,
showFeedback = true,
}: AssistantMessageProps) {
const trackFeedback = (feedback: "like" | "dislike") => {
trackButton({
action: feedback,
elementId: "message-feedback",
namespace: "chat",
CTA: feedback === "like" ? "Like Message" : "Dislike Message",
timestamp: timestamp?.getTime(),
});
};

return (
<motion.div
initial={animate ? { opacity: 0, y: -20 } : { opacity: 1, y: 0 }}
Expand Down Expand Up @@ -151,6 +167,9 @@ export function AssistantMessage({
}
/>
{usage && !isStreaming && <TokenUsage usage={usage} />}
{!isInitialGreeting && showFeedback && (
<MessageActions trackFeedback={trackFeedback} />
)}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
</motion.div>
</div>
</Message>
Expand Down
54 changes: 54 additions & 0 deletions frontend/app/chat/_components/message-actions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ThumbsDown, ThumbsUp } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";

interface MessageActionsProps {
trackFeedback: (feedback: "like" | "dislike") => void;
}

const MessageActions = ({ trackFeedback }: MessageActionsProps) => {
const [feedbackSelected, setFeedbackSelected] = useState<
"like" | "dislike" | null
>(null);

const handleFeedback = (feedback: "like" | "dislike") => {
if (feedbackSelected === feedback) return; // Prevent multiple tracking events for the same feedback
trackFeedback(feedback);
setFeedbackSelected(feedback);
};

return (
<div className="flex space-x-2 mt-2">
<Button
variant="ghost"
size="icon"
className={
feedbackSelected !== "like"
? "text-muted-foreground hover:text-foreground"
: ""
}
onClick={() => handleFeedback("like")}
>
<ThumbsUp
className={`h-4 w-4 ${feedbackSelected === "like" ? "fill-current" : ""}`}
/>
</Button>
<Button
variant="ghost"
size="icon"
className={
feedbackSelected !== "dislike"
? "text-muted-foreground hover:text-foreground"
: ""
}
onClick={() => handleFeedback("dislike")}
>
<ThumbsDown
className={`h-4 w-4 ${feedbackSelected === "dislike" ? "fill-current" : ""}`}
/>
</Button>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</div>
);
};

export default MessageActions;
6 changes: 6 additions & 0 deletions frontend/app/chat/_types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export interface Message {
usage?: TokenUsage;
}

export const INITIAL_ASSISTANT_MESSAGE: Message = {
role: "assistant",
content: "How can I assist?",
timestamp: new Date(),
};

export interface FunctionCall {
name: string;
arguments?: Record<string, unknown>;
Expand Down
26 changes: 6 additions & 20 deletions frontend/app/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type {
RequestBody,
ToolCallResult,
} from "./_types/types";
import { INITIAL_ASSISTANT_MESSAGE } from "./_types/types";

function ChatPage() {
const isDebugMode = process.env.NEXT_PUBLIC_OPENRAG_DEBUG === "true";
Expand All @@ -52,11 +53,7 @@ function ChatPage() {
setConversationFilter,
} = useChat();
const [messages, setMessages] = useState<Message[]>([
{
role: "assistant",
content: "How can I assist?",
timestamp: new Date(),
},
INITIAL_ASSISTANT_MESSAGE,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the INITIAL_ASSISTANT_MESSAGE definition to see if timestamp is static or dynamic
rg -A 5 -B 2 'INITIAL_ASSISTANT_MESSAGE\s*=' frontend/app/chat/_types/types.ts

Repository: langflow-ai/openrag

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Search for INITIAL_ASSISTANT_MESSAGE definition across the frontend
rg 'INITIAL_ASSISTANT_MESSAGE\s*=' frontend/ --type ts --type tsx -A 8

Repository: langflow-ai/openrag

Length of output: 91


🏁 Script executed:

#!/bin/bash
# Also search for where it's imported from in page.tsx
rg 'import.*INITIAL_ASSISTANT_MESSAGE' frontend/app/chat/page.tsx -B 2 -A 2

Repository: langflow-ai/openrag

Length of output: 189


🏁 Script executed:

#!/bin/bash
# Check the structure of the page.tsx file at the mentioned lines
sed -n '50,70p' frontend/app/chat/page.tsx
sed -n '320,335p' frontend/app/chat/page.tsx
sed -n '560,575p' frontend/app/chat/page.tsx

Repository: langflow-ai/openrag

Length of output: 2087


🏁 Script executed:

#!/bin/bash
# Read the types.ts file to find INITIAL_ASSISTANT_MESSAGE definition
cat frontend/app/chat/_types/types.ts

Repository: langflow-ai/openrag

Length of output: 1728


🏁 Script executed:

#!/bin/bash
# Also check the chat-context.tsx implementation mentioned in the review
rg -B 5 -A 5 'new Date().toISOString()' frontend/app/chat/

Repository: langflow-ai/openrag

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Find chat-context.tsx
fd 'chat-context' frontend/ --type f

Repository: langflow-ai/openrag

Length of output: 98


🏁 Script executed:

#!/bin/bash
# Check line 347 area and message initialization in chat-context
rg 'const createMessage|content.*timestamp|new Date' frontend/app/chat/chat-context.tsx -B 3 -A 3

Repository: langflow-ai/openrag

Length of output: 138


🏁 Script executed:

#!/bin/bash
# Check the correct chat-context.tsx location
rg 'INITIAL_ASSISTANT_MESSAGE|new Date' frontend/contexts/chat-context.tsx -B 3 -A 3

Repository: langflow-ai/openrag

Length of output: 809


🏁 Script executed:

#!/bin/bash
# Also search for any message creation patterns around line 347 or nearby
sed -n '340,360p' frontend/contexts/chat-context.tsx

Repository: langflow-ai/openrag

Length of output: 719


Create fresh timestamps when resetting to INITIAL_ASSISTANT_MESSAGE instead of reusing the stale module-level timestamp.

The INITIAL_ASSISTANT_MESSAGE constant is defined with timestamp: new Date() at module load time, meaning all three reset locations (initial state at line 56, handleNewConversation effect at line 328, and placeholderConversation effect at line 566) share the same static timestamp rather than reflecting the actual start time of each conversation.

The pattern in frontend/contexts/chat-context.tsx demonstrates the correct approach: extract only the content from INITIAL_ASSISTANT_MESSAGE and create a fresh timestamp with new Date().toISOString(). Apply the same pattern here:

Proposed fix
-const [messages, setMessages] = useState<Message[]>([
-  INITIAL_ASSISTANT_MESSAGE,
-]);
+const [messages, setMessages] = useState<Message[]>([
+  { ...INITIAL_ASSISTANT_MESSAGE, timestamp: new Date() },
+]);

And similarly for lines 328 and 566:

-setMessages([INITIAL_ASSISTANT_MESSAGE]);
+setMessages([{ ...INITIAL_ASSISTANT_MESSAGE, timestamp: new Date() }]);

Also applies to: 328-328, 566-566

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/app/chat/page.tsx` at line 56, INITIAL_ASSISTANT_MESSAGE is created
at module load and reusing it causes stale timestamps; when resetting the
conversation in the page component (initial state where
INITIAL_ASSISTANT_MESSAGE is used, inside the handleNewConversation effect, and
inside the placeholderConversation effect), unpack only the message content from
INITIAL_ASSISTANT_MESSAGE and build a new message object with the same content
but a fresh timestamp using new Date().toISOString(); update the places that
reference INITIAL_ASSISTANT_MESSAGE to create a new object (e.g., {
...INITIAL_ASSISTANT_MESSAGE, timestamp: new Date().toISOString() } or extract
content and set timestamp) so each reset gets a current timestamp.

]);
const [input, setInput] = useState("");
const { loading, setLoading } = useLoadingStore();
Expand Down Expand Up @@ -328,13 +325,7 @@ function ChatPage() {
// Abort any in-flight streaming so it doesn't bleed into new chat
abortStream();
// Reset chat UI even if context state was already 'new'
setMessages([
{
role: "assistant",
content: "How can I assist?",
timestamp: new Date(),
},
]);
setMessages([INITIAL_ASSISTANT_MESSAGE]);
setInput("");
setExpandedFunctionCalls(new Set());
setIsFilterHighlighted(false);
Expand Down Expand Up @@ -572,13 +563,7 @@ function ChatPage() {
useEffect(() => {
if (placeholderConversation && currentConversationId === null) {
console.log("Starting new conversation");
setMessages([
{
role: "assistant",
content: "How can I assist?",
timestamp: new Date(),
},
]);
setMessages([INITIAL_ASSISTANT_MESSAGE]);
lastLoadedConversationRef.current = null;

// Focus input when starting a new conversation
Expand Down Expand Up @@ -1142,9 +1127,10 @@ function ChatPage() {
isInitialGreeting={
index === 0 &&
messages.length === 1 &&
message.content === "How can I assist?"
message === INITIAL_ASSISTANT_MESSAGE
}
usage={message.usage}
timestamp={message.timestamp}
/>
)}
</div>
Expand Down
1 change: 1 addition & 0 deletions frontend/app/onboarding/_components/onboarding-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ export function OnboardingContent({
onToggle={() => {}}
isStreaming={!!streamingMessage}
isCompleted={currentStep > 3}
showFeedback={false}
/>
)}

Expand Down
11 changes: 3 additions & 8 deletions frontend/contexts/chat-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
useState,
} from "react";
import { useGetSettingsQuery } from "@/app/api/queries/useGetSettingsQuery";
import { INITIAL_ASSISTANT_MESSAGE } from "@/app/chat/_types/types";

export type EndpointType = "chat" | "langflow";

Expand All @@ -22,7 +23,7 @@ interface ConversationDocument {
interface ConversationMessage {
role: string;
content: string;
timestamp?: string;
timestamp?: Date;
response_id?: string;
}

Expand Down Expand Up @@ -340,13 +341,7 @@ export function ChatProvider({ children }: ChatProviderProps) {
response_id: "new-conversation-" + Date.now(),
title: "New conversation",
endpoint: endpoint,
messages: [
{
role: "assistant",
content: "How can I assist?",
timestamp: new Date().toISOString(),
},
],
messages: [INITIAL_ASSISTANT_MESSAGE],
created_at: new Date().toISOString(),
last_activity: new Date().toISOString(),
};
Expand Down
2 changes: 1 addition & 1 deletion frontend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"jsx": "preserve",
"incremental": true,
"plugins": [
{
Expand Down
Loading