Skip to content

Commit

Permalink
Merge pull request #462 from reorproject/chat-low-hanging-fruit
Browse files Browse the repository at this point in the history
update prompt and bring back loader
  • Loading branch information
samlhuillier authored Oct 22, 2024
2 parents cc5b0ba + 4b41112 commit da9b442
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 36 deletions.
12 changes: 7 additions & 5 deletions src/components/Chat/ChatConfigComponents/exampleAgents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { allAvailableToolDefinitions } from '../../../lib/llm/tools/tool-definit
const defaultAgentPromptTemplate: PromptTemplate = [
{
role: 'system',
content: `You are a helpful assistant helping a user organize and manage their personal knowledge and notes. Here are some guidelines:
- You will answer the user's question and help them with their request.
- You can search the knowledge base by using the search tool and create new notes by using the create note tool.
- Make sure you respond in the same language as the user's query and context.
- An initial query has been made and the context is already provided for you (so please do not call the search tool initially).
content: `You are a helpful assistant responding to the user's query. You are operating within the context of the user's personal knowledge base.
Here are some guidelines you must follow:
- Always respond in the same language as the user's query and context.
- You may be given context from the user's knowledge base that is relevant to the user's query. If so, please use it.
- You may be given a list of tools that you can use to help you search the user's knowledge base or perform actions on the user's knowledge base.
- If provided to you, the search tool is particularly useful, although you should *not* use it initially if context has already been provided.
- The date and time of the query is {TODAY}.`,
},
{
Expand Down
71 changes: 54 additions & 17 deletions src/components/Chat/ChatMessages.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useState, useRef, useEffect, useCallback } from 'react'
import '../../styles/chat.css'
import { Chat, AgentConfig, LoadingState, ReorChatMessage } from '../../lib/llm/types'
import ChatInput from './ChatInput'
Expand Down Expand Up @@ -51,27 +51,69 @@ const ChatMessages: React.FC<ChatMessagesProps> = ({
loadingState,
}) => {
const [userTextFieldInput, setUserTextFieldInput] = useState<string | undefined>()
const [shouldAutoScroll, setShouldAutoScroll] = useState(true)
const chatContainerRef = useRef<HTMLDivElement>(null)
const lastMessageRef = useRef<HTMLDivElement>(null)

const scrollToBottom = useCallback(() => {
if (chatContainerRef.current) {
const { scrollHeight, clientHeight } = chatContainerRef.current
chatContainerRef.current.scrollTop = scrollHeight - clientHeight
}
}, [])

useEffect(() => {
if (shouldAutoScroll) {
scrollToBottom()
}
}, [currentChat?.messages, loadingState, shouldAutoScroll, scrollToBottom])

const handleScroll = () => {
if (chatContainerRef.current) {
const { scrollTop, scrollHeight, clientHeight } = chatContainerRef.current
const isScrolledToBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 1
setShouldAutoScroll(isScrolledToBottom)
}
}

const handleSubmitNewMessage = () => {
if (userTextFieldInput) {
handleNewChatMessage(userTextFieldInput)
setUserTextFieldInput('')
setShouldAutoScroll(true)
}
}

useEffect(() => {
const observer = new MutationObserver(() => {
if (shouldAutoScroll) {
scrollToBottom()
}
})

if (lastMessageRef.current) {
observer.observe(lastMessageRef.current, { childList: true, subtree: true, characterData: true })
}

return () => observer.disconnect()
}, [shouldAutoScroll, scrollToBottom])

return (
<div className="flex h-full flex-col">
<div className="grow overflow-auto">
<div className="grow overflow-auto" ref={chatContainerRef} onScroll={handleScroll}>
<div className="flex flex-col items-center gap-3 p-4">
<div className="w-full max-w-3xl">
{currentChat?.messages?.length > 0 &&
currentChat.messages.map((message, index) => (
<Message
// eslint-disable-next-line react/no-array-index-key
key={index}
message={message}
index={index}
currentChat={currentChat}
setCurrentChat={setCurrentChat}
/>
// eslint-disable-next-line react/no-array-index-key
<div key={index} ref={index === currentChat.messages.length - 1 ? lastMessageRef : null}>
<Message message={message} index={index} currentChat={currentChat} setCurrentChat={setCurrentChat} />
</div>
))}
</div>

{loadingState === 'waiting-for-first-token' && (
<div className="mt-4 flex w-full max-w-3xl items-start gap-6">
<div className="mt-4 flex w-full max-w-3xl items-start gap-6 p-2">
<LoadingDots />
</div>
)}
Expand All @@ -83,12 +125,7 @@ const ChatMessages: React.FC<ChatMessagesProps> = ({
<ChatInput
userTextFieldInput={userTextFieldInput ?? ''}
setUserTextFieldInput={setUserTextFieldInput}
handleSubmitNewMessage={() => {
if (userTextFieldInput) {
handleNewChatMessage(userTextFieldInput)
setUserTextFieldInput('')
}
}}
handleSubmitNewMessage={handleSubmitNewMessage}
loadingState={loadingState}
/>
</div>
Expand Down
20 changes: 14 additions & 6 deletions src/components/Chat/MessageComponents/ChatSources.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import { FileInfoWithContent } from 'electron/main/filesystem/types'
import { DBEntry } from 'electron/main/vector-database/schema'
import posthog from 'posthog-js'
import { Card, CardDescription } from '@/components/ui/card'
import { HoverCard, HoverCardTrigger, HoverCardContent } from '@/components/ui/hover-card'
import { useContentContext } from '@/contexts/ContentContext'
Expand Down Expand Up @@ -37,6 +38,11 @@ const ChatSources: React.FC<ChatSourcesProps> = ({ contextItems }) => {
return item.content
}

const handleOpenContent = (path: string) => {
openContent(path)
posthog.capture('open_content_from_chat_sources')
}

if (contextItems.length === 0) {
return null
}
Expand All @@ -45,21 +51,23 @@ const ChatSources: React.FC<ChatSourcesProps> = ({ contextItems }) => {
<div>
<div className="mb-1 text-sm text-muted-foreground">Sources:</div>

<div className="flex space-x-2 overflow-x-auto p-0">
<div className="scrollbar-thumb-rounded-full flex space-x-2 overflow-x-auto p-0 pb-1 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-gray-800">

Check warning on line 54 in src/components/Chat/MessageComponents/ChatSources.tsx

View workflow job for this annotation

GitHub Actions / build_and_package (macos-13)

Classname 'scrollbar-thumb-rounded-full' is not a Tailwind CSS class!

Check warning on line 54 in src/components/Chat/MessageComponents/ChatSources.tsx

View workflow job for this annotation

GitHub Actions / build_and_package (macos-latest)

Classname 'scrollbar-thumb-rounded-full' is not a Tailwind CSS class!

Check warning on line 54 in src/components/Chat/MessageComponents/ChatSources.tsx

View workflow job for this annotation

GitHub Actions / build_and_package (windows-latest)

Classname 'scrollbar-thumb-rounded-full' is not a Tailwind CSS class!

Check warning on line 54 in src/components/Chat/MessageComponents/ChatSources.tsx

View workflow job for this annotation

GitHub Actions / build_and_package (ubuntu-latest, x64)

Classname 'scrollbar-thumb-rounded-full' is not a Tailwind CSS class!
{contextItems.map((contextItem) => (
<HoverCard key={getItemPath(contextItem)}>
<HoverCard key={getItemPath(contextItem)} openDelay={100}>
<HoverCardTrigger>
<Card
className="flex h-10 w-28 shrink-0 cursor-pointer items-center justify-center bg-secondary"
onClick={() => openContent(getItemPath(contextItem))}
onClick={() => handleOpenContent(getItemPath(contextItem))}
>
<CardDescription className="px-1 text-center text-xs">
<CardDescription className="overflow-hidden break-all px-1 text-center text-xs">
{truncateName(getItemName(contextItem), 20)}
</CardDescription>
</Card>
</HoverCardTrigger>
<HoverCardContent>
<MarkdownRenderer content={getItemContent(contextItem)} />
<HoverCardContent className="max-h-[60vh] w-80 overflow-y-auto">
<div className="p-2">
<MarkdownRenderer content={getItemContent(contextItem)} />
</div>
</HoverCardContent>
</HoverCard>
))}
Expand Down
14 changes: 10 additions & 4 deletions src/components/Chat/MessageComponents/ToolCalls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ChatSources from './ChatSources'
import { findToolResultMatchingToolCall } from '../../../lib/llm/chat'
import { Button } from '@/components/ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
import MarkdownRenderer from '@/components/Common/MarkdownRenderer'

interface ToolCallComponentProps {
toolCallPart: ToolCallPart
Expand Down Expand Up @@ -61,6 +62,13 @@ const SearchToolRenderer: React.FC<ToolRendererProps> = ({ existingToolResult })
const DefaultToolRenderer: React.FC<ToolRendererProps> = ({ toolCallPart, existingToolResult, executeToolCall }) => {
const [isOpen, setIsOpen] = useState(true)

const renderValue = (value: unknown): string => {
if (typeof value === 'string') {
return value
}
return JSON.stringify(value, null, 2)
}

return (
<Collapsible open={isOpen} onOpenChange={setIsOpen} className="mt-2 rounded-md border border-border bg-secondary">
<div className="flex items-center justify-between px-3 py-2">
Expand All @@ -77,16 +85,14 @@ const DefaultToolRenderer: React.FC<ToolRendererProps> = ({ toolCallPart, existi
{Object.entries(toolCallPart.args as Record<string, unknown>).map(([key, value]) => (
<div key={key} className="text-xs">
<span className="font-medium text-secondary-foreground">{key}:</span>{' '}
<span className="text-muted-foreground">{JSON.stringify(value)}</span>
<MarkdownRenderer content={renderValue(value)} />
</div>
))}
</div>
{existingToolResult && (
<div className="border-t border-border px-3 py-2">
<h5 className="mb-1 text-xs font-medium text-muted-foreground">Result:</h5>
<div className="text-xs text-secondary-foreground">
{JSON.stringify(existingToolResult.content[0].result)}
</div>
<MarkdownRenderer content={renderValue(existingToolResult.content[0].result)} />
</div>
)}
{!existingToolResult && (
Expand Down
1 change: 1 addition & 0 deletions src/components/Chat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const ChatComponent: React.FC = () => {
const llmClient = await resolveLLMClient(defaultLLMName)
abortControllerRef.current = new AbortController()
const toolsZodSchema = Object.assign({}, ...outputChat.toolDefinitions.map(convertToolConfigToZodSchema))
setLoadingState('waiting-for-first-token')
const { textStream, toolCalls } = await streamText({
model: llmClient,
messages: removeUncalledToolsFromMessages(outputChat.messages),
Expand Down
2 changes: 1 addition & 1 deletion src/components/Common/MarkdownRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface MarkdownRendererProps {
const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ content }) => {
return (
<ReactMarkdown
className="overflow-hidden whitespace-normal break-words text-muted-foreground"
className="overflow-hidden whitespace-normal break-words leading-relaxed text-muted-foreground"
rehypePlugins={[rehypeRaw]}
>
{content}
Expand Down
5 changes: 2 additions & 3 deletions src/contexts/ContentContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ interface ContentProviderProps {
export const ContentProvider: React.FC<ContentProviderProps> = ({ children }) => {
const [currentOpenFileOrChatID, setCurrentOpenFileOrChatID] = useState<string | null>(null)

const { allChatsMetadata, setShowChatbot, setSidebarShowing, openNewChat } = useChatContext()
const { allChatsMetadata, setShowChatbot, openNewChat } = useChatContext()
const {
vaultFilesFlattened: flattenedFiles,
openOrCreateFile,
Expand All @@ -45,15 +45,14 @@ export const ContentProvider: React.FC<ContentProviderProps> = ({ children }) =>
openNewChat(pathOrChatID)
} else {
setShowChatbot(false)
setSidebarShowing('files')
openOrCreateFile(pathOrChatID, optionalContentToWriteOnCreate)
}
setCurrentOpenFileOrChatID(pathOrChatID)
if (!dontUpdateChatHistory) {
addToNavigationHistory(pathOrChatID)
}
},
[allChatsMetadata, setShowChatbot, openNewChat, setSidebarShowing, openOrCreateFile, addToNavigationHistory],
[allChatsMetadata, setShowChatbot, openNewChat, openOrCreateFile, addToNavigationHistory],
)

const createUntitledNote = useCallback(
Expand Down

0 comments on commit da9b442

Please sign in to comment.