Skip to content

Commit 9920882

Browse files
authored
fix(blocks): move type coercions from tools.config.tool to tools.config.params (#3264)
* fix(blocks): move type coercions from tools.config.tool to tools.config.params Number() coercions in tools.config.tool ran at serialization time before variable resolution, destroying dynamic references like <block.result.count> by converting them to NaN/null. Moved all coercions to tools.config.params which runs at execution time after variables are resolved. Fixed in 15 blocks: exa, arxiv, sentry, incidentio, wikipedia, ahrefs, posthog, elasticsearch, dropbox, hunter, lemlist, spotify, youtube, grafana, parallel. Also added mode: 'advanced' to optional exa fields. Closes #3258 * fix(blocks): address PR review — move remaining param mutations from tool() to params() - Moved field mappings from tool() to params() in grafana, posthog, lemlist, spotify, dropbox (same dynamic reference bug) - Fixed parallel.ts excerpts/full_content boolean logic - Fixed parallel.ts search_queries empty case (must set undefined) - Fixed elasticsearch.ts timeout not included when already ends with 's' - Restored dropbox.ts tool() switch for proper default fallback * fix(blocks): restore field renames to tool() for serialization-time validation Field renames (e.g. personalApiKey→apiKey) must be in tool() because validateRequiredFieldsBeforeExecution calls selectToolId()→tool() then checks renamed field names on params. Only type coercions (Number(), boolean) stay in params() to avoid destroying dynamic variable references.
1 parent 9ca5254 commit 9920882

File tree

17 files changed

+173
-237
lines changed

17 files changed

+173
-237
lines changed

.claude/commands/add-block.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,8 @@ Enables AI-assisted field generation.
454454

455455
## Tools Configuration
456456

457+
**Important:** `tools.config.tool` runs during serialization before variable resolution. Put `Number()` and other type coercions in `tools.config.params` instead, which runs at execution time after variables are resolved.
458+
457459
**Preferred:** Use tool names directly as dropdown option IDs to avoid switch cases:
458460
```typescript
459461
// Dropdown options use tool IDs directly

CLAUDE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,16 @@ export const ServiceBlock: BlockConfig = {
238238
bgColor: '#hexcolor',
239239
icon: ServiceIcon,
240240
subBlocks: [ /* see SubBlock Properties */ ],
241-
tools: { access: ['service_action'], config: { tool: (p) => `service_${p.operation}` } },
241+
tools: { access: ['service_action'], config: { tool: (p) => `service_${p.operation}`, params: (p) => ({ /* type coercions here */ }) } },
242242
inputs: { /* ... */ },
243243
outputs: { /* ... */ },
244244
}
245245
```
246246

247247
Register in `blocks/registry.ts` (alphabetically).
248248

249+
**Important:** `tools.config.tool` runs during serialization (before variable resolution). Never do `Number()` or other type coercions there — dynamic references like `<Block.output>` will be destroyed. Use `tools.config.params` for type coercions (it runs during execution, after variables are resolved).
250+
249251
**SubBlock Properties:**
250252
```typescript
251253
{

apps/sim/blocks/blocks/ahrefs.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -485,14 +485,6 @@ Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, n
485485
],
486486
config: {
487487
tool: (params) => {
488-
// Convert numeric string inputs to numbers
489-
if (params.limit) {
490-
params.limit = Number(params.limit)
491-
}
492-
if (params.offset) {
493-
params.offset = Number(params.offset)
494-
}
495-
496488
switch (params.operation) {
497489
case 'ahrefs_domain_rating':
498490
return 'ahrefs_domain_rating'
@@ -514,6 +506,12 @@ Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, n
514506
return 'ahrefs_domain_rating'
515507
}
516508
},
509+
params: (params) => {
510+
const result: Record<string, unknown> = {}
511+
if (params.limit) result.limit = Number(params.limit)
512+
if (params.offset) result.offset = Number(params.offset)
513+
return result
514+
},
517515
},
518516
},
519517
inputs: {

apps/sim/blocks/blocks/arxiv.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,6 @@ export const ArxivBlock: BlockConfig<ArxivResponse> = {
110110
access: ['arxiv_search', 'arxiv_get_paper', 'arxiv_get_author_papers'],
111111
config: {
112112
tool: (params) => {
113-
// Convert maxResults to a number for operations that use it
114-
if (params.maxResults) {
115-
params.maxResults = Number(params.maxResults)
116-
}
117-
118113
switch (params.operation) {
119114
case 'arxiv_search':
120115
return 'arxiv_search'
@@ -126,6 +121,11 @@ export const ArxivBlock: BlockConfig<ArxivResponse> = {
126121
return 'arxiv_search'
127122
}
128123
},
124+
params: (params) => {
125+
const result: Record<string, unknown> = {}
126+
if (params.maxResults) result.maxResults = Number(params.maxResults)
127+
return result
128+
},
129129
},
130130
},
131131
inputs: {

apps/sim/blocks/blocks/dropbox.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -309,20 +309,6 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
309309
],
310310
config: {
311311
tool: (params) => {
312-
// Convert numeric params
313-
if (params.limit) {
314-
params.limit = Number(params.limit)
315-
}
316-
if (params.maxResults) {
317-
params.maxResults = Number(params.maxResults)
318-
}
319-
320-
// Normalize file input for upload operation - use canonical 'file' param
321-
const normalizedFile = normalizeFileInput(params.file, { single: true })
322-
if (normalizedFile) {
323-
params.file = normalizedFile
324-
}
325-
326312
switch (params.operation) {
327313
case 'dropbox_upload':
328314
return 'dropbox_upload'
@@ -348,6 +334,16 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
348334
return 'dropbox_upload'
349335
}
350336
},
337+
params: (params) => {
338+
const result: Record<string, unknown> = {}
339+
if (params.limit) result.limit = Number(params.limit)
340+
if (params.maxResults) result.maxResults = Number(params.maxResults)
341+
const normalizedFile = normalizeFileInput(params.file, { single: true })
342+
if (normalizedFile) {
343+
result.file = normalizedFile
344+
}
345+
return result
346+
},
351347
},
352348
},
353349
inputs: {

apps/sim/blocks/blocks/elasticsearch.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -457,24 +457,19 @@ Return ONLY valid JSON - no explanations, no markdown code blocks.`,
457457
],
458458
config: {
459459
tool: (params) => {
460-
// Convert numeric strings to numbers
461-
if (params.size) {
462-
params.size = Number(params.size)
463-
}
464-
if (params.from) {
465-
params.from = Number(params.from)
466-
}
467-
if (params.retryOnConflict) {
468-
params.retryOnConflict = Number(params.retryOnConflict)
469-
}
470-
// Append 's' to timeout for Elasticsearch time format
471-
if (params.timeout && !params.timeout.endsWith('s')) {
472-
params.timeout = `${params.timeout}s`
473-
}
474-
475460
// Return the operation as the tool ID
476461
return params.operation || 'elasticsearch_search'
477462
},
463+
params: (params) => {
464+
const result: Record<string, unknown> = {}
465+
if (params.size) result.size = Number(params.size)
466+
if (params.from) result.from = Number(params.from)
467+
if (params.retryOnConflict) result.retryOnConflict = Number(params.retryOnConflict)
468+
if (params.timeout && typeof params.timeout === 'string') {
469+
result.timeout = params.timeout.endsWith('s') ? params.timeout : `${params.timeout}s`
470+
}
471+
return result
472+
},
478473
},
479474
},
480475

apps/sim/blocks/blocks/exa.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
4949
title: 'Use Autoprompt',
5050
type: 'switch',
5151
condition: { field: 'operation', value: 'exa_search' },
52+
mode: 'advanced',
5253
},
5354
{
5455
id: 'type',
@@ -62,20 +63,23 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
6263
],
6364
value: () => 'auto',
6465
condition: { field: 'operation', value: 'exa_search' },
66+
mode: 'advanced',
6567
},
6668
{
6769
id: 'includeDomains',
6870
title: 'Include Domains',
6971
type: 'long-input',
7072
placeholder: 'example.com, another.com (comma-separated)',
7173
condition: { field: 'operation', value: 'exa_search' },
74+
mode: 'advanced',
7275
},
7376
{
7477
id: 'excludeDomains',
7578
title: 'Exclude Domains',
7679
type: 'long-input',
7780
placeholder: 'exclude.com, another.com (comma-separated)',
7881
condition: { field: 'operation', value: 'exa_search' },
82+
mode: 'advanced',
7983
},
8084
{
8185
id: 'category',
@@ -95,6 +99,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
9599
],
96100
value: () => '',
97101
condition: { field: 'operation', value: 'exa_search' },
102+
mode: 'advanced',
98103
},
99104
{
100105
id: 'text',
@@ -107,12 +112,14 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
107112
title: 'Include Highlights',
108113
type: 'switch',
109114
condition: { field: 'operation', value: 'exa_search' },
115+
mode: 'advanced',
110116
},
111117
{
112118
id: 'summary',
113119
title: 'Include Summary',
114120
type: 'switch',
115121
condition: { field: 'operation', value: 'exa_search' },
122+
mode: 'advanced',
116123
},
117124
{
118125
id: 'livecrawl',
@@ -125,6 +132,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
125132
],
126133
value: () => 'never',
127134
condition: { field: 'operation', value: 'exa_search' },
135+
mode: 'advanced',
128136
},
129137
// Get Contents operation inputs
130138
{
@@ -147,26 +155,30 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
147155
type: 'long-input',
148156
placeholder: 'Enter a query to guide the summary generation...',
149157
condition: { field: 'operation', value: 'exa_get_contents' },
158+
mode: 'advanced',
150159
},
151160
{
152161
id: 'subpages',
153162
title: 'Number of Subpages',
154163
type: 'short-input',
155164
placeholder: '5',
156165
condition: { field: 'operation', value: 'exa_get_contents' },
166+
mode: 'advanced',
157167
},
158168
{
159169
id: 'subpageTarget',
160170
title: 'Subpage Target Keywords',
161171
type: 'long-input',
162172
placeholder: 'docs, tutorial, about (comma-separated)',
163173
condition: { field: 'operation', value: 'exa_get_contents' },
174+
mode: 'advanced',
164175
},
165176
{
166177
id: 'highlights',
167178
title: 'Include Highlights',
168179
type: 'switch',
169180
condition: { field: 'operation', value: 'exa_get_contents' },
181+
mode: 'advanced',
170182
},
171183
// Find Similar Links operation inputs
172184
{
@@ -196,19 +208,22 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
196208
type: 'long-input',
197209
placeholder: 'example.com, another.com (comma-separated)',
198210
condition: { field: 'operation', value: 'exa_find_similar_links' },
211+
mode: 'advanced',
199212
},
200213
{
201214
id: 'excludeDomains',
202215
title: 'Exclude Domains',
203216
type: 'long-input',
204217
placeholder: 'exclude.com, another.com (comma-separated)',
205218
condition: { field: 'operation', value: 'exa_find_similar_links' },
219+
mode: 'advanced',
206220
},
207221
{
208222
id: 'excludeSourceDomain',
209223
title: 'Exclude Source Domain',
210224
type: 'switch',
211225
condition: { field: 'operation', value: 'exa_find_similar_links' },
226+
mode: 'advanced',
212227
},
213228
{
214229
id: 'category',
@@ -228,18 +243,21 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
228243
],
229244
value: () => '',
230245
condition: { field: 'operation', value: 'exa_find_similar_links' },
246+
mode: 'advanced',
231247
},
232248
{
233249
id: 'highlights',
234250
title: 'Include Highlights',
235251
type: 'switch',
236252
condition: { field: 'operation', value: 'exa_find_similar_links' },
253+
mode: 'advanced',
237254
},
238255
{
239256
id: 'summary',
240257
title: 'Include Summary',
241258
type: 'switch',
242259
condition: { field: 'operation', value: 'exa_find_similar_links' },
260+
mode: 'advanced',
243261
},
244262
{
245263
id: 'livecrawl',
@@ -252,6 +270,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
252270
],
253271
value: () => 'never',
254272
condition: { field: 'operation', value: 'exa_find_similar_links' },
273+
mode: 'advanced',
255274
},
256275
// Answer operation inputs
257276
{
@@ -267,6 +286,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
267286
title: 'Include Text',
268287
type: 'switch',
269288
condition: { field: 'operation', value: 'exa_answer' },
289+
mode: 'advanced',
270290
},
271291
// Research operation inputs
272292
{
@@ -309,16 +329,6 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
309329
],
310330
config: {
311331
tool: (params) => {
312-
// Convert numResults to a number for operations that use it
313-
if (params.numResults) {
314-
params.numResults = Number(params.numResults)
315-
}
316-
317-
// Convert subpages to a number if provided
318-
if (params.subpages) {
319-
params.subpages = Number(params.subpages)
320-
}
321-
322332
switch (params.operation) {
323333
case 'exa_search':
324334
return 'exa_search'
@@ -334,6 +344,16 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
334344
return 'exa_search'
335345
}
336346
},
347+
params: (params) => {
348+
const result: Record<string, unknown> = {}
349+
if (params.numResults) {
350+
result.numResults = Number(params.numResults)
351+
}
352+
if (params.subpages) {
353+
result.subpages = Number(params.subpages)
354+
}
355+
return result
356+
},
337357
},
338358
},
339359
inputs: {

0 commit comments

Comments
 (0)