Skip to content

Commit a3159bc

Browse files
committed
Fix streaming bug
1 parent 2354909 commit a3159bc

File tree

3 files changed

+56
-56
lines changed

3 files changed

+56
-56
lines changed

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

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ function extractCitationsFromResponse(response: any): Array<{
7878
title: string
7979
url: string
8080
}> {
81+
// Handle ReadableStream responses
82+
if (response instanceof ReadableStream) {
83+
return []
84+
}
85+
86+
// Handle string responses
87+
if (typeof response === 'string') {
88+
return []
89+
}
90+
91+
// Handle object responses
92+
if (typeof response !== 'object' || !response) {
93+
return []
94+
}
95+
96+
// Check for tool results
8197
if (!response.toolResults || !Array.isArray(response.toolResults)) {
8298
return []
8399
}
@@ -131,39 +147,28 @@ async function generateChatResponse(
131147
- Troubleshooting issues
132148
- Best practices
133149
134-
You have access to the Sim Studio documentation through a search tool, but use it SELECTIVELY.
150+
You have access to the Sim Studio documentation through a search tool. Use it when users ask about Sim Studio features, tools, or functionality.
135151
136152
WHEN TO SEARCH DOCUMENTATION:
137-
- User asks "How do I create a workflow?"
138-
- User asks about specific tools or blocks
139-
- User needs help with Sim Studio features
153+
- User asks about specific Sim Studio features or tools
154+
- User needs help with workflows or blocks
140155
- User has technical questions about the platform
156+
- User asks "How do I..." questions about Sim Studio
141157
142-
WHEN NOT TO SEARCH DOCUMENTATION:
143-
- Simple greetings like "hi", "hello", "hey"
144-
- General conversation like "how are you?"
145-
- Thank you messages
158+
WHEN NOT TO SEARCH:
159+
- Simple greetings or casual conversation
146160
- General programming questions unrelated to Sim Studio
147-
- Small talk or casual conversation
148-
149-
Guidelines:
150-
- Be conversational and helpful
151-
- For greetings and casual conversation, respond directly without searching
152-
- Only use docs_search_internal when the user specifically needs information about Sim Studio features
153-
- When you do search, synthesize the information and provide clear, actionable answers
154-
- Be friendly and natural in your responses
155-
156-
CITATION INSTRUCTIONS:
157-
When you search documentation and reference information from the sources, use inline citations strategically and sparingly:
158-
- Use citation markers like {cite:1}, {cite:2}, etc. to reference specific sources
159-
- Cite each source only ONCE at the specific header or topic that relates to that source
160-
- Place citations directly after the header or concept that the source specifically addresses
161-
- If multiple sources support the same topic, cite them together like {cite:1}{cite:2}{cite:3}
162-
- Do NOT repeatedly cite the same source throughout your response
163-
- Only cite sources that you actually reference in your answer
164-
165-
MAKE SURE YOU FULLY ANSWER THE USER'S QUESTION.
166-
`
161+
- Thank you messages or small talk
162+
163+
CITATION FORMAT:
164+
When you reference information from documentation sources, use this format:
165+
- Use [1], [2], [3] etc. to cite sources
166+
- Place citations at the end of sentences that reference specific information
167+
- Each source should only be cited once in your response
168+
- Continue your full response after adding citations - don't stop mid-answer
169+
170+
IMPORTANT: Always provide complete, helpful responses. If you add citations, continue writing your full answer. Do not stop your response after adding a citation.`
171+
167172
// Define the documentation search tool for the LLM
168173
const tools = [
169174
{
@@ -237,7 +242,6 @@ MAKE SURE YOU FULLY ANSWER THE USER'S QUESTION.
237242
})
238243

239244
// Store citations for later use in the main streaming handler
240-
241245
;(streamResponse as any)._citations = responseCitations
242246

243247
return streamResponse
@@ -426,22 +430,12 @@ export async function POST(req: NextRequest) {
426430
}
427431

428432
// Extract citations from response if available
429-
const citations =
430-
typeof response === 'object' && 'citations' in response
431-
? response.citations
432-
: typeof response === 'object' && 'toolResults' in response
433-
? extractCitationsFromResponse(response)
434-
: []
433+
const citations = extractCitationsFromResponse(response)
435434

436435
const assistantMessage = {
437436
id: crypto.randomUUID(),
438437
role: 'assistant',
439-
content:
440-
typeof response === 'string'
441-
? response
442-
: 'content' in response
443-
? response.content
444-
: '[Error generating response]',
438+
content: typeof response === 'string' ? response : (typeof response === 'object' && 'content' in response ? response.content : '[Error generating response]') || '[Error generating response]',
445439
timestamp: new Date().toISOString(),
446440
citations: citations.length > 0 ? citations : undefined,
447441
}
@@ -470,13 +464,9 @@ export async function POST(req: NextRequest) {
470464

471465
return NextResponse.json({
472466
success: true,
473-
response:
474-
typeof response === 'string'
475-
? response
476-
: 'content' in response
477-
? response.content
478-
: '[Error generating response]',
467+
response: typeof response === 'string' ? response : (typeof response === 'object' && 'content' in response ? response.content : '[Error generating response]') || '[Error generating response]',
479468
chatId: currentChat?.id,
469+
citations: extractCitationsFromResponse(response),
480470
metadata: {
481471
requestId,
482472
message,

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,17 @@ function ModalCopilotMessage({ message }: CopilotModalMessage) {
4848
if (!citations || citations.length === 0) return text
4949

5050
let processedText = text
51-
citations.forEach((citation) => {
52-
const citationRegex = new RegExp(`\\{cite:${citation.id}\\}`, 'g')
53-
processedText = processedText.replace(
54-
citationRegex,
55-
`<a href="${citation.url}" target="_blank" rel="noopener noreferrer" class="inline-flex items-center text-primary hover:text-primary/80 text-sm" title="${citation.title}">↗</a>`
56-
)
51+
52+
// Replace [1], [2], [3] etc. with clickable citation icons
53+
processedText = processedText.replace(/\[(\d+)\]/g, (match, num) => {
54+
const citationIndex = Number.parseInt(num) - 1
55+
const citation = citations?.[citationIndex]
56+
57+
if (citation) {
58+
return `<a href="${citation.url}" target="_blank" rel="noopener noreferrer" class="inline-flex items-center text-primary hover:text-primary/80 text-sm" title="${citation.title}">↗</a>`
59+
}
60+
61+
return match
5762
})
5863

5964
return processedText

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,11 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(
209209
let accumulatedContent = ''
210210
let newChatId: string | undefined
211211
let responseCitations: Array<{ id: number; title: string; url: string }> = []
212+
let streamComplete = false
212213

213214
while (true) {
214215
const { done, value } = await reader.read()
215-
if (done) break
216+
if (done || streamComplete) break
216217

217218
const chunk = decoder.decode(value, { stream: true })
218219
const lines = chunk.split('\n')
@@ -276,6 +277,10 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(
276277
// Reload chats in background to get the updated list
277278
loadChats()
278279
}
280+
281+
// Mark stream as complete to exit outer loop
282+
streamComplete = true
283+
break
279284
} else if (data.type === 'error') {
280285
throw new Error(data.error || 'Streaming error')
281286
}
@@ -325,8 +330,8 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(
325330

326331
let processedContent = content
327332

328-
// Replace {cite:1}, {cite:2}, etc. with clickable citation icons
329-
processedContent = processedContent.replace(/\{cite:(\d+)\}/g, (match, num) => {
333+
// Replace [1], [2], [3] etc. with clickable citation icons
334+
processedContent = processedContent.replace(/\[(\d+)\]/g, (match, num) => {
330335
const citationIndex = Number.parseInt(num) - 1
331336
const citation = citations?.[citationIndex]
332337

0 commit comments

Comments
 (0)