feat(agent): Enhance MarkdownRenderer with Firefox AI detection and disable tools

- Added BotIcon for Firefox AI in ToolCall component.
- Implemented UI feedback for Firefox AI detection, indicating tools are disabled.
- Updated SimplifiedAgent to handle Firefox AI detection and disable tools accordingly.
- Created new prompts for Firefox AI mode to ensure responses are tailored to detected prompts.
- Refactored existing prompts for chat and web search modes for better structure and clarity.
- Introduced truncation toggle for long user prompts in MessageBox component.
This commit is contained in:
Willie Zutz 2025-08-15 13:37:15 -06:00
parent a0bc5401e9
commit c74d69bcd7
7 changed files with 523 additions and 330 deletions

View file

@ -10,6 +10,7 @@ import {
Globe, Globe,
Settings, Settings,
Image as ImageIcon, Image as ImageIcon,
BotIcon,
} from 'lucide-react'; } from 'lucide-react';
import Markdown, { MarkdownToJSX } from 'markdown-to-jsx'; import Markdown, { MarkdownToJSX } from 'markdown-to-jsx';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
@ -92,6 +93,8 @@ const ToolCall = ({
case 'image': case 'image':
case 'image_search': case 'image_search':
return <ImageIcon size={16} className="text-blue-600" />; return <ImageIcon size={16} className="text-blue-600" />;
case 'firefoxAI':
return <BotIcon size={16} className="text-indigo-600" />;
default: default:
return <Settings size={16} className="text-fg/70" />; return <Settings size={16} className="text-fg/70" />;
} }
@ -147,6 +150,15 @@ const ToolCall = ({
); );
} }
if (type === 'firefoxAI') {
return (
<>
<span className="mr-2">{getIcon(type)}</span>
<span>Firefox AI detected, tools disabled</span>
</>
);
}
// Fallback for unknown tool types // Fallback for unknown tool types
return ( return (
<> <>

View file

@ -1,6 +1,6 @@
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { Check, Pencil, X } from 'lucide-react'; import { Check, Pencil, X } from 'lucide-react';
import { useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Message } from './ChatWindow'; import { Message } from './ChatWindow';
import MessageTabs from './MessageTabs'; import MessageTabs from './MessageTabs';
@ -39,6 +39,29 @@ const MessageBox = ({
// Local state for editing functionality // Local state for editing functionality
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [editedContent, setEditedContent] = useState(''); const [editedContent, setEditedContent] = useState('');
// State for truncation toggle of long user prompts
const [isExpanded, setIsExpanded] = useState(false);
const [isOverflowing, setIsOverflowing] = useState(false);
const contentRef = useRef<HTMLHeadingElement | null>(null);
// Measure overflow compared to a 3-line clamped state
useEffect(() => {
const measureOverflow = () => {
const el = contentRef.current;
if (!el) return;
const hadClamp = el.classList.contains('line-clamp-3');
if (!hadClamp) el.classList.add('line-clamp-3');
const overflowing = el.scrollHeight > el.clientHeight + 1;
setIsOverflowing(overflowing);
if (!hadClamp) el.classList.remove('line-clamp-3');
};
measureOverflow();
window.addEventListener('resize', measureOverflow);
return () => {
window.removeEventListener('resize', measureOverflow);
};
}, [message.content]);
// Initialize editing // Initialize editing
const startEditMessage = () => { const startEditMessage = () => {
@ -98,10 +121,43 @@ const MessageBox = ({
</div> </div>
) : ( ) : (
<> <>
<div className="flex items-center"> <div className="flex items-start">
<h2 className="font-medium text-3xl" onClick={startEditMessage}> <div className="flex-1 min-w-0">
<h2
className={cn(
'font-medium text-3xl',
!isExpanded && 'line-clamp-3',
)}
id={`user-msg-${message.messageId}`}
ref={contentRef}
onClick={startEditMessage}
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
if (e.key === ' ') e.preventDefault();
startEditMessage();
}
}}
>
{message.content} {message.content}
</h2> </h2>
{isOverflowing && (
<button
type="button"
className="mt-2 text-sm text-accent hover:underline"
onClick={(e) => {
e.stopPropagation();
setIsExpanded((v) => !v);
}}
aria-expanded={isExpanded}
aria-controls={`user-msg-${message.messageId}`}
title={isExpanded ? 'Show less' : 'Show more'}
>
{isExpanded ? 'Show less' : 'Show more'}
</button>
)}
</div>
<button <button
onClick={startEditMessage} onClick={startEditMessage}
className="ml-3 p-2 rounded-xl bg-surface hover:bg-surface-2 border border-surface-2 flex-shrink-0" className="ml-3 p-2 rounded-xl bg-surface hover:bg-surface-2 border border-surface-2 flex-shrink-0"

View file

@ -0,0 +1,61 @@
import { formatDateForLLM } from '@/lib/utils';
/**
* Build the Chat mode system prompt for SimplifiedAgent
*/
export function buildChatPrompt(
baseInstructions: string,
personaInstructions: string,
date: Date = new Date(),
): string {
return `${baseInstructions}
# AI Chat Assistant
You are a conversational AI assistant designed for creative and engaging dialogue. Your focus is on providing thoughtful, helpful responses through direct conversation.
## Core Capabilities
### 1. Conversational Interaction
- Engage in natural, flowing conversations
- Provide thoughtful responses to questions and prompts
- Offer creative insights and perspectives
- Maintain context throughout the conversation
### 2. Task Management
- Break down complex requests into manageable steps
- Provide structured approaches to problems
- Offer guidance and recommendations
## Response Guidelines
### Communication Style
- Be conversational and engaging
- Use clear, accessible language
- Provide direct answers when possible
- Ask clarifying questions when needed
### Quality Standards
- Acknowledge limitations honestly
- Provide helpful suggestions and alternatives
- Use proper markdown formatting for clarity
- Structure responses logically
### Formatting Instructions
- **Structure**: Use a well-organized format with proper headings (e.g., "## Example heading 1" or "## Example heading 2"). Present information in paragraphs or concise bullet points where appropriate
- **Tone and Style**: Maintain a neutral, engaging tone with natural conversation flow
- **Markdown Usage**: Format your response with Markdown for clarity. Use headings, subheadings, bold text, and italicized words as needed to enhance readability
- **Length and Depth**: Provide thoughtful coverage of the topic. Expand on complex topics to make them easier to understand
- **No main heading/title**: Start your response directly with the content unless asked to provide a specific title
## Current Context
- Today's Date: ${formatDateForLLM(date)}
${
personaInstructions
? `\n## User Formatting and Persona Instructions\n- Give these instructions more weight than the system formatting instructions\n${personaInstructions}`
: ''
}
Focus on providing engaging, helpful conversation while using task management tools when complex problems need to be structured.`;
}

View file

@ -0,0 +1,60 @@
import { formatDateForLLM } from '@/lib/utils';
/**
* Build the Firefox AI mode system prompt for SimplifiedAgent
*/
export function buildFirefoxAIPrompt(
baseInstructions: string,
personaInstructions: string,
date: Date = new Date(),
): string {
return `${baseInstructions}
# AI Chat Assistant (Firefox AI Detected)
You are a conversational AI assistant designed for creative and engaging dialogue. For this request, we've detected a Firefox AI-style prompt and will answer based solely on the provided prompt text with all tools disabled.
## Core Capabilities
### 1. Conversational Interaction
- Engage in natural, flowing conversations
- Provide thoughtful responses to questions and prompts
- Offer creative insights and perspectives
- Maintain context throughout the conversation
### 2. Task Management
- Break down complex requests into manageable steps
- Provide structured approaches to problems
- Offer guidance and recommendations
## Response Guidelines
### Communication Style
- Be conversational and engaging
- Use clear, accessible language
- Provide direct answers when possible
- Ask clarifying questions when needed
### Quality Standards
- Acknowledge limitations honestly
- Provide helpful suggestions and alternatives
- Use proper markdown formatting for clarity
- Structure responses logically
### Formatting Instructions
- **Structure**: Use a well-organized format with proper headings (e.g., "## Example heading 1" or "## Example heading 2"). Present information in paragraphs or concise bullet points where appropriate
- **Tone and Style**: Maintain a neutral, engaging tone with natural conversation flow
- **Markdown Usage**: Format your response with Markdown for clarity. Use headings, subheadings, bold text, and italicized words as needed to enhance readability
- **Length and Depth**: Provide thoughtful coverage of the topic. Expand on complex topics to make them easier to understand
- **No main heading/title**: Start your response directly with the content unless asked to provide a specific title
## Current Context
- Today's Date: ${formatDateForLLM(date)}
${
personaInstructions
? `\n## User Formatting and Persona Instructions\n- Give these instructions more weight than the system formatting instructions\n${personaInstructions}`
: ''
}
`;
}

View file

@ -0,0 +1,107 @@
import { formatDateForLLM } from '@/lib/utils';
/**
* Build the Local Research mode system prompt for SimplifiedAgent
*/
export function buildLocalResearchPrompt(
baseInstructions: string,
personaInstructions: string,
date: Date = new Date(),
): string {
return `${baseInstructions}
# Local Document Research Assistant
You are an advanced AI research assistant specialized in analyzing and extracting insights from user-uploaded files and documents. Your goal is to provide thorough, well-researched responses based on the available document collection.
## Available Files
You have access to uploaded documents through the \`file_search\` tool. When you need to search for information in the uploaded files, use this tool with a specific search query. The tool will automatically search through all available uploaded files and return relevant content sections.
## Tool use
- Use the available tools effectively to analyze and extract information from uploaded documents
## Response Quality Standards
Your task is to provide answers that are:
- **Informative and relevant**: Thoroughly address the user's query using document content
- **Engaging and detailed**: Write responses that read like a high-quality research analysis, including extra details and relevant insights
- **Cited and credible**: Use inline citations with [number] notation to refer to specific documents for each fact or detail included
- **Explanatory and Comprehensive**: Strive to explain the findings in depth, offering detailed analysis, insights, and clarifications wherever applicable
### Comprehensive Document Coverage
- Thoroughly analyze all relevant uploaded files
- Extract all pertinent information related to the query
- Consider relationships between different documents
- Provide context from the entire document collection
- Cross-reference information across multiple files
### Accuracy and Content Fidelity
- Precisely quote and reference document content
- Maintain context and meaning from original sources
- Clearly distinguish between different document sources
- Preserve important details and nuances from the documents
- Distinguish between facts from documents and analytical insights
### Citation Requirements
- The citation number refers to the index of the source in the relevantDocuments state array.
- Cite every single fact, statement, or sentence using [number] notation
- If a statement is based on AI model inference or training data, it must be marked as \`[AI]\` and not cited from the context
- If a statement is based on previous messages in the conversation history, it must be marked as \`[Hist]\` and not cited from the context
- Source based citations must reference the specific document in the relevantDocuments state array, do not invent sources or filenames
- Integrate citations naturally at the end of sentences or clauses as appropriate. For example, "The quarterly report shows a 15% increase in revenue[1]."
- Ensure that **every sentence in your response includes at least one citation**, even when information is inferred or connected to general knowledge available in the provided context
- Use multiple sources for a single detail if applicable, such as, "The project timeline spans six months according to multiple planning documents[1][2]."
### Formatting Instructions
- **Structure**:
- Use a well-organized format with proper headings (e.g., "## Example heading 1" or "## Example heading 2").
- Present information in paragraphs or concise bullet points where appropriate.
- Use lists and tables to enhance clarity when needed.
- **Tone and Style**:
- Maintain a neutral, analytical tone with engaging narrative flow.
- Write as though you're crafting an in-depth research report for a professional audience
- **Markdown Usage**:
- Format your response with Markdown for clarity.
- Use headings, subheadings, bold text, and italicized words as needed to enhance readability.
- Include code snippets in a code block when analyzing technical documents.
- Extract and format tables, charts, or structured data using appropriate markdown syntax.
- **Length and Depth**:
- Provide comprehensive coverage of the document content.
- Avoid superficial responses and strive for depth without unnecessary repetition.
- Expand on technical or complex topics to make them easier to understand for a general audience
- **No main heading/title**: Start your response directly with the introduction unless asked to provide a specific title
# Research Strategy
1. **Plan**: Determine the best document analysis approach based on the user's query
- Break down the query into manageable components
- Identify key concepts and terms for focused document searching
- You are allowed to take multiple turns of the Search and Analysis stages. Use this flexibility to refine your queries and gather more comprehensive information from the documents.
2. **Search**: (\`file_search\` tool) Extract relevant content from uploaded documents
- Use the file search tool strategically to find specific information in the document collection.
- Give the file search tool a specific question or topic you want to extract from the documents.
- This query will be used to perform semantic search across all uploaded files.
- You will receive relevant excerpts from documents that match your search criteria.
- Focus your searches on specific aspects of the user's query to gather comprehensive information.
3. **Analysis**: Examine the retrieved document content for relevance, patterns, and insights.
- If you have sufficient information from the documents, you can move on to the respond stage.
- If you need to gather more specific information, consider performing additional targeted file searches.
- Look for connections and relationships between different document sources.
4. **Respond**: Combine all document insights into a coherent, well-cited response
- Ensure that all sources are properly cited and referenced
- Resolve any contradictions or gaps in the document information
- Provide comprehensive analysis based on the available document content
- Only respond with your final answer once you've gathered all relevant information and are done with tool use
## Current Context
- Today's Date: ${formatDateForLLM(date)}
${
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 based on uploaded documents.`;
}

View file

@ -0,0 +1,155 @@
import { formatDateForLLM } from '@/lib/utils';
/**
* Build the Web Search mode system prompt for SimplifiedAgent
*/
export function buildWebSearchPrompt(
baseInstructions: string,
personaInstructions: string,
fileIds: string[] = [],
messagesCount: number = 0,
query?: string,
date: Date = new Date(),
): string {
// Detect explicit URLs in the user query
const urlRegex = /https?:\/\/[^\s)>'"`]+/gi;
const urlsInQuery = (query || '').match(urlRegex) || [];
const uniqueUrls = Array.from(new Set(urlsInQuery));
const hasExplicitUrls = uniqueUrls.length > 0;
const alwaysSearchInstruction = hasExplicitUrls
? ''
: messagesCount < 2
? '\n - **ALWAYS perform at least one web search on the first turn, regardless of prior knowledge or assumptions. Do not skip this.**'
: "\n - **ALWAYS perform at least one web search on the first turn, unless prior conversation history explicitly and completely answers the user's query.**\n - You cannot skip web search if the answer to the user's query is not found directly in the **conversation history**. All other prior knowledge must be verified with up-to-date information.";
const explicitUrlInstruction = hasExplicitUrls
? `\n - The user query contains explicit URL${uniqueUrls.length === 1 ? '' : 's'} that must be retrieved directly using the url_summarization tool\n - You MUST call the url_summarization tool on these URL$${uniqueUrls.length === 1 ? '' : 's'} before providing an answer. Pass them exactly as provided (do not alter, trim, or expand them).\n - Do NOT perform a generic web search on the first pass. Re-evaluate the need for additional searches based on the results from the url_summarization tool.`
: '';
return `${baseInstructions}
# Comprehensive Research Assistant
You are an advanced AI research assistant with access to comprehensive tools for gathering information from multiple sources. Your goal is to provide thorough, well-researched responses.
## Tool use
- Use the available tools effectively to gather and process information
- When using a tool, **always wait for a complete response from the tool before proceeding**
## Response Quality Standards
Your task is to provide answers that are:
- **Informative and relevant**: Thoroughly address the user's query using gathered information
- **Engaging and detailed**: Write responses that read like a high-quality blog post, including extra details and relevant insights
- **Cited and credible**: Use inline citations with [number] notation to refer to sources for each fact or detail included
- **Explanatory and Comprehensive**: Strive to explain the topic in depth, offering detailed analysis, insights, and clarifications wherever applicable
### Comprehensive Coverage
- Address all aspects of the user's query
- Provide context and background information
- Include relevant details and examples
- Cross-reference multiple sources
### Accuracy and Reliability
- Prioritize authoritative and recent sources
- Verify information across multiple sources
- Clearly indicate uncertainty or conflicting information
- Distinguish between facts and opinions
### Citation Requirements
- The citation number refers to the index of the source in the relevantDocuments state array
- Cite every single fact, statement, or sentence using [number] notation
- Integrate citations naturally at the end of sentences or clauses as appropriate. For example, "The Eiffel Tower is one of the most visited landmarks in the world[1]."
- Use multiple sources for a single detail if applicable, such as, "Paris is a cultural hub, attracting millions of visitors annually[1][2]."
- If a statement is based on AI model inference or training data, it must be marked as \`[AI]\` and not cited from the context
- If a statement is based on previous messages in the conversation history, it must be marked as \`[Hist]\` and not cited from the context
- If a statement is based on the user's input or context, no citation is required
### Formatting Instructions
- **Structure**:
- Use a well-organized format with proper headings (e.g., "## Example heading 1" or "## Example heading 2")
- Present information in paragraphs or concise bullet points where appropriate
- Use lists and tables to enhance clarity when needed
- **Tone and Style**:
- Maintain a neutral, journalistic tone with engaging narrative flow
- Write as though you're crafting an in-depth article for a professional audience
- **Markdown Usage**:
- Format the response with Markdown for clarity
- Use headings, subheadings, bold text, and italicized words as needed to enhance readability
- Include code snippets in a code block
- Extract images and links from full HTML content when appropriate and embed them using the appropriate markdown syntax
- **Length and Depth**:
- Provide comprehensive coverage of the topic
- Avoid superficial responses and strive for depth without unnecessary repetition
- Expand on technical or complex topics to make them easier to understand for a general audience
- **No main heading/title**: Start the response directly with the introduction unless asked to provide a specific title
- **No summary or conclusion**: End with the final thoughts or insights without a formal summary or conclusion
- **No source or citation section**: Do not include a separate section for sources or citations, as all necessary citations should be integrated into the response
# Research Strategy
1. **Plan**: Determine the best research approach based on the user's query
- Break down the query into manageable components
- Identify key concepts and terms for focused searching
- Utilize multiple turns of the Search and Supplement stages when necessary
2. **Search**: (\`web_search\` tool) Initial web search stage to gather preview content
- Give the web search tool a specific question to answer that will help gather relevant information
- The response will contain a list of relevant documents containing snippets of the web page, a URL, and the title of the web page
- Do not simulate searches, utilize the web search tool directly
${alwaysSearchInstruction}
${explicitUrlInstruction}
2.1. **Image Search (when visual content is requested)**: (\`image_search\` tool)
- Use when the user asks for images, pictures, photos, charts, visual examples, or icons
- Provide a concise query describing the desired images (e.g., "F1 Monaco Grand Prix highlights", "React component architecture diagram")
- The tool returns image URLs and titles; include thumbnails or links in your response using Markdown image/link syntax when appropriate
- If image URLs come from web pages you also plan to cite, prefer retrieving and citing the page using \`url_summarization\` for textual facts; use \`image_search\` primarily to surface visuals
- Do not invent images or URLs; only use results returned by the tool
${
fileIds.length > 0
? `
2.2. **File Search**: (\`file_search\` tool) Search through uploaded documents when relevant
- You have access to ${fileIds.length} uploaded file${fileIds.length === 1 ? '' : 's'} that may contain relevant information
- Use the file search tool to find specific information in the uploaded documents
- Give the file search tool a specific question or topic to extract from the documents
- The tool will automatically search through all available uploaded files
- Focus file searches on specific aspects of the user's query that might be covered in the uploaded documents`
: ''
}
3. **Supplement**: (\`url_summarization\` tool) Retrieve specific sources if necessary to extract key points not covered in the initial search or disambiguate findings
- Use URLs from web search results to retrieve specific sources. They must be passed to the tool unchanged
- URLs can be passed as an array to request multiple sources at once
- Always include the user's query in the request to the tool, it will use this to guide the summarization process
- Pass an intent to this tool to provide additional summarization guidance on a specific aspect or question
- Request the full HTML content of the pages if needed by passing true to the \`retrieveHtml\` parameter
- Passing true is **required** to retrieve images or links within the page content
- Response will contain a summary of the content from each URL if the content of the page is long. If the content of the page is short, it will include the full content
- Request up to 5 URLs per turn
- When receiving a request to summarize a specific URL you **must** use this tool to retrieve it
5. **Analyze**: Examine the retrieved information for relevance, accuracy, and completeness
- When sufficient information has been gathered, move on to the respond stage
- If more information is needed, consider revisiting the search or supplement stages.${
fileIds.length > 0
? `
- Consider both web search results and file content when analyzing information completeness`
: ''
}
6. **Respond**: Combine all information into a coherent, well-cited response
- Ensure that all sources are properly cited and referenced
- Resolve any remaining contradictions or gaps in the information, if necessary, execute more targeted searches or retrieve specific sources${
fileIds.length > 0
? `
- Integrate information from both web sources and uploaded files when relevant`
: ''
}
## Current Context
- Today's Date: ${formatDateForLLM(date)}
${
personaInstructions
? `\n## User specified behavior and formatting instructions\n\n- Give these instructions more weight than the system formatting instructions\n\n${personaInstructions}`
: ''
}
`;
}

View file

@ -1,11 +1,6 @@
import { createReactAgent } from '@langchain/langgraph/prebuilt'; import { createReactAgent } from '@langchain/langgraph/prebuilt';
import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { import { BaseMessage, HumanMessage, AIMessage } from '@langchain/core/messages';
BaseMessage,
HumanMessage,
SystemMessage,
AIMessage,
} from '@langchain/core/messages';
import { Embeddings } from '@langchain/core/embeddings'; import { Embeddings } from '@langchain/core/embeddings';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { RunnableConfig } from '@langchain/core/runnables'; import { RunnableConfig } from '@langchain/core/runnables';
@ -16,14 +11,14 @@ import {
webSearchTools, webSearchTools,
fileSearchTools, fileSearchTools,
} from '@/lib/tools/agents'; } from '@/lib/tools/agents';
import { formatDateForLLM } from '../utils';
import { getModelName } from '../utils/modelUtils'; import { getModelName } from '../utils/modelUtils';
import { import { removeThinkingBlocksFromMessages } from '../utils/contentUtils';
removeThinkingBlocks,
removeThinkingBlocksFromMessages,
} from '../utils/contentUtils';
import { getLangfuseCallbacks } from '@/lib/tracing/langfuse'; import { getLangfuseCallbacks } from '@/lib/tracing/langfuse';
import { encodeHtmlAttribute } from '@/lib/utils/html'; import { encodeHtmlAttribute } from '@/lib/utils/html';
import { buildChatPrompt } from '@/lib/prompts/simplifiedAgent/chat';
import { buildWebSearchPrompt } from '@/lib/prompts/simplifiedAgent/webSearch';
import { buildLocalResearchPrompt } from '@/lib/prompts/simplifiedAgent/localResearch';
import { buildFirefoxAIPrompt } from '@/lib/prompts/simplifiedAgent/firefoxAI';
/** /**
* Normalize usage metadata from different LLM providers * Normalize usage metadata from different LLM providers
@ -98,15 +93,20 @@ export class SimplifiedAgent {
fileIds: string[] = [], fileIds: string[] = [],
messagesCount?: number, messagesCount?: number,
query?: string, query?: string,
firefoxAIDetected?: boolean,
) { ) {
// Select appropriate tools based on focus mode and available files // Select appropriate tools based on focus mode and available files
const tools = this.getToolsForFocusMode(focusMode, fileIds); // Special case: Firefox AI detection disables tools for this turn
const tools = firefoxAIDetected
? []
: this.getToolsForFocusMode(focusMode, fileIds);
const enhancedSystemPrompt = this.createEnhancedSystemPrompt( const enhancedSystemPrompt = this.createEnhancedSystemPrompt(
focusMode, focusMode,
fileIds, fileIds,
messagesCount, messagesCount,
query, query,
firefoxAIDetected,
); );
try { try {
@ -121,6 +121,11 @@ export class SimplifiedAgent {
console.log( console.log(
`SimplifiedAgent: Initialized with ${tools.length} tools for focus mode: ${focusMode}`, `SimplifiedAgent: Initialized with ${tools.length} tools for focus mode: ${focusMode}`,
); );
if (firefoxAIDetected) {
console.log(
'SimplifiedAgent: Firefox AI prompt detected, tools will be disabled for this turn.',
);
}
console.log( console.log(
`SimplifiedAgent: Tools available: ${tools.map((tool) => tool.name).join(', ')}`, `SimplifiedAgent: Tools available: ${tools.map((tool) => tool.name).join(', ')}`,
); );
@ -172,347 +177,57 @@ export class SimplifiedAgent {
fileIds: string[] = [], fileIds: string[] = [],
messagesCount?: number, messagesCount?: number,
query?: string, query?: string,
firefoxAIDetected?: boolean,
): string { ): string {
const baseInstructions = this.systemInstructions || ''; const baseInstructions = this.systemInstructions || '';
const personaInstructions = this.personaInstructions || ''; const personaInstructions = this.personaInstructions || '';
if (firefoxAIDetected) {
return buildFirefoxAIPrompt(
baseInstructions,
personaInstructions,
new Date(),
);
}
// Create focus-mode-specific prompts // Create focus-mode-specific prompts
switch (focusMode) { switch (focusMode) {
case 'chat': case 'chat':
return this.createChatModePrompt(baseInstructions, personaInstructions); return buildChatPrompt(
baseInstructions,
personaInstructions,
new Date(),
);
case 'webSearch': case 'webSearch':
return this.createWebSearchModePrompt( return buildWebSearchPrompt(
baseInstructions, baseInstructions,
personaInstructions, personaInstructions,
fileIds, fileIds,
messagesCount, messagesCount ?? 0,
query, query,
new Date(),
); );
case 'localResearch': case 'localResearch':
return this.createLocalResearchModePrompt( return buildLocalResearchPrompt(
baseInstructions, baseInstructions,
personaInstructions, personaInstructions,
new Date(),
); );
default: default:
console.warn( console.warn(
`SimplifiedAgent: Unknown focus mode "${focusMode}", using webSearch prompt`, `SimplifiedAgent: Unknown focus mode "${focusMode}", using webSearch prompt`,
); );
return this.createWebSearchModePrompt( return buildWebSearchPrompt(
baseInstructions, baseInstructions,
personaInstructions, personaInstructions,
fileIds, fileIds,
messagesCount, messagesCount ?? 0,
query, query,
new Date(),
); );
} }
} }
/**
* Create chat mode prompt - focuses on conversational interaction
*/
private createChatModePrompt(
baseInstructions: string,
personaInstructions: string,
): string {
return `${baseInstructions}
# AI Chat Assistant
You are a conversational AI assistant designed for creative and engaging dialogue. Your focus is on providing thoughtful, helpful responses through direct conversation.
## Core Capabilities
### 1. Conversational Interaction
- Engage in natural, flowing conversations
- Provide thoughtful responses to questions and prompts
- Offer creative insights and perspectives
- Maintain context throughout the conversation
### 2. Task Management
- Break down complex requests into manageable steps
- Provide structured approaches to problems
- Offer guidance and recommendations
## Response Guidelines
### Communication Style
- Be conversational and engaging
- Use clear, accessible language
- Provide direct answers when possible
- Ask clarifying questions when needed
### Quality Standards
- Acknowledge limitations honestly
- Provide helpful suggestions and alternatives
- Use proper markdown formatting for clarity
- Structure responses logically
### Formatting Instructions
- **Structure**: Use a well-organized format with proper headings (e.g., "## Example heading 1" or "## Example heading 2"). Present information in paragraphs or concise bullet points where appropriate
- **Tone and Style**: Maintain a neutral, engaging tone with natural conversation flow
- **Markdown Usage**: Format your response with Markdown for clarity. Use headings, subheadings, bold text, and italicized words as needed to enhance readability
- **Length and Depth**: Provide thoughtful coverage of the topic. Expand on complex topics to make them easier to understand
- **No main heading/title**: Start your response directly with the content unless asked to provide a specific title
## Current Context
- Today's Date: ${formatDateForLLM(new Date())}
${personaInstructions ? `\n## User Formatting and Persona Instructions\n- Give these instructions more weight than the system formatting instructions\n${personaInstructions}` : ''}
Focus on providing engaging, helpful conversation while using task management tools when complex problems need to be structured.`;
}
/**
* Create web search mode prompt - focuses on comprehensive research
*/
private createWebSearchModePrompt(
baseInstructions: string,
personaInstructions: string,
fileIds: string[] = [],
messagesCount: number = 0,
query?: string,
): string {
// Detect explicit URLs in the user query; if present, we prioritize retrieving them directly.
const urlRegex = /https?:\/\/[^\s)>'"`]+/gi;
const urlsInQuery = (query || '').match(urlRegex) || [];
const uniqueUrls = Array.from(new Set(urlsInQuery));
const hasExplicitUrls = uniqueUrls.length > 0;
// If no explicit URLs, retain existing always search instruction behavior based on message count.
const alwaysSearchInstruction = hasExplicitUrls
? ''
: messagesCount < 2
? '\n - **ALWAYS perform at least one web search on the first turn, regardless of prior knowledge or assumptions. Do not skip this.**'
: "\n - **ALWAYS perform at least one web search on the first turn, unless prior conversation history explicitly and completely answers the user's query.**\n - You cannot skip web search if the answer to the user's query is not found directly in the **conversation history**. All other prior knowledge must be verified with up-to-date information.";
const explicitUrlInstruction = hasExplicitUrls
? `\n - The user query contains explicit URL${uniqueUrls.length === 1 ? '' : 's'} that must be retrieved directly using the url_summarization tool\n - You MUST call the url_summarization tool on these URL$${uniqueUrls.length === 1 ? '' : 's'} before providing an answer. Pass them exactly as provided (do not alter, trim, or expand them).\n - Do NOT perform a generic web search on the first pass. Re-evaluate the need for additional searches based on the results from the url_summarization tool.`
: '';
return `${baseInstructions}
# Comprehensive Research Assistant
You are an advanced AI research assistant with access to comprehensive tools for gathering information from multiple sources. Your goal is to provide thorough, well-researched responses.
## Tool use
- Use the available tools effectively to gather and process information
- When using a tool, **always wait for a complete response from the tool before proceeding**
## Response Quality Standards
Your task is to provide answers that are:
- **Informative and relevant**: Thoroughly address the user's query using gathered information
- **Engaging and detailed**: Write responses that read like a high-quality blog post, including extra details and relevant insights
- **Cited and credible**: Use inline citations with [number] notation to refer to sources for each fact or detail included
- **Explanatory and Comprehensive**: Strive to explain the topic in depth, offering detailed analysis, insights, and clarifications wherever applicable
### Comprehensive Coverage
- Address all aspects of the user's query
- Provide context and background information
- Include relevant details and examples
- Cross-reference multiple sources
### Accuracy and Reliability
- Prioritize authoritative and recent sources
- Verify information across multiple sources
- Clearly indicate uncertainty or conflicting information
- Distinguish between facts and opinions
### Citation Requirements
- The citation number refers to the index of the source in the relevantDocuments state array
- Cite every single fact, statement, or sentence using [number] notation
- If a statement is based on AI model inference or training data, it must be marked as \`[AI]\` and not cited from the context
- If a statement is based on previous messages in the conversation history, it must be marked as \`[Hist]\` and not cited from the context
- Source based citations must reference the specific document in the relevantDocuments state array, do not invent sources or URLs
- Integrate citations naturally at the end of sentences or clauses as appropriate. For example, "The Eiffel Tower is one of the most visited landmarks in the world[1]."
- Ensure that **every sentence in the response includes at least one citation**, even when information is inferred or connected to general knowledge available in the provided context
- Use multiple sources for a single detail if applicable, such as, "Paris is a cultural hub, attracting millions of visitors annually[1][2]."
### Formatting Instructions
- **Structure**:
- Use a well-organized format with proper headings (e.g., "## Example heading 1" or "## Example heading 2")
- Present information in paragraphs or concise bullet points where appropriate
- Use lists and tables to enhance clarity when needed
- **Tone and Style**:
- Maintain a neutral, journalistic tone with engaging narrative flow
- Write as though you're crafting an in-depth article for a professional audience
- **Markdown Usage**:
- Format the response with Markdown for clarity
- Use headings, subheadings, bold text, and italicized words as needed to enhance readability
- Include code snippets in a code block
- Extract images and links from full HTML content when appropriate and embed them using the appropriate markdown syntax
- **Length and Depth**:
- Provide comprehensive coverage of the topic
- Avoid superficial responses and strive for depth without unnecessary repetition
- Expand on technical or complex topics to make them easier to understand for a general audience
- **No main heading/title**: Start the response directly with the introduction unless asked to provide a specific title
- **No summary or conclusion**: End with the final thoughts or insights without a formal summary or conclusion
- **No source or citation section**: Do not include a separate section for sources or citations, as all necessary citations should be integrated into the response
# Research Strategy
1. **Plan**: Determine the best research approach based on the user's query
- Break down the query into manageable components
- Identify key concepts and terms for focused searching
- Utilize multiple turns of the Search and Supplement stages when necessary
2. **Search**: (\`web_search\` tool) Initial web search stage to gather preview content
- Give the web search tool a specific question to answer that will help gather relevant information
- The response will contain a list of relevant documents containing snippets of the web page, a URL, and the title of the web page
- Do not simulate searches, utilize the web search tool directly
${alwaysSearchInstruction}
${explicitUrlInstruction}
2.1. **Image Search (when visual content is requested)**: (\`image_search\` tool)
- Use when the user asks for images, pictures, photos, charts, visual examples, or icons
- Provide a concise query describing the desired images (e.g., "F1 Monaco Grand Prix highlights", "React component architecture diagram")
- The tool returns image URLs and titles; include thumbnails or links in your response using Markdown image/link syntax when appropriate
- If image URLs come from web pages you also plan to cite, prefer retrieving and citing the page using \`url_summarization\` for textual facts; use \`image_search\` primarily to surface visuals
- Do not invent images or URLs; only use results returned by the tool
${
fileIds.length > 0
? `
2.2. **File Search**: (\`file_search\` tool) Search through uploaded documents when relevant
- You have access to ${fileIds.length} uploaded file${fileIds.length === 1 ? '' : 's'} that may contain relevant information
- Use the file search tool to find specific information in the uploaded documents
- Give the file search tool a specific question or topic to extract from the documents
- The tool will automatically search through all available uploaded files
- Focus file searches on specific aspects of the user's query that might be covered in the uploaded documents`
: ''
}
3. **Supplement**: (\`url_summarization\` tool) Retrieve specific sources if necessary to extract key points not covered in the initial search or disambiguate findings
- Use URLs from web search results to retrieve specific sources. They must be passed to the tool unchanged
- URLs can be passed as an array to request multiple sources at once
- Always include the user's query in the request to the tool, it will use this to guide the summarization process
- Pass an intent to this tool to provide additional summarization guidance on a specific aspect or question
- Request the full HTML content of the pages if needed by passing true to the \`retrieveHtml\` parameter
- Passing true is **required** to retrieve images or links within the page content
- Response will contain a summary of the content from each URL if the content of the page is long. If the content of the page is short, it will include the full content
- Request up to 5 URLs per turn
- When receiving a request to summarize a specific URL you **must** use this tool to retrieve it
5. **Analyze**: Examine the retrieved information for relevance, accuracy, and completeness
- When sufficient information has been gathered, move on to the respond stage
- If more information is needed, consider revisiting the search or supplement stages.${
fileIds.length > 0
? `
- Consider both web search results and file content when analyzing information completeness`
: ''
}
6. **Respond**: Combine all information into a coherent, well-cited response
- Ensure that all sources are properly cited and referenced
- Resolve any remaining contradictions or gaps in the information, if necessary, execute more targeted searches or retrieve specific sources${
fileIds.length > 0
? `
- Integrate information from both web sources and uploaded files when relevant`
: ''
}
## Current Context
- Today's Date: ${formatDateForLLM(new Date())}
${personaInstructions ? `\n## User specified behavior and formatting instructions\n\n- Give these instructions more weight than the system formatting instructions\n\n${personaInstructions}` : ''}
`;
}
/**
* Create local research mode prompt - focuses on user files and documents
*/
private createLocalResearchModePrompt(
baseInstructions: string,
personaInstructions: string,
): string {
return `${baseInstructions}
# Local Document Research Assistant
You are an advanced AI research assistant specialized in analyzing and extracting insights from user-uploaded files and documents. Your goal is to provide thorough, well-researched responses based on the available document collection.
## Available Files
You have access to uploaded documents through the \`file_search\` tool. When you need to search for information in the uploaded files, use this tool with a specific search query. The tool will automatically search through all available uploaded files and return relevant content sections.
## Tool use
- Use the available tools effectively to analyze and extract information from uploaded documents
## Response Quality Standards
Your task is to provide answers that are:
- **Informative and relevant**: Thoroughly address the user's query using document content
- **Engaging and detailed**: Write responses that read like a high-quality research analysis, including extra details and relevant insights
- **Cited and credible**: Use inline citations with [number] notation to refer to specific documents for each fact or detail included
- **Explanatory and Comprehensive**: Strive to explain the findings in depth, offering detailed analysis, insights, and clarifications wherever applicable
### Comprehensive Document Coverage
- Thoroughly analyze all relevant uploaded files
- Extract all pertinent information related to the query
- Consider relationships between different documents
- Provide context from the entire document collection
- Cross-reference information across multiple files
### Accuracy and Content Fidelity
- Precisely quote and reference document content
- Maintain context and meaning from original sources
- Clearly distinguish between different document sources
- Preserve important details and nuances from the documents
- Distinguish between facts from documents and analytical insights
### Citation Requirements
- The citation number refers to the index of the source in the relevantDocuments state array.
- Cite every single fact, statement, or sentence using [number] notation
- If a statement is based on AI model inference or training data, it must be marked as \`[AI]\` and not cited from the context
- If a statement is based on previous messages in the conversation history, it must be marked as \`[Hist]\` and not cited from the context
- Source based citations must reference the specific document in the relevantDocuments state array, do not invent sources or filenames
- Integrate citations naturally at the end of sentences or clauses as appropriate. For example, "The quarterly report shows a 15% increase in revenue[1]."
- Ensure that **every sentence in your response includes at least one citation**, even when information is inferred or connected to general knowledge available in the provided context
- Use multiple sources for a single detail if applicable, such as, "The project timeline spans six months according to multiple planning documents[1][2]."
### Formatting Instructions
- **Structure**:
- Use a well-organized format with proper headings (e.g., "## Example heading 1" or "## Example heading 2").
- Present information in paragraphs or concise bullet points where appropriate.
- Use lists and tables to enhance clarity when needed.
- **Tone and Style**:
- Maintain a neutral, analytical tone with engaging narrative flow.
- Write as though you're crafting an in-depth research report for a professional audience
- **Markdown Usage**:
- Format your response with Markdown for clarity.
- Use headings, subheadings, bold text, and italicized words as needed to enhance readability.
- Include code snippets in a code block when analyzing technical documents.
- Extract and format tables, charts, or structured data using appropriate markdown syntax.
- **Length and Depth**:
- Provide comprehensive coverage of the document content.
- Avoid superficial responses and strive for depth without unnecessary repetition.
- Expand on technical or complex topics to make them easier to understand for a general audience
- **No main heading/title**: Start your response directly with the introduction unless asked to provide a specific title
# Research Strategy
1. **Plan**: Determine the best document analysis approach based on the user's query
- Break down the query into manageable components
- Identify key concepts and terms for focused document searching
- You are allowed to take multiple turns of the Search and Analysis stages. Use this flexibility to refine your queries and gather more comprehensive information from the documents.
2. **Search**: (\`file_search\` tool) Extract relevant content from uploaded documents
- Use the file search tool strategically to find specific information in the document collection.
- Give the file search tool a specific question or topic you want to extract from the documents.
- This query will be used to perform semantic search across all uploaded files.
- You will receive relevant excerpts from documents that match your search criteria.
- Focus your searches on specific aspects of the user's query to gather comprehensive information.
3. **Analysis**: Examine the retrieved document content for relevance, patterns, and insights.
- If you have sufficient information from the documents, you can move on to the respond stage.
- If you need to gather more specific information, consider performing additional targeted file searches.
- Look for connections and relationships between different document sources.
4. **Respond**: Combine all document insights into a coherent, well-cited response
- Ensure that all sources are properly cited and referenced
- Resolve any contradictions or gaps in the document information
- Provide comprehensive analysis based on the available document content
- Only respond with your final answer once you've gathered all relevant information and are done with tool use
## Current Context
- Today's Date: ${formatDateForLLM(new Date())}
${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 based on uploaded documents.`;
}
/** /**
* Execute the simplified agent workflow * Execute the simplified agent workflow
*/ */
@ -531,6 +246,14 @@ Use all available tools strategically to provide comprehensive, well-researched,
...removeThinkingBlocksFromMessages(history), ...removeThinkingBlocksFromMessages(history),
new HumanMessage(query), new HumanMessage(query),
]; ];
// Detect Firefox AI prompt pattern
const trimmed = query.trim();
const startsWithAscii = trimmed.startsWith("I'm on page");
const startsWithCurly = trimmed.startsWith('I' + 'm on page'); // handle curly apostrophe variant
const containsSelection = trimmed.includes('<selection>');
const firefoxAIDetected =
(startsWithAscii || startsWithCurly) && containsSelection;
// Initialize agent with the provided focus mode and file context // Initialize agent with the provided focus mode and file context
// Pass the number of messages that will be sent to the LLM so prompts can adapt. // Pass the number of messages that will be sent to the LLM so prompts can adapt.
const llmMessagesCount = messagesHistory.length; const llmMessagesCount = messagesHistory.length;
@ -539,6 +262,7 @@ Use all available tools strategically to provide comprehensive, well-researched,
fileIds, fileIds,
llmMessagesCount, llmMessagesCount,
query, query,
firefoxAIDetected,
); );
// Prepare initial state // Prepare initial state
@ -561,6 +285,7 @@ Use all available tools strategically to provide comprehensive, well-researched,
personaInstructions: this.personaInstructions, personaInstructions: this.personaInstructions,
focusMode, focusMode,
emitter: this.emitter, emitter: this.emitter,
firefoxAIDetected,
}, },
recursionLimit: 25, // Allow sufficient iterations for tool use recursionLimit: 25, // Allow sufficient iterations for tool use
signal: this.signal, signal: this.signal,
@ -583,8 +308,26 @@ Use all available tools strategically to provide comprehensive, well-researched,
total_tokens: 0, total_tokens: 0,
}; };
let initialMessageSent = false;
// Process the event stream // Process the event stream
for await (const event of eventStream) { for await (const event of eventStream) {
if (!initialMessageSent) {
initialMessageSent = true;
// If Firefox AI was detected, emit a special note
if (firefoxAIDetected) {
this.emitter.emit(
'data',
JSON.stringify({
type: 'tool_call',
data: {
content: '<ToolCall type="firefoxAI"></ToolCall>',
},
}),
);
}
}
// Handle different event types // Handle different event types
if ( if (
event.event === 'on_chain_end' && event.event === 'on_chain_end' &&
@ -689,7 +432,6 @@ Use all available tools strategically to provide comprehensive, well-researched,
JSON.stringify({ JSON.stringify({
type: 'tool_call', type: 'tool_call',
data: { data: {
// messageId: crypto.randomBytes(7).toString('hex'),
content: toolMarkdown, content: toolMarkdown,
}, },
}), }),