Skip to content

Commit 48b32a3

Browse files
improvement(copilot): add subblock enums to block metadata (#870)
* Add subblock enums to metadata * Update apps/sim/lib/copilot/tools/server-tools/blocks/get-blocks-metadata.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
1 parent 6ab9fa7 commit 48b32a3

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

apps/sim/lib/copilot/tools/server-tools/blocks/get-blocks-metadata.ts

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,93 @@ class GetBlocksMetadataTool extends BaseCopilotTool<GetBlocksMetadataParams, Blo
2929
// Export the tool instance
3030
export const getBlocksMetadataTool = new GetBlocksMetadataTool()
3131

32+
/**
33+
* Safely resolve subblock options, handling both static arrays and functions
34+
*/
35+
function resolveSubBlockOptions(options: any): any[] {
36+
try {
37+
if (typeof options === 'function') {
38+
const resolved = options()
39+
return Array.isArray(resolved) ? resolved : []
40+
}
41+
return Array.isArray(options) ? options : []
42+
} catch (error) {
43+
logger.warn('Failed to resolve subblock options:', error)
44+
return []
45+
}
46+
}
47+
48+
/**
49+
* Process subBlocks configuration to include all UI metadata
50+
*/
51+
function processSubBlocks(subBlocks: any[]): any[] {
52+
if (!Array.isArray(subBlocks)) {
53+
return []
54+
}
55+
56+
return subBlocks.map((subBlock) => {
57+
const processedSubBlock: any = {
58+
id: subBlock.id,
59+
title: subBlock.title,
60+
type: subBlock.type,
61+
layout: subBlock.layout,
62+
mode: subBlock.mode,
63+
required: subBlock.required,
64+
placeholder: subBlock.placeholder,
65+
description: subBlock.description,
66+
hidden: subBlock.hidden,
67+
condition: subBlock.condition,
68+
// Slider specific
69+
min: subBlock.min,
70+
max: subBlock.max,
71+
step: subBlock.step,
72+
integer: subBlock.integer,
73+
// Input specific
74+
rows: subBlock.rows,
75+
password: subBlock.password,
76+
multiSelect: subBlock.multiSelect,
77+
// Code specific
78+
language: subBlock.language,
79+
generationType: subBlock.generationType,
80+
// OAuth specific
81+
provider: subBlock.provider,
82+
serviceId: subBlock.serviceId,
83+
requiredScopes: subBlock.requiredScopes,
84+
// File specific
85+
mimeType: subBlock.mimeType,
86+
acceptedTypes: subBlock.acceptedTypes,
87+
multiple: subBlock.multiple,
88+
maxSize: subBlock.maxSize,
89+
// Other properties
90+
connectionDroppable: subBlock.connectionDroppable,
91+
columns: subBlock.columns,
92+
value: typeof subBlock.value === 'function' ? 'function' : undefined, // Don't serialize functions
93+
wandConfig: subBlock.wandConfig,
94+
}
95+
96+
// Resolve options if present
97+
if (subBlock.options) {
98+
try {
99+
const resolvedOptions = resolveSubBlockOptions(subBlock.options)
100+
processedSubBlock.options = resolvedOptions.map((option) => ({
101+
label: option.label,
102+
id: option.id,
103+
// Note: Icons are React components, so we'll just indicate if they exist
104+
hasIcon: !!option.icon,
105+
}))
106+
} catch (error) {
107+
logger.warn(`Failed to resolve options for subBlock ${subBlock.id}:`, error)
108+
processedSubBlock.options = []
109+
}
110+
}
111+
112+
// Remove undefined properties to keep the response clean
113+
return Object.fromEntries(
114+
Object.entries(processedSubBlock).filter(([_, value]) => value !== undefined)
115+
)
116+
})
117+
}
118+
32119
// Implementation function
33120
export async function getBlocksMetadata(
34121
params: GetBlocksMetadataParams
@@ -80,9 +167,23 @@ export async function getBlocksMetadata(
80167
id: blockId,
81168
name: blockConfig.name || blockId,
82169
description: blockConfig.description || '',
170+
longDescription: blockConfig.longDescription,
171+
category: blockConfig.category,
172+
bgColor: blockConfig.bgColor,
83173
inputs: blockConfig.inputs || {},
84174
outputs: blockConfig.outputs || {},
85175
tools: blockConfig.tools?.access || [],
176+
hideFromToolbar: blockConfig.hideFromToolbar,
177+
}
178+
179+
// Process and include subBlocks configuration
180+
if (blockConfig.subBlocks && Array.isArray(blockConfig.subBlocks)) {
181+
logger.info(`Processing ${blockConfig.subBlocks.length} subBlocks for ${blockId}`)
182+
metadata.subBlocks = processSubBlocks(blockConfig.subBlocks)
183+
logger.info(`✓ Processed subBlocks for ${blockId}:`, metadata.subBlocks.length)
184+
} else {
185+
logger.info(`No subBlocks found for ${blockId}`)
186+
metadata.subBlocks = []
86187
}
87188
}
88189

@@ -146,6 +247,7 @@ export async function getBlocksMetadata(
146247

147248
logger.info(`Final metadata keys for ${blockId}:`, Object.keys(metadata))
148249
logger.info(`Has YAML documentation: ${!!metadata.yamlDocumentation}`)
250+
logger.info(`Has subBlocks: ${!!metadata.subBlocks && metadata.subBlocks.length > 0}`)
149251

150252
result[blockId] = metadata
151253
}
@@ -214,6 +316,43 @@ const SPECIAL_BLOCKS_METADATA: Record<string, any> = {
214316
totalIterations: 'number',
215317
},
216318
tools: { access: [] },
319+
subBlocks: [
320+
{
321+
id: 'loopType',
322+
title: 'Loop Type',
323+
type: 'dropdown',
324+
required: true,
325+
options: [
326+
{ label: 'For Loop (count)', id: 'for' },
327+
{ label: 'For Each (collection)', id: 'forEach' },
328+
],
329+
},
330+
{
331+
id: 'iterations',
332+
title: 'Iterations',
333+
type: 'slider',
334+
min: 1,
335+
max: 1000,
336+
integer: true,
337+
condition: { field: 'loopType', value: 'for' },
338+
},
339+
{
340+
id: 'collection',
341+
title: 'Collection',
342+
type: 'short-input',
343+
placeholder: 'Array or object to iterate over...',
344+
condition: { field: 'loopType', value: 'forEach' },
345+
},
346+
{
347+
id: 'maxConcurrency',
348+
title: 'Max Concurrency',
349+
type: 'slider',
350+
min: 1,
351+
max: 10,
352+
integer: true,
353+
default: 1,
354+
},
355+
],
217356
},
218357
parallel: {
219358
type: 'parallel',
@@ -232,5 +371,42 @@ const SPECIAL_BLOCKS_METADATA: Record<string, any> = {
232371
totalBranches: 'number',
233372
},
234373
tools: { access: [] },
374+
subBlocks: [
375+
{
376+
id: 'parallelType',
377+
title: 'Parallel Type',
378+
type: 'dropdown',
379+
required: true,
380+
options: [
381+
{ label: 'Count (number)', id: 'count' },
382+
{ label: 'Collection (array)', id: 'collection' },
383+
],
384+
},
385+
{
386+
id: 'count',
387+
title: 'Count',
388+
type: 'slider',
389+
min: 1,
390+
max: 100,
391+
integer: true,
392+
condition: { field: 'parallelType', value: 'count' },
393+
},
394+
{
395+
id: 'collection',
396+
title: 'Collection',
397+
type: 'short-input',
398+
placeholder: 'Array to process in parallel...',
399+
condition: { field: 'parallelType', value: 'collection' },
400+
},
401+
{
402+
id: 'maxConcurrency',
403+
title: 'Max Concurrency',
404+
type: 'slider',
405+
min: 1,
406+
max: 50,
407+
integer: true,
408+
default: 10,
409+
},
410+
],
235411
},
236412
}

0 commit comments

Comments
 (0)