From 803fd5cc17a4244d077d52e6c094b07bf807a463 Mon Sep 17 00:00:00 2001 From: Willie Zutz Date: Sun, 10 Aug 2025 17:36:15 -0600 Subject: [PATCH] feat(Focus): Enhance hover effects and update icon colors for better visibility feat(Optimization): Update icon colors for consistency and improve hover styles feat(SimplifiedAgent): Add messagesCount parameter to initializeAgent for adaptive prompts --- docs/installation/TRACING.md | 23 +++++++------- src/components/MessageInputActions/Focus.tsx | 18 +++++------ .../MessageInputActions/Optimization.tsx | 12 +++---- src/lib/search/simplifiedAgent.ts | 31 ++++++++++++++++--- src/lib/search/speedSearch.ts | 10 +++--- src/lib/utils/analyzePreviewContent.ts | 4 +-- 6 files changed, 61 insertions(+), 37 deletions(-) diff --git a/docs/installation/TRACING.md b/docs/installation/TRACING.md index 21a9271..ced0aaa 100644 --- a/docs/installation/TRACING.md +++ b/docs/installation/TRACING.md @@ -1,4 +1,3 @@ - # Tracing LLM Calls in Perplexica Perplexica supports tracing all LangChain and LangGraph LLM calls for debugging, analytics, and prompt transparency. You can use either Langfuse (self-hosted, private, or cloud) or LangSmith (cloud, by LangChain) for tracing. @@ -10,21 +9,22 @@ Langfuse is an open-source, self-hostable observability platform for LLM applica ### Setup 1. **Deploy Langfuse** - - See: [Langfuse Self-Hosting Guide](https://langfuse.com/docs/self-hosting) - - You can also use the Langfuse Cloud if you prefer. + - See: [Langfuse Self-Hosting Guide](https://langfuse.com/docs/self-hosting) + - You can also use the Langfuse Cloud if you prefer. 2. **Configure Environment Variables** - - Add the following to your environment variables in docker-compose or your deployment environment: + - Add the following to your environment variables in docker-compose or your deployment environment: - ```env - LANGFUSE_PUBLIC_KEY=your-public-key - LANGFUSE_SECRET_KEY=your-secret-key - LANGFUSE_BASE_URL=https://your-langfuse-instance.com - ``` - - These are required for the tracing integration to work. If not set, tracing is disabled gracefully. + ```env + LANGFUSE_PUBLIC_KEY=your-public-key + LANGFUSE_SECRET_KEY=your-secret-key + LANGFUSE_BASE_URL=https://your-langfuse-instance.com + ``` + + - These are required for the tracing integration to work. If not set, tracing is disabled gracefully. 3. **Run Perplexica** - - All LLM and agent calls will be traced automatically. You can view traces in your Langfuse dashboard. + - All LLM and agent calls will be traced automatically. You can view traces in your Langfuse dashboard. ## LangSmith Tracing (Cloud by LangChain) @@ -38,5 +38,6 @@ Perplexica also supports tracing via [LangSmith](https://smith.langchain.com/), --- For more details on tracing, see the respective documentation: + - [Langfuse Documentation](https://langfuse.com/docs) - [LangSmith Observability](https://docs.smith.langchain.com/observability) diff --git a/src/components/MessageInputActions/Focus.tsx b/src/components/MessageInputActions/Focus.tsx index e8f4472..57e837e 100644 --- a/src/components/MessageInputActions/Focus.tsx +++ b/src/components/MessageInputActions/Focus.tsx @@ -42,7 +42,7 @@ const Focus = ({ ); return ( -
+
@@ -52,7 +52,7 @@ const Focus = ({ 'p-2 transition-all duration-200', focusMode === 'webSearch' ? 'text-accent scale-105' - : 'text-fg/70', + : 'text-fg/70 hover:bg-surface-2', )} onMouseEnter={() => setShowWebSearchTooltip(true)} onMouseLeave={() => setShowWebSearchTooltip(false)} @@ -72,8 +72,8 @@ const Focus = ({ className={cn( 'p-2 transition-all duration-200', focusMode === 'chat' - ? 'text-[#10B981] scale-105' - : 'text-fg/70', + ? 'text-accent scale-105' + : 'text-fg/70 hover:bg-surface-2', )} onMouseEnter={() => setShowChatTooltip(true)} onMouseLeave={() => setShowChatTooltip(false)} @@ -93,8 +93,8 @@ const Focus = ({ className={cn( 'p-2 transition-all duration-200', focusMode === 'localResearch' - ? 'text-[#8B5CF6] scale-105' - : 'text-fg/70', + ? 'text-accent scale-105' + : 'text-fg/70 hover:bg-surface-2', )} onMouseEnter={() => setShowLocalResearchTooltip(true)} onMouseLeave={() => setShowLocalResearchTooltip(false)} @@ -129,7 +129,7 @@ const Focus = ({
- +

{chatMode?.title}

@@ -146,8 +146,8 @@ const Focus = ({
- -

+ +

{localResearchMode?.title}

diff --git a/src/components/MessageInputActions/Optimization.tsx b/src/components/MessageInputActions/Optimization.tsx index dad3918..a5b02cc 100644 --- a/src/components/MessageInputActions/Optimization.tsx +++ b/src/components/MessageInputActions/Optimization.tsx @@ -8,14 +8,14 @@ const OptimizationModes = [ title: 'Speed', description: 'Prioritize speed and get the quickest possible answer. Uses only web search results - attached files will not be processed.', - icon: , + icon: , }, { key: 'agent', title: 'Agent (Experimental)', description: 'Use an agentic workflow to answer complex multi-part questions. This mode may take longer and is experimental. It uses large prompts and may not work with all models. Best with at least a 8b model that supports 32k context or more.', - icon: , + icon: , }, ]; @@ -57,7 +57,7 @@ const Optimization = ({ className={cn( 'p-2 transition-all duration-200', !isAgentMode - ? 'bg-[#FF9800]/20 text-[#FF9800] scale-105' + ? 'bg-surface-2 text-accent scale-105' : 'text-fg/30 hover:text-fg/50 hover:bg-surface-2/50', )} onMouseEnter={() => setShowSpeedTooltip(true)} @@ -74,7 +74,7 @@ const Optimization = ({ className={cn( 'p-2 transition-all duration-200', isAgentMode - ? 'bg-[#9C27B0]/20 text-[#9C27B0] scale-105' + ? 'bg-surface-2 text-accent scale-105' : 'text-fg/30 hover:text-fg/50 hover:bg-surface-2/50', )} onMouseEnter={() => setShowAgentTooltip(true)} @@ -89,7 +89,7 @@ const Optimization = ({
- +

{speedMode?.title}

@@ -106,7 +106,7 @@ const Optimization = ({
- +

{agentMode?.title}

diff --git a/src/lib/search/simplifiedAgent.ts b/src/lib/search/simplifiedAgent.ts index 9c90d8b..7ddbe55 100644 --- a/src/lib/search/simplifiedAgent.ts +++ b/src/lib/search/simplifiedAgent.ts @@ -89,13 +89,18 @@ export class SimplifiedAgent { /** * Initialize the createReactAgent with tools and configuration */ - private initializeAgent(focusMode: string, fileIds: string[] = []) { + private initializeAgent( + focusMode: string, + fileIds: string[] = [], + messagesCount?: number, + ) { // Select appropriate tools based on focus mode and available files const tools = this.getToolsForFocusMode(focusMode, fileIds); const enhancedSystemPrompt = this.createEnhancedSystemPrompt( focusMode, fileIds, + messagesCount, ); try { @@ -159,6 +164,7 @@ export class SimplifiedAgent { private createEnhancedSystemPrompt( focusMode: string, fileIds: string[] = [], + messagesCount?: number, ): string { const baseInstructions = this.systemInstructions || ''; const personaInstructions = this.personaInstructions || ''; @@ -172,6 +178,7 @@ export class SimplifiedAgent { baseInstructions, personaInstructions, fileIds, + messagesCount, ); case 'localResearch': return this.createLocalResearchModePrompt( @@ -186,6 +193,7 @@ export class SimplifiedAgent { baseInstructions, personaInstructions, fileIds, + messagesCount, ); } } @@ -252,7 +260,13 @@ Focus on providing engaging, helpful conversation while using task management to baseInstructions: string, personaInstructions: string, fileIds: string[] = [], + messagesCount: number = 0, ): string { + // If the number of messages passed to the LLM is < 2 (i.e., first turn), enforce ALWAYS web search. + const alwaysSearchInstruction = + messagesCount < 2 + ? '\n - **You must ALWAYS perform at least one web search on the first turn, regardless of prior knowledge or assumptions. Do not skip this.**' + : ''; return `${baseInstructions} # Comprehensive Research Assistant @@ -323,7 +337,7 @@ Your task is to provide answers that are: - Give the web search tool a specific question you want answered that will help you gather relevant information - This query will be passed directly to the search engine - You will receive a list of relevant documents containing snippets of the web page, a URL, and the title of the web page - - **Always perform at least one web search** unless the question can be definitively answered with previous conversation history or local file content. If you don't have conversation history or local files, **you must perform a web search** + ${alwaysSearchInstruction} ${ fileIds.length > 0 ? ` @@ -368,7 +382,14 @@ ${ ${personaInstructions ? `\n## User Formatting and Persona Instructions\n- Give these instructions more weight than the system formatting instructions\n${personaInstructions}` : ''} -Use all available tools strategically to provide comprehensive, well-researched, formatted responses with proper citations`; +Use all available tools strategically to provide comprehensive, well-researched, formatted responses with proper citations. +${ + messagesCount < 2 + ? ` +**DO NOT SKIP WEB SEARCH** +` + : '' +}`; } /** @@ -487,7 +508,9 @@ Use all available tools strategically to provide comprehensive, well-researched, console.log(`SimplifiedAgent: File IDs: ${fileIds.join(', ')}`); // Initialize agent with the provided focus mode and file context - const agent = this.initializeAgent(focusMode, fileIds); + // Pass the number of messages that will be sent to the LLM so prompts can adapt. + const llmMessagesCount = [...history, new HumanMessage(query)].length; + const agent = this.initializeAgent(focusMode, fileIds, llmMessagesCount); // Prepare initial state const initialState = { diff --git a/src/lib/search/speedSearch.ts b/src/lib/search/speedSearch.ts index 68fe6ce..139a861 100644 --- a/src/lib/search/speedSearch.ts +++ b/src/lib/search/speedSearch.ts @@ -104,7 +104,7 @@ class SpeedSearchAgent implements SpeedSearchAgentType { this.emitProgress(emitter, 10, `Building search query`); - return RunnableSequence.from([ + return RunnableSequence.from([ PromptTemplate.fromTemplate(this.config.queryGeneratorPrompt), llm, this.strParser, @@ -237,7 +237,7 @@ class SpeedSearchAgent implements SpeedSearchAgentType { Make sure to answer the query in the summary. `, - { signal, ...getLangfuseCallbacks() }, + { signal, ...getLangfuseCallbacks() }, ); const document = new Document({ @@ -542,7 +542,7 @@ ${docs[index].metadata?.url.toLowerCase().includes('file') ? '' : '\n' + do personaInstructions, ); - const stream = answeringChain.streamEvents( + const stream = answeringChain.streamEvents( { chat_history: history, query: message, @@ -550,8 +550,8 @@ ${docs[index].metadata?.url.toLowerCase().includes('file') ? '' : '\n' + do { version: 'v1', // Pass the abort signal to the LLM streaming chain - signal, - ...getLangfuseCallbacks(), + signal, + ...getLangfuseCallbacks(), }, ); diff --git a/src/lib/utils/analyzePreviewContent.ts b/src/lib/utils/analyzePreviewContent.ts index 967373d..e815b06 100644 --- a/src/lib/utils/analyzePreviewContent.ts +++ b/src/lib/utils/analyzePreviewContent.ts @@ -82,7 +82,7 @@ Snippet: ${content.snippet} name: 'analyze_preview_content', }); - const analysisResult = await structuredLLM.invoke( + const analysisResult = await structuredLLM.invoke( `You are a preview content analyzer, tasked with determining if search result snippets contain sufficient information to answer the Task Query. # Instructions @@ -119,7 +119,7 @@ ${taskQuery} # Search Result Previews to Analyze: ${formattedPreviewContent} `, - { signal, ...getLangfuseCallbacks() }, + { signal, ...getLangfuseCallbacks() }, ); if (!analysisResult) {