diff --git a/apps/sim/app/api/copilot/route.ts b/apps/sim/app/api/copilot/route.ts index f39547d5df..af8813f228 100644 --- a/apps/sim/app/api/copilot/route.ts +++ b/apps/sim/app/api/copilot/route.ts @@ -137,39 +137,7 @@ export async function POST(req: NextRequest) { logger.info(`[${requestId}] StreamingExecution detected`) streamToRead = (result.response as any).stream - // Extract citations from StreamingExecution at API level - const execution = (result.response as any).execution - logger.info(`[${requestId}] Extracting citations from StreamingExecution`, { - hasExecution: !!execution, - hasToolResults: !!execution?.toolResults, - toolResultsLength: execution?.toolResults?.length || 0, - }) - - if (execution?.toolResults) { - for (const toolResult of execution.toolResults) { - logger.info(`[${requestId}] Processing tool result for citations`, { - hasResult: !!toolResult, - resultKeys: toolResult && typeof toolResult === 'object' ? Object.keys(toolResult) : [], - hasResultsArray: !!(toolResult && typeof toolResult === 'object' && toolResult.results), - }) - - if (toolResult && typeof toolResult === 'object' && toolResult.results) { - // Convert documentation search results to citations - const extractedCitations = toolResult.results.map((res: any, index: number) => ({ - id: index + 1, - title: res.title || 'Documentation', - url: res.url || '#', - similarity: res.similarity, - })) - result.citations = extractedCitations - logger.info( - `[${requestId}] Extracted ${extractedCitations.length} citations from tool results:`, - extractedCitations - ) - break // Use first set of results found - } - } - } + // No need to extract citations - LLM generates direct markdown links } if (streamToRead) { @@ -187,7 +155,6 @@ export async function POST(req: NextRequest) { const metadata = { type: 'metadata', chatId: result.chatId, - citations: result.citations || [], metadata: { requestId, message, @@ -245,7 +212,6 @@ export async function POST(req: NextRequest) { success: true, response: result.response, chatId: result.chatId, - citations: result.citations || [], metadata: { requestId, message, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx index 4e9eef1dfd..a07e5272c3 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx @@ -152,39 +152,17 @@ export const Copilot = forwardRef( return new Date(timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) } - // Function to render content with inline hyperlinked citations and basic markdown - const renderContentWithCitations = ( - content: string, - citations: CopilotMessage['citations'] = [] - ) => { + // Function to render content with basic markdown (including direct links from LLM) + const renderMarkdownContent = (content: string) => { if (!content) return content let processedContent = content - // Replace [1], [2], [3] etc. with clickable citation icons - processedContent = processedContent.replace(/\[(\d+)\]/g, (match, num) => { - const citationIndex = Number.parseInt(num) - 1 - const citation = citations?.[citationIndex] - - if (citation) { - return `` - } - - return match - }) - - // Also replace standalone ↗ symbols with clickable citation links - if (citations && citations.length > 0) { - let citationIndex = 0 - processedContent = processedContent.replace(/↗/g, () => { - if (citationIndex < citations.length) { - const citation = citations[citationIndex] - citationIndex++ - return `` - } - return '↗' - }) - } + // Process markdown links: [text](url) + processedContent = processedContent.replace( + /\[([^\]]+)\]\(([^\)]+)\)/g, + '$1' + ) // Basic markdown processing processedContent = processedContent @@ -244,12 +222,12 @@ export const Copilot = forwardRef( - {/* Enhanced content rendering with inline citations */} + {/* Enhanced content rendering with markdown links */}
diff --git a/apps/sim/lib/copilot/config.ts b/apps/sim/lib/copilot/config.ts index c266b5c55b..a264c42deb 100644 --- a/apps/sim/lib/copilot/config.ts +++ b/apps/sim/lib/copilot/config.ts @@ -67,12 +67,12 @@ WHEN NOT TO SEARCH: CITATION FORMAT: When you reference information from documentation sources, use this format: -- Use [1], [2], [3] etc. to cite sources -- Place citations at the end of sentences that reference specific information -- Each source should only be cited once in your response -- Continue your full response after adding citations - don't stop mid-answer +- Include direct links using markdown format: [link text](URL) +- Use descriptive link text (e.g., "workflow documentation" not "here") +- Place links naturally in context, not clustered at the end +- Only link when it adds value - don't over-link basic concepts -IMPORTANT: Always provide complete, helpful responses. If you add citations, continue writing your full answer. Do not stop your response after adding a citation.`, +IMPORTANT: Always provide complete, helpful responses. Include relevant links to help users find more detailed information.`, }, rag: { defaultProvider: 'anthropic', diff --git a/apps/sim/lib/copilot/service.ts b/apps/sim/lib/copilot/service.ts index 5f1243b436..f7c95f3e03 100644 --- a/apps/sim/lib/copilot/service.ts +++ b/apps/sim/lib/copilot/service.ts @@ -271,15 +271,14 @@ Content: ${result.content}` const systemPrompt = `You are a helpful assistant that answers questions about Sim Studio documentation. You are having a conversation with the user, so refer to the conversation history when relevant. -IMPORTANT: Use inline citations strategically and sparingly. When referencing information from the sources, include the citation number in curly braces like {cite:1}, {cite:2}, etc. +IMPORTANT: When referencing information from sources, include direct links using markdown format: [link text](URL) Citation Guidelines: -- Cite each source only ONCE at the specific header or topic that relates to that source -- Do NOT repeatedly cite the same source throughout your response -- Place citations directly after the header or concept that the source specifically addresses -- If multiple sources support the same specific topic, cite them together like {cite:1}{cite:2}{cite:3} -- Each citation should be placed at the relevant header/topic it supports, not grouped at the beginning -- Avoid cluttering the text with excessive citations +- When mentioning specific features or concepts, link directly to the relevant documentation +- Use the exact URLs provided in the source context +- Make link text descriptive (e.g., "workflow documentation" not "here") +- Place links naturally in context, not clustered at the end +- Only link when it adds value - don't over-link basic concepts Content Guidelines: - Answer the user's question accurately using the provided documentation @@ -291,7 +290,7 @@ Content Guidelines: - NEVER include object representations like "[object Object]" - always use proper text - When mentioning tool names, use their actual names from the documentation -The sources are numbered [1] through [${searchResults.length}] in the context below.` +Each source in the context below includes a URL that you can reference directly.` const userPrompt = `${conversationContext}Current Question: ${query} @@ -692,7 +691,6 @@ export async function deleteChat(chatId: string, userId: string): Promise }> { const { message, chatId, workflowId, createNewChat, stream, userId } = request @@ -718,40 +716,7 @@ export async function sendMessage(request: SendMessageRequest): Promise<{ workflowId, }) - // Extract citations from StreamingExecution if available - let citations: Array<{ id: number; title: string; url: string; similarity?: number }> = [] - - if (typeof response === 'object' && response && 'execution' in response) { - // This is a StreamingExecution - extract citations from tool calls - const execution = (response as any).execution - logger.info('Extracting citations from StreamingExecution', { - hasExecution: !!execution, - hasToolResults: !!execution?.toolResults, - toolResultsLength: execution?.toolResults?.length || 0, - }) - - if (execution?.toolResults) { - for (const toolResult of execution.toolResults) { - logger.info('Processing tool result for citations', { - hasResult: !!toolResult, - resultKeys: toolResult && typeof toolResult === 'object' ? Object.keys(toolResult) : [], - hasResultsArray: !!(toolResult && typeof toolResult === 'object' && toolResult.results), - }) - - if (toolResult && typeof toolResult === 'object' && toolResult.results) { - // Convert documentation search results to citations - citations = toolResult.results.map((result: any, index: number) => ({ - id: index + 1, - title: result.title || 'Documentation', - url: result.url || '#', - similarity: result.similarity, - })) - logger.info(`Extracted ${citations.length} citations from tool results`) - break // Use first set of results found - } - } - } - } + // No need to extract citations - LLM generates direct markdown links // For non-streaming responses, save immediately // For streaming responses, save will be handled by the API layer after stream completes @@ -768,7 +733,6 @@ export async function sendMessage(request: SendMessageRequest): Promise<{ role: 'assistant', content: response, timestamp: new Date().toISOString(), - citations: citations.length > 0 ? citations : undefined, } const updatedMessages = [...conversationHistory, userMessage, assistantMessage] @@ -788,7 +752,6 @@ export async function sendMessage(request: SendMessageRequest): Promise<{ return { response, chatId: currentChat?.id, - citations, } } catch (error) { logger.error('Failed to send message:', error) diff --git a/apps/sim/stores/copilot/store.ts b/apps/sim/stores/copilot/store.ts index 956fe8dca7..12e24be395 100644 --- a/apps/sim/stores/copilot/store.ts +++ b/apps/sim/stores/copilot/store.ts @@ -363,7 +363,7 @@ export const useCopilotStore = create()( const decoder = new TextDecoder() let accumulatedContent = '' let newChatId: string | undefined - let responseCitations: Array<{ id: number; title: string; url: string }> = [] + // Citations no longer needed - LLM generates direct markdown links let streamComplete = false try { @@ -381,21 +381,11 @@ export const useCopilotStore = create()( const data = JSON.parse(line.slice(6)) if (data.type === 'metadata') { - // Get chatId and citations from metadata + // Get chatId from metadata if (data.chatId) { newChatId = data.chatId } - if (data.citations) { - responseCitations = data.citations - } - if (data.sources) { - // Convert sources to citations format - responseCitations = data.sources.map((source: any, index: number) => ({ - id: index + 1, - title: source.title, - url: source.link, - })) - } + // Citations no longer needed - LLM generates direct markdown links } else if (data.type === 'content') { console.log('[CopilotStore] Received content chunk:', data.content) accumulatedContent += data.content @@ -411,8 +401,6 @@ export const useCopilotStore = create()( ? { ...msg, content: accumulatedContent, - citations: - responseCitations.length > 0 ? responseCitations : undefined, } : msg ), @@ -427,8 +415,6 @@ export const useCopilotStore = create()( ? { ...msg, content: accumulatedContent, - citations: - responseCitations.length > 0 ? responseCitations : undefined, } : msg ),