Skip to content

Commit 0c7a8ef

Browse files
Sg312waleedlatif1icecrasher321greptile-apps[bot]aadamgough
authored
feat(copilot): add depths (#974)
* Checkpont * can edit names and types * Add reasoning and thinking * Update agent max * Max mode v1 * Add best practices * Todo list shows up * Todolist works * Updates to todo * Updates * Updates * Checkpoitn * Yaml export updates * Updates * Checkpoint fr * Fix diff veiw on new workflow * Subflow autolayout fix v1 * Autolayout fixes 2 * Gdrive list files * Get oauth credential (email) * Gdrive file picker * Gdrive file access prompt * Api request * Copilot ui for some tool calls * Updates * Fix overflow * Openai * Streaming * Checkpoint * Update * Openai responses api * Depth skeleton * Depth tooltips * Mode selector tool tips * Update ui * Update ordering * Lint * Remove migrations * Add migrations back * Lint * Fix isdev * Fix tests * Comments --------- Co-authored-by: Waleed Latif <walif6@gmail.com> Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai> Co-authored-by: Adam Gough <77861281+aadamgough@users.noreply.github.com> Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net>
1 parent f081f5a commit 0c7a8ef

47 files changed

Lines changed: 9013 additions & 351 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ describe('Copilot Chat API Route', () => {
223223
stream: true,
224224
streamToolCalls: true,
225225
mode: 'agent',
226+
provider: 'openai',
227+
depth: 0,
226228
}),
227229
})
228230
)
@@ -284,6 +286,8 @@ describe('Copilot Chat API Route', () => {
284286
stream: true,
285287
streamToolCalls: true,
286288
mode: 'agent',
289+
provider: 'openai',
290+
depth: 0,
287291
}),
288292
})
289293
)
@@ -337,6 +341,8 @@ describe('Copilot Chat API Route', () => {
337341
stream: true,
338342
streamToolCalls: true,
339343
mode: 'agent',
344+
provider: 'openai',
345+
depth: 0,
340346
}),
341347
})
342348
)
@@ -430,6 +436,8 @@ describe('Copilot Chat API Route', () => {
430436
stream: true,
431437
streamToolCalls: true,
432438
mode: 'ask',
439+
provider: 'openai',
440+
depth: 0,
433441
}),
434442
})
435443
)

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

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,13 @@ const ChatMessageSchema = z.object({
3939
chatId: z.string().optional(),
4040
workflowId: z.string().min(1, 'Workflow ID is required'),
4141
mode: z.enum(['ask', 'agent']).optional().default('agent'),
42+
depth: z.number().int().min(0).max(3).optional().default(0),
4243
createNewChat: z.boolean().optional().default(false),
4344
stream: z.boolean().optional().default(true),
4445
implicitFeedback: z.string().optional(),
4546
fileAttachments: z.array(FileAttachmentSchema).optional(),
47+
provider: z.string().optional().default('openai'),
48+
conversationId: z.string().optional(),
4649
})
4750

4851
// Sim Agent API configuration
@@ -156,10 +159,13 @@ export async function POST(req: NextRequest) {
156159
chatId,
157160
workflowId,
158161
mode,
162+
depth,
159163
createNewChat,
160164
stream,
161165
implicitFeedback,
162166
fileAttachments,
167+
provider,
168+
conversationId,
163169
} = ChatMessageSchema.parse(body)
164170

165171
logger.info(`[${tracker.requestId}] Processing copilot chat request`, {
@@ -171,6 +177,8 @@ export async function POST(req: NextRequest) {
171177
createNewChat,
172178
messageLength: message.length,
173179
hasImplicitFeedback: !!implicitFeedback,
180+
provider: provider || 'openai',
181+
hasConversationId: !!conversationId,
174182
})
175183

176184
// Handle chat context
@@ -252,7 +260,7 @@ export async function POST(req: NextRequest) {
252260
}
253261

254262
// Build messages array for sim agent with conversation history
255-
const messages = []
263+
const messages: any[] = []
256264

257265
// Add conversation history (need to rebuild these with file support if they had attachments)
258266
for (const msg of conversationHistory) {
@@ -327,16 +335,13 @@ export async function POST(req: NextRequest) {
327335
})
328336
}
329337

330-
// Start title generation in parallel if this is a new chat with first message
331-
if (actualChatId && !currentChat?.title && conversationHistory.length === 0) {
332-
logger.info(`[${tracker.requestId}] Will start parallel title generation inside stream`)
333-
}
338+
// Determine provider and conversationId to use for this request
339+
const providerToUse = provider || 'openai'
340+
const effectiveConversationId =
341+
(currentChat?.conversationId as string | undefined) || conversationId
334342

335-
// Forward to sim agent API
336-
logger.info(`[${tracker.requestId}] Sending request to sim agent API`, {
337-
messageCount: messages.length,
338-
endpoint: `${SIM_AGENT_API_URL}/api/chat-completion-streaming`,
339-
})
343+
// If we have a conversationId, only send the most recent user message; else send full history
344+
const messagesForAgent = effectiveConversationId ? [messages[messages.length - 1]] : messages
340345

341346
const simAgentResponse = await fetch(`${SIM_AGENT_API_URL}/api/chat-completion-streaming`, {
342347
method: 'POST',
@@ -345,12 +350,15 @@ export async function POST(req: NextRequest) {
345350
...(SIM_AGENT_API_KEY && { 'x-api-key': SIM_AGENT_API_KEY }),
346351
},
347352
body: JSON.stringify({
348-
messages,
353+
messages: messagesForAgent,
349354
workflowId,
350355
userId: authenticatedUserId,
351356
stream: stream,
352357
streamToolCalls: true,
353358
mode: mode,
359+
provider: providerToUse,
360+
...(effectiveConversationId ? { conversationId: effectiveConversationId } : {}),
361+
...(typeof depth === 'number' ? { depth } : {}),
354362
...(session?.user?.name && { userName: session.user.name }),
355363
}),
356364
})
@@ -388,6 +396,8 @@ export async function POST(req: NextRequest) {
388396
const toolCalls: any[] = []
389397
let buffer = ''
390398
let isFirstDone = true
399+
let responseIdFromStart: string | undefined
400+
let responseIdFromDone: string | undefined
391401

392402
// Send chatId as first event
393403
if (actualChatId) {
@@ -486,6 +496,13 @@ export async function POST(req: NextRequest) {
486496
}
487497
break
488498

499+
case 'reasoning':
500+
// Treat like thinking: do not add to assistantContent to avoid leaking
501+
logger.debug(
502+
`[${tracker.requestId}] Reasoning chunk received (${(event.data || event.content || '').length} chars)`
503+
)
504+
break
505+
489506
case 'tool_call':
490507
logger.info(
491508
`[${tracker.requestId}] Tool call ${event.data?.partial ? '(partial)' : '(complete)'}:`,
@@ -528,7 +545,22 @@ export async function POST(req: NextRequest) {
528545
})
529546
break
530547

548+
case 'start':
549+
if (event.data?.responseId) {
550+
responseIdFromStart = event.data.responseId
551+
logger.info(
552+
`[${tracker.requestId}] Received start event with responseId: ${responseIdFromStart}`
553+
)
554+
}
555+
break
556+
531557
case 'done':
558+
if (event.data?.responseId) {
559+
responseIdFromDone = event.data.responseId
560+
logger.info(
561+
`[${tracker.requestId}] Received done event with responseId: ${responseIdFromDone}`
562+
)
563+
}
532564
if (isFirstDone) {
533565
logger.info(
534566
`[${tracker.requestId}] Initial AI response complete, tool count: ${toolCalls.length}`
@@ -622,19 +654,23 @@ export async function POST(req: NextRequest) {
622654
)
623655
}
624656

657+
const responseId = responseIdFromDone || responseIdFromStart
658+
625659
// Update chat in database immediately (without title)
626660
await db
627661
.update(copilotChats)
628662
.set({
629663
messages: updatedMessages,
630664
updatedAt: new Date(),
665+
...(responseId ? { conversationId: responseId } : {}),
631666
})
632667
.where(eq(copilotChats.id, actualChatId!))
633668

634669
logger.info(`[${tracker.requestId}] Updated chat ${actualChatId} with new messages`, {
635670
messageCount: updatedMessages.length,
636671
savedUserMessage: true,
637672
savedAssistantMessage: assistantContent.trim().length > 0,
673+
updatedConversationId: responseId || null,
638674
})
639675
}
640676
} catch (error) {

apps/sim/app/api/copilot/chat/update-messages/route.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,6 @@ export async function POST(req: NextRequest) {
5151
const body = await req.json()
5252
const { chatId, messages } = UpdateMessagesSchema.parse(body)
5353

54-
logger.info(`[${tracker.requestId}] Updating chat messages`, {
55-
userId,
56-
chatId,
57-
messageCount: messages.length,
58-
})
59-
6054
// Verify that the chat belongs to the user
6155
const [chat] = await db
6256
.select()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ async function updateToolCallStatus(
3838

3939
try {
4040
const key = `tool_call:${toolCallId}`
41-
const timeout = 60000 // 1 minute timeout
41+
const timeout = 600000 // 10 minutes timeout for user confirmation
4242
const pollInterval = 100 // Poll every 100ms
4343
const startTime = Date.now()
4444

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ async function pollRedisForTool(
6565
}
6666

6767
const key = `tool_call:${toolCallId}`
68-
const timeout = 300000 // 5 minutes
68+
const timeout = 600000 // 10 minutes for long-running operations
6969
const pollInterval = 1000 // 1 second
7070
const startTime = Date.now()
7171

apps/sim/app/api/workflows/[id]/yaml/route.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
365365
position: { x: number; y: number }
366366
subBlocks?: Record<string, any>
367367
data?: Record<string, any>
368+
parentId?: string
369+
extent?: string
368370
}>
369371
const edges = workflowState.edges
370372
const warnings = conversionResult.warnings || []
@@ -395,6 +397,13 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
395397

396398
if (!blockConfig && (block.type === 'loop' || block.type === 'parallel')) {
397399
// Handle loop/parallel blocks (they don't have regular block configs)
400+
// Preserve parentId if it exists (though loop/parallel shouldn't have parents)
401+
const containerData = block.data || {}
402+
if (block.parentId) {
403+
containerData.parentId = block.parentId
404+
containerData.extent = block.extent || 'parent'
405+
}
406+
398407
newWorkflowState.blocks[newId] = {
399408
id: newId,
400409
type: block.type,
@@ -407,7 +416,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
407416
isWide: false,
408417
advancedMode: false,
409418
height: 0,
410-
data: block.data || {},
419+
data: containerData,
411420
}
412421
logger.debug(`[${requestId}] Processed loop/parallel block: ${block.id} -> ${newId}`)
413422
} else if (blockConfig) {
@@ -440,6 +449,13 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
440449
// Set up outputs from block configuration
441450
const outputs = resolveOutputType(blockConfig.outputs)
442451

452+
// Preserve parentId if it exists in the imported block
453+
const blockData = block.data || {}
454+
if (block.parentId) {
455+
blockData.parentId = block.parentId
456+
blockData.extent = block.extent || 'parent'
457+
}
458+
443459
newWorkflowState.blocks[newId] = {
444460
id: newId,
445461
type: block.type,
@@ -452,7 +468,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
452468
isWide: false,
453469
advancedMode: false,
454470
height: 0,
455-
data: block.data || {},
471+
data: blockData,
456472
}
457473

458474
logger.debug(`[${requestId}] Processed regular block: ${block.id} -> ${newId}`)
@@ -529,6 +545,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
529545
}
530546
}
531547

548+
// Debug: Log block parent-child relationships before generating loops
532549
// Generate loop and parallel configurations
533550
const loops = generateLoopBlocks(newWorkflowState.blocks)
534551
const parallels = generateParallelBlocks(newWorkflowState.blocks)

0 commit comments

Comments
 (0)