11import { db } from '@sim/db'
22import { copilotChats } from '@sim/db/schema'
33import { createLogger } from '@sim/logger'
4- import { and , desc , eq } from 'drizzle-orm'
4+ import { and , desc , eq , sql } from 'drizzle-orm'
55import { type NextRequest , NextResponse } from 'next/server'
66import { z } from 'zod'
77import { getSession } from '@/lib/auth'
@@ -15,6 +15,7 @@ import {
1515import { COPILOT_REQUEST_MODES } from '@/lib/copilot/models'
1616import { orchestrateCopilotStream } from '@/lib/copilot/orchestrator'
1717import { getStreamMeta , readStreamEvents } from '@/lib/copilot/orchestrator/stream/buffer'
18+ import type { OrchestratorResult } from '@/lib/copilot/orchestrator/types'
1819import {
1920 authenticateCopilotRequestSessionOnly ,
2021 createBadRequestResponse ,
@@ -285,6 +286,35 @@ export async function POST(req: NextRequest) {
285286 } )
286287 } catch { }
287288
289+ if ( actualChatId ) {
290+ const userMsg = {
291+ id : userMessageIdToUse ,
292+ role : 'user' as const ,
293+ content : message ,
294+ timestamp : new Date ( ) . toISOString ( ) ,
295+ ...( fileAttachments && fileAttachments . length > 0 && { fileAttachments } ) ,
296+ ...( Array . isArray ( normalizedContexts ) &&
297+ normalizedContexts . length > 0 && {
298+ contexts : normalizedContexts ,
299+ } ) ,
300+ }
301+
302+ const [ updated ] = await db
303+ . update ( copilotChats )
304+ . set ( {
305+ messages : sql `${ copilotChats . messages } || ${ JSON . stringify ( [ userMsg ] ) } ::jsonb` ,
306+ conversationId : userMessageIdToUse ,
307+ updatedAt : new Date ( ) ,
308+ } )
309+ . where ( eq ( copilotChats . id , actualChatId ) )
310+ . returning ( { messages : copilotChats . messages } )
311+
312+ if ( updated ) {
313+ const freshMessages : any [ ] = Array . isArray ( updated . messages ) ? updated . messages : [ ]
314+ conversationHistory = freshMessages . filter ( ( m : any ) => m . id !== userMessageIdToUse )
315+ }
316+ }
317+
288318 if ( stream ) {
289319 const sseStream = createSSEStream ( {
290320 requestPayload,
@@ -297,6 +327,7 @@ export async function POST(req: NextRequest) {
297327 titleModel : selectedModel ,
298328 titleProvider : provider ,
299329 requestId : tracker . requestId ,
330+ workspaceId : resolvedWorkspaceId ,
300331 orchestrateOptions : {
301332 userId : authenticatedUserId ,
302333 workflowId,
@@ -305,6 +336,72 @@ export async function POST(req: NextRequest) {
305336 autoExecuteTools : true ,
306337 interactive : true ,
307338 promptForToolApproval : true ,
339+ onComplete : async ( result : OrchestratorResult ) => {
340+ if ( ! actualChatId ) return
341+
342+ const assistantMessage : Record < string , unknown > = {
343+ id : crypto . randomUUID ( ) ,
344+ role : 'assistant' as const ,
345+ content : result . content ,
346+ timestamp : new Date ( ) . toISOString ( ) ,
347+ ...( result . requestId ? { requestId : result . requestId } : { } ) ,
348+ }
349+ if ( result . toolCalls . length > 0 ) {
350+ assistantMessage . toolCalls = result . toolCalls
351+ }
352+ if ( result . contentBlocks . length > 0 ) {
353+ assistantMessage . contentBlocks = result . contentBlocks . map ( ( block ) => {
354+ const stored : Record < string , unknown > = { type : block . type }
355+ if ( block . content ) stored . content = block . content
356+ if ( block . type === 'tool_call' && block . toolCall ) {
357+ stored . toolCall = {
358+ id : block . toolCall . id ,
359+ name : block . toolCall . name ,
360+ state :
361+ block . toolCall . result ?. success !== undefined
362+ ? block . toolCall . result . success
363+ ? 'success'
364+ : 'error'
365+ : block . toolCall . status ,
366+ result : block . toolCall . result ,
367+ ...( block . calledBy ? { calledBy : block . calledBy } : { } ) ,
368+ }
369+ }
370+ return stored
371+ } )
372+ }
373+
374+ try {
375+ const [ row ] = await db
376+ . select ( { messages : copilotChats . messages } )
377+ . from ( copilotChats )
378+ . where ( eq ( copilotChats . id , actualChatId ) )
379+ . limit ( 1 )
380+
381+ const msgs : any [ ] = Array . isArray ( row ?. messages ) ? row . messages : [ ]
382+ const userIdx = msgs . findIndex ( ( m : any ) => m . id === userMessageIdToUse )
383+ const alreadyHasResponse =
384+ userIdx >= 0 &&
385+ userIdx + 1 < msgs . length &&
386+ ( msgs [ userIdx + 1 ] as any ) ?. role === 'assistant'
387+
388+ if ( ! alreadyHasResponse ) {
389+ await db
390+ . update ( copilotChats )
391+ . set ( {
392+ messages : sql `${ copilotChats . messages } || ${ JSON . stringify ( [ assistantMessage ] ) } ::jsonb` ,
393+ conversationId : sql `CASE WHEN ${ copilotChats . conversationId } = ${ userMessageIdToUse } THEN NULL ELSE ${ copilotChats . conversationId } END` ,
394+ updatedAt : new Date ( ) ,
395+ } )
396+ . where ( eq ( copilotChats . id , actualChatId ) )
397+ }
398+ } catch ( error ) {
399+ logger . error ( `[${ tracker . requestId } ] Failed to persist chat messages` , {
400+ chatId : actualChatId ,
401+ error : error instanceof Error ? error . message : 'Unknown error' ,
402+ } )
403+ }
404+ } ,
308405 } ,
309406 } )
310407
0 commit comments