Skip to content

Add collapsible user input display for long messages #471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 1, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions .github/actions/poetry_setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ runs:
with:
python-version: ${{ inputs.python-version }}

- uses: actions/cache@v3
- uses: actions/cache@v4
id: cache-bin-poetry
name: Cache Poetry binary - Python ${{ inputs.python-version }}
env:
Expand Down Expand Up @@ -75,7 +75,7 @@ runs:
run: pipx install "poetry==$POETRY_VERSION" --python '${{ steps.setup-python.outputs.python-path }}' --verbose

- name: Restore pip and poetry cached dependencies
uses: actions/cache@v3
uses: actions/cache@v4
env:
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "4"
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/eval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
environment: Evaluation
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Set up Python + Poetry
uses: "./.github/actions/poetry_setup"
Expand Down
1 change: 1 addition & 0 deletions _scripts/clear_index.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Clear Weaviate index."""

import logging
import os

Expand Down
3 changes: 2 additions & 1 deletion _scripts/evaluate_chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@

import weaviate
from langchain import load as langchain_load
from langchain.chat_models import ChatAnthropic, ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder, PromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.retriever import BaseRetriever
from langchain.schema.runnable import Runnable, RunnableMap
from langchain.smith import RunEvalConfig
from langchain.vectorstores import Weaviate
from langchain_anthropic import ChatAnthropic
from langchain_openai import ChatOpenAI
from langsmith import Client, RunEvaluator
from langsmith.evaluation.evaluator import EvaluationResult
from langsmith.schemas import Example, Run
Expand Down
2 changes: 1 addition & 1 deletion _scripts/evaluate_chains_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
AgentTokenBufferMemory,
)
from langchain.agents.openai_functions_agent.base import OpenAIFunctionsAgent
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import MessagesPlaceholder
from langchain.schema.messages import SystemMessage
from langchain.smith import RunEvalConfig, run_on_dataset
from langchain.vectorstores import Weaviate
from langchain_openai import ChatOpenAI
from langsmith import Client, RunEvaluator
from langsmith.evaluation.evaluator import EvaluationResult
from langsmith.schemas import Example, Run
Expand Down
3 changes: 2 additions & 1 deletion _scripts/evaluate_chains_improved_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import weaviate
from langchain import load as langchain_load
from langchain.chat_models import ChatAnthropic, ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder, PromptTemplate
Expand All @@ -16,6 +15,8 @@
from langchain.schema.runnable import Runnable, RunnableMap
from langchain.smith import RunEvalConfig
from langchain.vectorstores import Weaviate
from langchain_anthropic import ChatAnthropic
from langchain_openai import ChatOpenAI
from langsmith import Client, RunEvaluator
from langsmith.evaluation.evaluator import EvaluationResult
from langsmith.schemas import Example, Run
Expand Down
3 changes: 2 additions & 1 deletion _scripts/evaluate_chat_langchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
# This is ugly
import argparse

from langchain.chat_models import ChatAnthropic, ChatOpenAI
from langchain.smith import RunEvalConfig
from langchain_anthropic import ChatAnthropic
from langchain_openai import ChatOpenAI
from langsmith import Client

# Ugly. Requires PYTHONATH=$(PWD) to run
Expand Down
1 change: 1 addition & 0 deletions backend/ingest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Load html from files, clean up, split, ingest into Weaviate."""

import logging
import os
import re
Expand Down
87 changes: 84 additions & 3 deletions frontend/app/components/chat-interface/messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,100 @@ import {
useThreadRuntime,
} from "@assistant-ui/react";
import { useState, type FC } from "react";
import { ChevronDownIcon, ChevronRightIcon } from "lucide-react";

import { MarkdownText } from "../ui/assistant-ui/markdown-text";
import { useGraphContext } from "@/app/contexts/GraphContext";
import { useRuns } from "@/app/hooks/useRuns";
import { TooltipIconButton } from "../ui/assistant-ui/tooltip-icon-button";
import { ThumbsDownIcon, ThumbsUpIcon } from "lucide-react";
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
} from "../ui/collapsible";

// Helper function to generate a brief headline from long text
function generateHeadline(text: string, maxLength: number = 60): string {
if (text.length <= maxLength) return text;

// Try to find the first sentence or logical break
const firstSentence = text.match(/^[^.!?]*[.!?]/);
if (firstSentence && firstSentence[0].length <= maxLength) {
return firstSentence[0].trim();
}

// Try to find subject line if it looks like an email
const subjectMatch = text.match(/^Subject:\s*([^\n\r]+)/i);
if (subjectMatch && subjectMatch[1].length <= maxLength) {
return subjectMatch[1].trim();
}

// Fallback to truncated text at word boundary
const truncated = text.substring(0, maxLength);
const lastSpace = truncated.lastIndexOf(" ");
return lastSpace > maxLength * 0.7
? truncated.substring(0, lastSpace) + "..."
: truncated + "...";
}

export const UserMessage: FC = () => {
const message = useMessage();
const [isExpanded, setIsExpanded] = useState(false);

// Get the text content from the message
const textContent =
message.content?.[0]?.type === "text" ? message.content[0].text : "";
const isLongText = textContent.length > 150; // Threshold for collapsible behavior

if (!isLongText) {
// For short text, use the original styling
return (
<MessagePrimitive.Root className="pt-2 sm:pt-4 flex w-full md:max-w-4xl md:mx-0 mx-auto max-w-[95%] md:py-4 py-2">
<div className="bg-inherit text-white break-words rounded-2xl sm:rounded-3xl pt-2 md:pt-2.5 mb-[-15px] sm:mb-[-25px] text-2xl sm:text-4xl font-light">
<MessagePrimitive.Content />
</div>
</MessagePrimitive.Root>
);
}

const headline = generateHeadline(textContent);

return (
<MessagePrimitive.Root className="pt-2 sm:pt-4 flex w-full md:max-w-4xl md:mx-0 mx-auto max-w-[95%] md:py-4 py-2">
<div className="bg-inherit text-white break-words rounded-2xl sm:rounded-3xl pt-2 md:pt-2.5 mb-[-15px] sm:mb-[-25px] text-2xl sm:text-4xl font-light">
<MessagePrimitive.Content />
</div>
<Collapsible
open={isExpanded}
onOpenChange={setIsExpanded}
className="w-full"
>
<CollapsibleTrigger className="w-full text-left group hover:opacity-80 transition-opacity">
<div className="bg-inherit text-white break-words rounded-2xl sm:rounded-3xl pt-2 md:pt-2.5 mb-[-15px] sm:mb-[-25px] flex items-start gap-2">
<div className="text-2xl sm:text-4xl font-light flex-1">
{headline}
</div>
<div className="flex items-center mt-1 text-gray-400 group-hover:text-white transition-colors">
{isExpanded ? (
<ChevronDownIcon className="w-5 h-5 sm:w-6 sm:h-6" />
) : (
<ChevronRightIcon className="w-5 h-5 sm:w-6 sm:h-6" />
)}
</div>
</div>
</CollapsibleTrigger>

<CollapsibleContent className="overflow-hidden">
<div className="pt-4 pb-2">
<div className="bg-gray-800/50 text-gray-200 text-sm sm:text-base rounded-lg p-3 sm:p-4 border border-gray-700/50">
<div className="font-medium text-gray-300 mb-2 text-xs sm:text-sm uppercase tracking-wide">
Full Message
</div>
<div className="whitespace-pre-wrap break-words leading-relaxed">
{textContent}
</div>
</div>
</div>
</CollapsibleContent>
</Collapsible>
</MessagePrimitive.Root>
);
};
Expand Down
Loading