Skip to content

Commit 6a66466

Browse files
Sg312icecrasher321
andauthored
fix(copilot): deprecate yaml, json import/export, deprecate build_workflow tool, convert copilot to json-based (#1488)
* Temp commit * Edit workflow self contained * Remove build_workflow * Base bad version * fix lint * Sanitize workflows for copilot * Fixes * Fix import/export buttons * fix autolayout * fix lint * fix training logic to work with json * Add claude sonnet 4.5 to copilot * Lint * Update copilot url * Update default model and fix build errors * Fix tests --------- Co-authored-by: Vikhyath Mondreti <[email protected]>
1 parent 3334429 commit 6a66466

File tree

63 files changed

+2894
-3160
lines changed

Some content is hidden

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

63 files changed

+2894
-3160
lines changed

apps/docs/content/docs/en/yaml/blocks/loop.mdx

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ type: object
1010
required:
1111
- type
1212
- name
13-
- inputs
1413
- connections
1514
properties:
1615
type:
@@ -22,21 +21,23 @@ properties:
2221
description: Display name for this loop block
2322
inputs:
2423
type: object
25-
required:
26-
- loopType
24+
description: Optional. If omitted, defaults will be applied.
2725
properties:
2826
loopType:
2927
type: string
3028
enum: [for, forEach]
3129
description: Type of loop to execute
30+
default: for
3231
iterations:
3332
type: number
3433
description: Number of iterations (for 'for' loops)
34+
default: 5
3535
minimum: 1
3636
maximum: 1000
3737
collection:
3838
type: string
3939
description: Collection to iterate over (for 'forEach' loops)
40+
default: ""
4041
maxConcurrency:
4142
type: number
4243
description: Maximum concurrent executions
@@ -45,40 +46,48 @@ properties:
4546
maximum: 10
4647
connections:
4748
type: object
48-
required:
49-
- loop
5049
properties:
50+
# Nested format (recommended)
5151
loop:
5252
type: object
53-
required:
54-
- start
5553
properties:
5654
start:
5755
type: string
5856
description: Target block ID to execute inside the loop
5957
end:
6058
type: string
6159
description: Target block ID for loop completion (optional)
60+
# Direct handle format (alternative)
61+
loop-start-source:
62+
type: string | string[]
63+
description: Target block ID to execute inside the loop (direct format)
64+
loop-end-source:
65+
type: string | string[]
66+
description: Target block ID for loop completion (direct format, optional)
6267
error:
6368
type: string
6469
description: Target block ID for error handling
70+
note: Use either the nested 'loop' format OR the direct 'loop-start-source' format, not both
6571
```
6672
6773
## Connection Configuration
6874
69-
Loop blocks use a special connection format with a `loop` section:
75+
Loop blocks support two connection formats:
76+
77+
### Direct Handle Format (Alternative)
7078
7179
```yaml
7280
connections:
73-
loop:
74-
start: <string> # Target block ID to execute inside the loop
75-
end: <string> # Target block ID after loop completion (optional)
81+
loop-start-source: <string> # Target block ID to execute inside the loop
82+
loop-end-source: <string> # Target block ID after loop completion (optional)
7683
error: <string> # Target block ID for error handling (optional)
7784
```
7885
86+
Both formats work identically. Use whichever you prefer.
87+
7988
## Child Block Configuration
8089
81-
Blocks inside a loop must have their `parentId` set to the loop block ID:
90+
Blocks inside a loop must have their `parentId` set to the loop block ID. The `extent` property is automatically set to `'parent'` and doesn't need to be specified:
8291

8392
```yaml
8493
loop-1:
@@ -261,6 +270,59 @@ process-task:
261270
success: task-completed
262271
```
263272
273+
### Direct Handle Format Example
274+
275+
The same loop can be written using the direct handle format:
276+
277+
```yaml
278+
my-loop:
279+
type: loop
280+
name: "Process Items"
281+
inputs:
282+
loopType: forEach
283+
collection: <start.items>
284+
connections:
285+
loop-start-source: process-item # Direct handle format
286+
loop-end-source: final-results # Direct handle format
287+
error: handle-error
288+
289+
process-item:
290+
type: agent
291+
name: "Process Item"
292+
parentId: my-loop
293+
inputs:
294+
systemPrompt: "Process this item"
295+
userPrompt: <loop.currentItem>
296+
model: gpt-4o
297+
apiKey: '{{OPENAI_API_KEY}}'
298+
```
299+
300+
### Minimal Loop Example (Using Defaults)
301+
302+
You can omit the `inputs` section entirely, and defaults will be applied:
303+
304+
```yaml
305+
simple-loop:
306+
type: loop
307+
name: "Simple Loop"
308+
# No inputs section - defaults to loopType: 'for', iterations: 5
309+
connections:
310+
loop-start-source: process-step
311+
loop-end-source: complete
312+
313+
process-step:
314+
type: agent
315+
name: "Process Step"
316+
parentId: simple-loop
317+
inputs:
318+
systemPrompt: "Execute step"
319+
userPrompt: "Step <loop.index>"
320+
model: gpt-4o
321+
apiKey: '{{OPENAI_API_KEY}}'
322+
```
323+
324+
This loop will execute 5 iterations by default.
325+
264326
## Loop Variables
265327

266328
Inside loop child blocks, these special variables are available:

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ describe('Copilot Chat API Route', () => {
230230
userId: 'user-123',
231231
stream: true,
232232
streamToolCalls: true,
233-
model: 'gpt-5',
233+
model: 'claude-4.5-sonnet',
234234
mode: 'agent',
235235
messageId: 'mock-uuid-1234-5678',
236236
version: '1.0.0',
@@ -300,7 +300,7 @@ describe('Copilot Chat API Route', () => {
300300
userId: 'user-123',
301301
stream: true,
302302
streamToolCalls: true,
303-
model: 'gpt-5',
303+
model: 'claude-4.5-sonnet',
304304
mode: 'agent',
305305
messageId: 'mock-uuid-1234-5678',
306306
version: '1.0.0',
@@ -358,7 +358,7 @@ describe('Copilot Chat API Route', () => {
358358
userId: 'user-123',
359359
stream: true,
360360
streamToolCalls: true,
361-
model: 'gpt-5',
361+
model: 'claude-4.5-sonnet',
362362
mode: 'agent',
363363
messageId: 'mock-uuid-1234-5678',
364364
version: '1.0.0',
@@ -450,7 +450,7 @@ describe('Copilot Chat API Route', () => {
450450
userId: 'user-123',
451451
stream: true,
452452
streamToolCalls: true,
453-
model: 'gpt-5',
453+
model: 'claude-4.5-sonnet',
454454
mode: 'ask',
455455
messageId: 'mock-uuid-1234-5678',
456456
version: '1.0.0',

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ const ChatMessageSchema = z.object({
4848
'gpt-4.1',
4949
'o3',
5050
'claude-4-sonnet',
51+
'claude-4.5-sonnet',
5152
'claude-4.1-opus',
5253
])
5354
.optional()
54-
.default('gpt-5'),
55+
.default('claude-4.5-sonnet'),
5556
mode: z.enum(['ask', 'agent']).optional().default('agent'),
5657
prefetch: z.boolean().optional(),
5758
createNewChat: z.boolean().optional().default(false),

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,9 @@ export async function POST(request: NextRequest) {
5151

5252
logger.info('Sending training data to agent indexer', {
5353
title,
54-
operationsCount: operations.length,
54+
operationsCount: Array.isArray(operations) ? operations.length : 0,
5555
})
5656

57-
const wrappedOperations = {
58-
operations: operations,
59-
}
60-
6157
// Forward to agent indexer
6258
const upstreamUrl = `${baseUrl}/operations/add`
6359
const upstreamResponse = await fetch(upstreamUrl, {
@@ -71,7 +67,7 @@ export async function POST(request: NextRequest) {
7167
prompt,
7268
input,
7369
output,
74-
operations: wrappedOperations,
70+
operations: { operations },
7571
}),
7672
})
7773

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

Lines changed: 17 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,9 @@ import { z } from 'zod'
66
import { getSession } from '@/lib/auth'
77
import { createLogger } from '@/lib/logs/console/logger'
88
import { getUserEntityPermissions } from '@/lib/permissions/utils'
9-
import { simAgentClient } from '@/lib/sim-agent/client'
109
import { generateRequestId } from '@/lib/utils'
10+
import { applyAutoLayout } from '@/lib/workflows/autolayout'
1111
import { loadWorkflowFromNormalizedTables } from '@/lib/workflows/db-helpers'
12-
import { getAllBlocks } from '@/blocks/registry'
13-
import type { BlockConfig } from '@/blocks/types'
14-
import { resolveOutputType } from '@/blocks/utils'
15-
import { generateLoopBlocks, generateParallelBlocks } from '@/stores/workflows/workflow/utils'
1612

1713
export const dynamic = 'force-dynamic'
1814

@@ -120,123 +116,46 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
120116
return NextResponse.json({ error: 'Could not load workflow data' }, { status: 500 })
121117
}
122118

123-
// Create workflow state for autolayout
124-
const workflowState = {
125-
blocks: currentWorkflowData.blocks,
126-
edges: currentWorkflowData.edges,
127-
loops: currentWorkflowData.loops || {},
128-
parallels: currentWorkflowData.parallels || {},
129-
}
130-
131119
const autoLayoutOptions = {
132-
strategy: layoutOptions.strategy,
133-
direction: layoutOptions.direction,
134-
spacing: {
135-
horizontal: layoutOptions.spacing?.horizontal || 500,
136-
vertical: layoutOptions.spacing?.vertical || 400,
137-
layer: layoutOptions.spacing?.layer || 700,
138-
},
139-
alignment: layoutOptions.alignment,
120+
horizontalSpacing: layoutOptions.spacing?.horizontal || 550,
121+
verticalSpacing: layoutOptions.spacing?.vertical || 200,
140122
padding: {
141-
x: layoutOptions.padding?.x || 250,
142-
y: layoutOptions.padding?.y || 250,
123+
x: layoutOptions.padding?.x || 150,
124+
y: layoutOptions.padding?.y || 150,
143125
},
126+
alignment: layoutOptions.alignment,
144127
}
145128

146-
// Gather block registry and utilities for sim-agent
147-
const blocks = getAllBlocks()
148-
const blockRegistry = blocks.reduce(
149-
(acc, block) => {
150-
const blockType = block.type
151-
acc[blockType] = {
152-
...block,
153-
id: blockType,
154-
subBlocks: block.subBlocks || [],
155-
outputs: block.outputs || {},
156-
} as any
157-
return acc
158-
},
159-
{} as Record<string, BlockConfig>
129+
const layoutResult = applyAutoLayout(
130+
currentWorkflowData.blocks,
131+
currentWorkflowData.edges,
132+
currentWorkflowData.loops || {},
133+
currentWorkflowData.parallels || {},
134+
autoLayoutOptions
160135
)
161136

162-
const autoLayoutResult = await simAgentClient.makeRequest('/api/yaml/autolayout', {
163-
body: {
164-
workflowState,
165-
options: autoLayoutOptions,
166-
blockRegistry,
167-
utilities: {
168-
generateLoopBlocks: generateLoopBlocks.toString(),
169-
generateParallelBlocks: generateParallelBlocks.toString(),
170-
resolveOutputType: resolveOutputType.toString(),
171-
},
172-
},
173-
})
174-
175-
// Log the full response for debugging
176-
logger.info(`[${requestId}] Sim-agent autolayout response:`, {
177-
success: autoLayoutResult.success,
178-
status: autoLayoutResult.status,
179-
error: autoLayoutResult.error,
180-
hasData: !!autoLayoutResult.data,
181-
hasWorkflowState: !!autoLayoutResult.data?.workflowState,
182-
hasBlocks: !!autoLayoutResult.data?.blocks,
183-
dataKeys: autoLayoutResult.data ? Object.keys(autoLayoutResult.data) : [],
184-
})
185-
186-
if (
187-
!autoLayoutResult.success ||
188-
(!autoLayoutResult.data?.workflowState && !autoLayoutResult.data?.blocks)
189-
) {
137+
if (!layoutResult.success || !layoutResult.blocks) {
190138
logger.error(`[${requestId}] Auto layout failed:`, {
191-
success: autoLayoutResult.success,
192-
error: autoLayoutResult.error,
193-
status: autoLayoutResult.status,
194-
fullResponse: autoLayoutResult,
195-
})
196-
const errorMessage =
197-
autoLayoutResult.error ||
198-
(autoLayoutResult.status === 401
199-
? 'Unauthorized - check API key'
200-
: autoLayoutResult.status === 404
201-
? 'Sim-agent service not found'
202-
: `HTTP ${autoLayoutResult.status}`)
203-
204-
return NextResponse.json(
205-
{
206-
error: 'Auto layout failed',
207-
details: errorMessage,
208-
},
209-
{ status: 500 }
210-
)
211-
}
212-
213-
// Handle both response formats from sim-agent
214-
const layoutedBlocks =
215-
autoLayoutResult.data?.workflowState?.blocks || autoLayoutResult.data?.blocks
216-
217-
if (!layoutedBlocks) {
218-
logger.error(`[${requestId}] No blocks returned from sim-agent:`, {
219-
responseData: autoLayoutResult.data,
139+
error: layoutResult.error,
220140
})
221141
return NextResponse.json(
222142
{
223143
error: 'Auto layout failed',
224-
details: 'No blocks returned from sim-agent',
144+
details: layoutResult.error || 'Unknown error',
225145
},
226146
{ status: 500 }
227147
)
228148
}
229149

230150
const elapsed = Date.now() - startTime
231-
const blockCount = Object.keys(layoutedBlocks).length
151+
const blockCount = Object.keys(layoutResult.blocks).length
232152

233153
logger.info(`[${requestId}] Autolayout completed successfully in ${elapsed}ms`, {
234154
blockCount,
235155
strategy: layoutOptions.strategy,
236156
workflowId,
237157
})
238158

239-
// Return the layouted blocks to the frontend - let the store handle saving
240159
return NextResponse.json({
241160
success: true,
242161
message: `Autolayout applied successfully to ${blockCount} blocks`,
@@ -245,7 +164,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
245164
direction: layoutOptions.direction,
246165
blockCount,
247166
elapsed: `${elapsed}ms`,
248-
layoutedBlocks: layoutedBlocks,
167+
layoutedBlocks: layoutResult.blocks,
249168
},
250169
})
251170
} catch (error) {

0 commit comments

Comments
 (0)