1- import { eq , and } from 'drizzle-orm'
1+ import { and , eq } from 'drizzle-orm'
22import { type NextRequest , NextResponse } from 'next/server'
33import { z } from 'zod'
4+ import { getSession } from '@/lib/auth'
45import { createLogger } from '@/lib/logs/console-logger'
56import { getRotatingApiKey } from '@/lib/utils'
6- import { getSession } from '@/lib/auth'
77import { db } from '@/db'
88import { copilotChats } from '@/db/schema'
99import { executeProviderRequest } from '@/providers'
1010import type { Message } from '@/providers/types'
11- import { executeTool } from '@/tools'
1211
1312const logger = createLogger ( 'CopilotChat' )
1413
@@ -34,10 +33,11 @@ const CopilotChatSchema = z.object({
3433async function generateChatTitle ( userMessage : string ) : Promise < string > {
3534 try {
3635 const apiKey = getRotatingApiKey ( 'anthropic' )
37-
36+
3837 const response = await executeProviderRequest ( 'anthropic' , {
3938 model : 'claude-3-haiku-20240307' ,
40- systemPrompt : 'You are a helpful assistant that generates concise, descriptive titles for chat conversations. Create a title that captures the main topic or question being discussed. Keep it under 50 characters and make it specific and clear.' ,
39+ systemPrompt :
40+ 'You are a helpful assistant that generates concise, descriptive titles for chat conversations. Create a title that captures the main topic or question being discussed. Keep it under 50 characters and make it specific and clear.' ,
4141 context : `Generate a concise title for a conversation that starts with this user message: "${ userMessage } "
4242
4343Return only the title text, nothing else.` ,
@@ -58,8 +58,6 @@ Return only the title text, nothing else.`,
5858 }
5959}
6060
61-
62-
6361/**
6462 * Generate chat response with tool calling support
6563 */
@@ -84,8 +82,8 @@ function extractCitationsFromResponse(response: any): Array<{
8482 return [ ]
8583 }
8684
87- const docsSearchResult = response . toolResults . find ( ( result : any ) =>
88- result . sources && Array . isArray ( result . sources )
85+ const docsSearchResult = response . toolResults . find (
86+ ( result : any ) => result . sources && Array . isArray ( result . sources )
8987 )
9088
9189 if ( ! docsSearchResult || ! docsSearchResult . sources ) {
@@ -109,15 +107,16 @@ async function generateChatResponse(
109107
110108 // Build conversation context
111109 const messages : Message [ ] = [ ]
112-
110+
113111 // Add conversation history
114- for ( const msg of conversationHistory . slice ( - 10 ) ) { // Keep last 10 messages
112+ for ( const msg of conversationHistory . slice ( - 10 ) ) {
113+ // Keep last 10 messages
115114 messages . push ( {
116115 role : msg . role as 'user' | 'assistant' | 'system' ,
117116 content : msg . content ,
118117 } )
119118 }
120-
119+
121120 // Add current user message
122121 messages . push ( {
123122 role : 'user' ,
@@ -170,7 +169,8 @@ MAKE SURE YOU FULLY ANSWER THE USER'S QUESTION.
170169 {
171170 id : 'docs_search_internal' ,
172171 name : 'Search Documentation' ,
173- description : 'Search Sim Studio documentation for information about features, tools, workflows, and functionality' ,
172+ description :
173+ 'Search Sim Studio documentation for information about features, tools, workflows, and functionality' ,
174174 params : { } ,
175175 parameters : {
176176 type : 'object' ,
@@ -204,43 +204,42 @@ MAKE SURE YOU FULLY ANSWER THE USER'S QUESTION.
204204 stream : false , // Always start with non-streaming to handle tool calls
205205 } )
206206
207-
208-
209- // If this is a streaming request and we got a regular response,
207+ // If this is a streaming request and we got a regular response,
210208 // we need to create a streaming response from the content
211209 if ( stream && typeof response === 'object' && 'content' in response ) {
212210 const content = response . content || 'Sorry, I could not generate a response.'
213-
211+
214212 // Extract citations from the provider response for later use
215213 const responseCitations = extractCitationsFromResponse ( response )
216-
214+
217215 // Create a ReadableStream that emits the content in character chunks
218216 const streamResponse = new ReadableStream ( {
219217 start ( controller ) {
220218 // Use character-based streaming for more reliable transmission
221219 const chunkSize = 8 // Stream 8 characters at a time for smooth experience
222220 let index = 0
223-
221+
224222 const pushNext = ( ) => {
225223 if ( index < content . length ) {
226224 const chunk = content . slice ( index , index + chunkSize )
227225 controller . enqueue ( new TextEncoder ( ) . encode ( chunk ) )
228226 index += chunkSize
229-
227+
230228 // Add a small delay to simulate streaming
231229 setTimeout ( pushNext , 25 )
232230 } else {
233231 controller . close ( )
234232 }
235233 }
236-
234+
237235 pushNext ( )
238- }
236+ } ,
239237 } )
240-
238+
241239 // Store citations for later use in the main streaming handler
240+
242241 ; ( streamResponse as any ) . _citations = responseCitations
243-
242+
244243 return streamResponse
245244 }
246245
@@ -252,7 +251,9 @@ MAKE SURE YOU FULLY ANSWER THE USER'S QUESTION.
252251 return 'Sorry, I could not generate a response.'
253252 } catch ( error ) {
254253 logger . error ( 'Failed to generate chat response:' , error )
255- throw new Error ( `Failed to generate response: ${ error instanceof Error ? error . message : 'Unknown error' } ` )
254+ throw new Error (
255+ `Failed to generate response: ${ error instanceof Error ? error . message : 'Unknown error' } `
256+ )
256257 }
257258}
258259
@@ -268,7 +269,7 @@ export async function POST(req: NextRequest) {
268269 const { message, chatId, workflowId, createNewChat, stream } = CopilotChatSchema . parse ( body )
269270
270271 const session = await getSession ( )
271-
272+
272273 logger . info ( `[${ requestId } ] Copilot chat message: "${ message } "` , {
273274 chatId,
274275 workflowId,
@@ -285,12 +286,7 @@ export async function POST(req: NextRequest) {
285286 const [ existingChat ] = await db
286287 . select ( )
287288 . from ( copilotChats )
288- . where (
289- and (
290- eq ( copilotChats . id , chatId ) ,
291- eq ( copilotChats . userId , session . user . id )
292- )
293- )
289+ . where ( and ( eq ( copilotChats . id , chatId ) , eq ( copilotChats . userId , session . user . id ) ) )
294290 . limit ( 1 )
295291
296292 if ( existingChat ) {
@@ -326,11 +322,11 @@ export async function POST(req: NextRequest) {
326322 const encoder = new TextEncoder ( )
327323 // Extract citations from the stream object if available
328324 const citations = ( response as any ) . _citations || [ ]
329-
330- return new Response (
331- new ReadableStream ( {
332- async start ( controller ) {
333- const reader = response . getReader ( )
325+
326+ return new Response (
327+ new ReadableStream ( {
328+ async start ( controller ) {
329+ const reader = response . getReader ( )
334330 let accumulatedResponse = ''
335331
336332 // Send initial metadata
@@ -352,7 +348,7 @@ export async function POST(req: NextRequest) {
352348
353349 const chunkText = new TextDecoder ( ) . decode ( value )
354350 accumulatedResponse += chunkText
355-
351+
356352 const contentChunk = {
357353 type : 'content' ,
358354 content : chunkText ,
@@ -430,14 +426,22 @@ export async function POST(req: NextRequest) {
430426 }
431427
432428 // Extract citations from response if available
433- const citations = typeof response === 'object' && 'citations' in response ? response . citations :
434- typeof response === 'object' && 'toolResults' in response ? extractCitationsFromResponse ( response ) : [ ]
429+ const citations =
430+ typeof response === 'object' && 'citations' in response
431+ ? response . citations
432+ : typeof response === 'object' && 'toolResults' in response
433+ ? extractCitationsFromResponse ( response )
434+ : [ ]
435435
436436 const assistantMessage = {
437437 id : crypto . randomUUID ( ) ,
438438 role : 'assistant' ,
439- content : typeof response === 'string' ? response :
440- 'content' in response ? response . content : '[Error generating response]' ,
439+ content :
440+ typeof response === 'string'
441+ ? response
442+ : 'content' in response
443+ ? response . content
444+ : '[Error generating response]' ,
441445 timestamp : new Date ( ) . toISOString ( ) ,
442446 citations : citations . length > 0 ? citations : undefined ,
443447 }
@@ -466,8 +470,12 @@ export async function POST(req: NextRequest) {
466470
467471 return NextResponse . json ( {
468472 success : true ,
469- response : typeof response === 'string' ? response :
470- 'content' in response ? response . content : '[Error generating response]' ,
473+ response :
474+ typeof response === 'string'
475+ ? response
476+ : 'content' in response
477+ ? response . content
478+ : '[Error generating response]' ,
471479 chatId : currentChat ?. id ,
472480 metadata : {
473481 requestId,
@@ -485,4 +493,4 @@ export async function POST(req: NextRequest) {
485493 logger . error ( `[${ requestId } ] Copilot chat error:` , error )
486494 return NextResponse . json ( { error : 'Internal server error' } , { status : 500 } )
487495 }
488- }
496+ }
0 commit comments