Skip to content

Commit 07cd6f9

Browse files
committed
Better ui
1 parent c53e950 commit 07cd6f9

File tree

5 files changed

+26
-133
lines changed

5 files changed

+26
-133
lines changed

apps/sim/app/api/copilot/route.ts

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -137,39 +137,7 @@ export async function POST(req: NextRequest) {
137137
logger.info(`[${requestId}] StreamingExecution detected`)
138138
streamToRead = (result.response as any).stream
139139

140-
// Extract citations from StreamingExecution at API level
141-
const execution = (result.response as any).execution
142-
logger.info(`[${requestId}] Extracting citations from StreamingExecution`, {
143-
hasExecution: !!execution,
144-
hasToolResults: !!execution?.toolResults,
145-
toolResultsLength: execution?.toolResults?.length || 0,
146-
})
147-
148-
if (execution?.toolResults) {
149-
for (const toolResult of execution.toolResults) {
150-
logger.info(`[${requestId}] Processing tool result for citations`, {
151-
hasResult: !!toolResult,
152-
resultKeys: toolResult && typeof toolResult === 'object' ? Object.keys(toolResult) : [],
153-
hasResultsArray: !!(toolResult && typeof toolResult === 'object' && toolResult.results),
154-
})
155-
156-
if (toolResult && typeof toolResult === 'object' && toolResult.results) {
157-
// Convert documentation search results to citations
158-
const extractedCitations = toolResult.results.map((res: any, index: number) => ({
159-
id: index + 1,
160-
title: res.title || 'Documentation',
161-
url: res.url || '#',
162-
similarity: res.similarity,
163-
}))
164-
result.citations = extractedCitations
165-
logger.info(
166-
`[${requestId}] Extracted ${extractedCitations.length} citations from tool results:`,
167-
extractedCitations
168-
)
169-
break // Use first set of results found
170-
}
171-
}
172-
}
140+
// No need to extract citations - LLM generates direct markdown links
173141
}
174142

175143
if (streamToRead) {
@@ -187,7 +155,6 @@ export async function POST(req: NextRequest) {
187155
const metadata = {
188156
type: 'metadata',
189157
chatId: result.chatId,
190-
citations: result.citations || [],
191158
metadata: {
192159
requestId,
193160
message,
@@ -245,7 +212,6 @@ export async function POST(req: NextRequest) {
245212
success: true,
246213
response: result.response,
247214
chatId: result.chatId,
248-
citations: result.citations || [],
249215
metadata: {
250216
requestId,
251217
message,

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -152,39 +152,17 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(
152152
return new Date(timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
153153
}
154154

155-
// Function to render content with inline hyperlinked citations and basic markdown
156-
const renderContentWithCitations = (
157-
content: string,
158-
citations: CopilotMessage['citations'] = []
159-
) => {
155+
// Function to render content with basic markdown (including direct links from LLM)
156+
const renderMarkdownContent = (content: string) => {
160157
if (!content) return content
161158

162159
let processedContent = content
163160

164-
// Replace [1], [2], [3] etc. with clickable citation icons
165-
processedContent = processedContent.replace(/\[(\d+)\]/g, (match, num) => {
166-
const citationIndex = Number.parseInt(num) - 1
167-
const citation = citations?.[citationIndex]
168-
169-
if (citation) {
170-
return `<a href="${citation.url}" target="_blank" rel="noopener noreferrer" class="inline-flex items-center ml-1 text-primary hover:text-primary/80 transition-colors text-sm" title="${citation.title}">↗</a>`
171-
}
172-
173-
return match
174-
})
175-
176-
// Also replace standalone ↗ symbols with clickable citation links
177-
if (citations && citations.length > 0) {
178-
let citationIndex = 0
179-
processedContent = processedContent.replace(//g, () => {
180-
if (citationIndex < citations.length) {
181-
const citation = citations[citationIndex]
182-
citationIndex++
183-
return `<a href="${citation.url}" target="_blank" rel="noopener noreferrer" class="inline-flex items-center text-primary hover:text-primary/80 transition-colors text-sm" title="${citation.title}">↗</a>`
184-
}
185-
return '↗'
186-
})
187-
}
161+
// Process markdown links: [text](url)
162+
processedContent = processedContent.replace(
163+
/\[([^\]]+)\]\(([^\)]+)\)/g,
164+
'<a href="$2" target="_blank" rel="noopener noreferrer" class="text-blue-600 hover:text-blue-800 font-semibold underline transition-colors">$1</a>'
165+
)
188166

189167
// Basic markdown processing
190168
processedContent = processedContent
@@ -244,12 +222,12 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(
244222
</span>
245223
</div>
246224

247-
{/* Enhanced content rendering with inline citations */}
225+
{/* Enhanced content rendering with markdown links */}
248226
<div className='prose prose-sm dark:prose-invert max-w-none'>
249227
<div
250228
className='text-foreground text-sm leading-normal'
251229
dangerouslySetInnerHTML={{
252-
__html: renderContentWithCitations(message.content, message.citations),
230+
__html: renderMarkdownContent(message.content),
253231
}}
254232
/>
255233
</div>

apps/sim/lib/copilot/config.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ WHEN NOT TO SEARCH:
6767
6868
CITATION FORMAT:
6969
When you reference information from documentation sources, use this format:
70-
- Use [1], [2], [3] etc. to cite sources
71-
- Place citations at the end of sentences that reference specific information
72-
- Each source should only be cited once in your response
73-
- Continue your full response after adding citations - don't stop mid-answer
70+
- Include direct links using markdown format: [link text](URL)
71+
- Use descriptive link text (e.g., "workflow documentation" not "here")
72+
- Place links naturally in context, not clustered at the end
73+
- Only link when it adds value - don't over-link basic concepts
7474
75-
IMPORTANT: Always provide complete, helpful responses. If you add citations, continue writing your full answer. Do not stop your response after adding a citation.`,
75+
IMPORTANT: Always provide complete, helpful responses. Include relevant links to help users find more detailed information.`,
7676
},
7777
rag: {
7878
defaultProvider: 'anthropic',

apps/sim/lib/copilot/service.ts

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -271,15 +271,14 @@ Content: ${result.content}`
271271

272272
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.
273273
274-
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.
274+
IMPORTANT: When referencing information from sources, include direct links using markdown format: [link text](URL)
275275
276276
Citation Guidelines:
277-
- Cite each source only ONCE at the specific header or topic that relates to that source
278-
- Do NOT repeatedly cite the same source throughout your response
279-
- Place citations directly after the header or concept that the source specifically addresses
280-
- If multiple sources support the same specific topic, cite them together like {cite:1}{cite:2}{cite:3}
281-
- Each citation should be placed at the relevant header/topic it supports, not grouped at the beginning
282-
- Avoid cluttering the text with excessive citations
277+
- When mentioning specific features or concepts, link directly to the relevant documentation
278+
- Use the exact URLs provided in the source context
279+
- Make link text descriptive (e.g., "workflow documentation" not "here")
280+
- Place links naturally in context, not clustered at the end
281+
- Only link when it adds value - don't over-link basic concepts
283282
284283
Content Guidelines:
285284
- Answer the user's question accurately using the provided documentation
@@ -291,7 +290,7 @@ Content Guidelines:
291290
- NEVER include object representations like "[object Object]" - always use proper text
292291
- When mentioning tool names, use their actual names from the documentation
293292
294-
The sources are numbered [1] through [${searchResults.length}] in the context below.`
293+
Each source in the context below includes a URL that you can reference directly.`
295294

296295
const userPrompt = `${conversationContext}Current Question: ${query}
297296
@@ -692,7 +691,6 @@ export async function deleteChat(chatId: string, userId: string): Promise<boolea
692691
export async function sendMessage(request: SendMessageRequest): Promise<{
693692
response: string | ReadableStream | any
694693
chatId?: string
695-
citations?: Array<{ id: number; title: string; url: string; similarity?: number }>
696694
}> {
697695
const { message, chatId, workflowId, createNewChat, stream, userId } = request
698696

@@ -718,40 +716,7 @@ export async function sendMessage(request: SendMessageRequest): Promise<{
718716
workflowId,
719717
})
720718

721-
// Extract citations from StreamingExecution if available
722-
let citations: Array<{ id: number; title: string; url: string; similarity?: number }> = []
723-
724-
if (typeof response === 'object' && response && 'execution' in response) {
725-
// This is a StreamingExecution - extract citations from tool calls
726-
const execution = (response as any).execution
727-
logger.info('Extracting citations from StreamingExecution', {
728-
hasExecution: !!execution,
729-
hasToolResults: !!execution?.toolResults,
730-
toolResultsLength: execution?.toolResults?.length || 0,
731-
})
732-
733-
if (execution?.toolResults) {
734-
for (const toolResult of execution.toolResults) {
735-
logger.info('Processing tool result for citations', {
736-
hasResult: !!toolResult,
737-
resultKeys: toolResult && typeof toolResult === 'object' ? Object.keys(toolResult) : [],
738-
hasResultsArray: !!(toolResult && typeof toolResult === 'object' && toolResult.results),
739-
})
740-
741-
if (toolResult && typeof toolResult === 'object' && toolResult.results) {
742-
// Convert documentation search results to citations
743-
citations = toolResult.results.map((result: any, index: number) => ({
744-
id: index + 1,
745-
title: result.title || 'Documentation',
746-
url: result.url || '#',
747-
similarity: result.similarity,
748-
}))
749-
logger.info(`Extracted ${citations.length} citations from tool results`)
750-
break // Use first set of results found
751-
}
752-
}
753-
}
754-
}
719+
// No need to extract citations - LLM generates direct markdown links
755720

756721
// For non-streaming responses, save immediately
757722
// 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<{
768733
role: 'assistant',
769734
content: response,
770735
timestamp: new Date().toISOString(),
771-
citations: citations.length > 0 ? citations : undefined,
772736
}
773737

774738
const updatedMessages = [...conversationHistory, userMessage, assistantMessage]
@@ -788,7 +752,6 @@ export async function sendMessage(request: SendMessageRequest): Promise<{
788752
return {
789753
response,
790754
chatId: currentChat?.id,
791-
citations,
792755
}
793756
} catch (error) {
794757
logger.error('Failed to send message:', error)

apps/sim/stores/copilot/store.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ export const useCopilotStore = create<CopilotStore>()(
363363
const decoder = new TextDecoder()
364364
let accumulatedContent = ''
365365
let newChatId: string | undefined
366-
let responseCitations: Array<{ id: number; title: string; url: string }> = []
366+
// Citations no longer needed - LLM generates direct markdown links
367367
let streamComplete = false
368368

369369
try {
@@ -381,21 +381,11 @@ export const useCopilotStore = create<CopilotStore>()(
381381
const data = JSON.parse(line.slice(6))
382382

383383
if (data.type === 'metadata') {
384-
// Get chatId and citations from metadata
384+
// Get chatId from metadata
385385
if (data.chatId) {
386386
newChatId = data.chatId
387387
}
388-
if (data.citations) {
389-
responseCitations = data.citations
390-
}
391-
if (data.sources) {
392-
// Convert sources to citations format
393-
responseCitations = data.sources.map((source: any, index: number) => ({
394-
id: index + 1,
395-
title: source.title,
396-
url: source.link,
397-
}))
398-
}
388+
// Citations no longer needed - LLM generates direct markdown links
399389
} else if (data.type === 'content') {
400390
console.log('[CopilotStore] Received content chunk:', data.content)
401391
accumulatedContent += data.content
@@ -411,8 +401,6 @@ export const useCopilotStore = create<CopilotStore>()(
411401
? {
412402
...msg,
413403
content: accumulatedContent,
414-
citations:
415-
responseCitations.length > 0 ? responseCitations : undefined,
416404
}
417405
: msg
418406
),
@@ -427,8 +415,6 @@ export const useCopilotStore = create<CopilotStore>()(
427415
? {
428416
...msg,
429417
content: accumulatedContent,
430-
citations:
431-
responseCitations.length > 0 ? responseCitations : undefined,
432418
}
433419
: msg
434420
),

0 commit comments

Comments
 (0)