Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix(blocks): move type coercions from tools.config.tool to tools.conf…
…ig.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
  • Loading branch information
waleedlatif1 committed Feb 20, 2026
commit afe0289be13ca58eb417243b6660df89ab94c9a6
2 changes: 2 additions & 0 deletions .claude/commands/add-block.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ Enables AI-assisted field generation.

## Tools Configuration

**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.

**Preferred:** Use tool names directly as dropdown option IDs to avoid switch cases:
```typescript
// Dropdown options use tool IDs directly
Expand Down
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,16 @@ export const ServiceBlock: BlockConfig = {
bgColor: '#hexcolor',
icon: ServiceIcon,
subBlocks: [ /* see SubBlock Properties */ ],
tools: { access: ['service_action'], config: { tool: (p) => `service_${p.operation}` } },
tools: { access: ['service_action'], config: { tool: (p) => `service_${p.operation}`, params: (p) => ({ /* type coercions here */ }) } },
inputs: { /* ... */ },
outputs: { /* ... */ },
}
```

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

**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).

**SubBlock Properties:**
```typescript
{
Expand Down
14 changes: 6 additions & 8 deletions apps/sim/blocks/blocks/ahrefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,14 +485,6 @@ Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, n
],
config: {
tool: (params) => {
// Convert numeric string inputs to numbers
if (params.limit) {
params.limit = Number(params.limit)
}
if (params.offset) {
params.offset = Number(params.offset)
}

switch (params.operation) {
case 'ahrefs_domain_rating':
return 'ahrefs_domain_rating'
Expand All @@ -514,6 +506,12 @@ Return ONLY the date string in YYYY-MM-DD format - no explanations, no quotes, n
return 'ahrefs_domain_rating'
}
},
params: (params) => {
const result: Record<string, unknown> = {}
if (params.limit) result.limit = Number(params.limit)
if (params.offset) result.offset = Number(params.offset)
return result
},
},
},
inputs: {
Expand Down
10 changes: 5 additions & 5 deletions apps/sim/blocks/blocks/arxiv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,6 @@ export const ArxivBlock: BlockConfig<ArxivResponse> = {
access: ['arxiv_search', 'arxiv_get_paper', 'arxiv_get_author_papers'],
config: {
tool: (params) => {
// Convert maxResults to a number for operations that use it
if (params.maxResults) {
params.maxResults = Number(params.maxResults)
}

switch (params.operation) {
case 'arxiv_search':
return 'arxiv_search'
Expand All @@ -126,6 +121,11 @@ export const ArxivBlock: BlockConfig<ArxivResponse> = {
return 'arxiv_search'
}
},
params: (params) => {
const result: Record<string, unknown> = {}
if (params.maxResults) result.maxResults = Number(params.maxResults)
return result
},
},
},
inputs: {
Expand Down
14 changes: 6 additions & 8 deletions apps/sim/blocks/blocks/dropbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,14 +309,6 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
],
config: {
tool: (params) => {
// Convert numeric params
if (params.limit) {
params.limit = Number(params.limit)
}
if (params.maxResults) {
params.maxResults = Number(params.maxResults)
}

// Normalize file input for upload operation - use canonical 'file' param
const normalizedFile = normalizeFileInput(params.file, { single: true })
if (normalizedFile) {
Expand Down Expand Up @@ -348,6 +340,12 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
return 'dropbox_upload'
}
},
params: (params) => {
const result: Record<string, unknown> = {}
if (params.limit) result.limit = Number(params.limit)
if (params.maxResults) result.maxResults = Number(params.maxResults)
return result
},
},
},
inputs: {
Expand Down
26 changes: 11 additions & 15 deletions apps/sim/blocks/blocks/elasticsearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,24 +457,20 @@ Return ONLY valid JSON - no explanations, no markdown code blocks.`,
],
config: {
tool: (params) => {
// Convert numeric strings to numbers
if (params.size) {
params.size = Number(params.size)
}
if (params.from) {
params.from = Number(params.from)
}
if (params.retryOnConflict) {
params.retryOnConflict = Number(params.retryOnConflict)
}
// Append 's' to timeout for Elasticsearch time format
if (params.timeout && !params.timeout.endsWith('s')) {
params.timeout = `${params.timeout}s`
}

// Return the operation as the tool ID
return params.operation || 'elasticsearch_search'
},
params: (params) => {
const result: Record<string, unknown> = {}
if (params.size) result.size = Number(params.size)
if (params.from) result.from = Number(params.from)
if (params.retryOnConflict) result.retryOnConflict = Number(params.retryOnConflict)
// Append 's' to timeout for Elasticsearch time format
if (params.timeout && typeof params.timeout === 'string' && !params.timeout.endsWith('s')) {
result.timeout = `${params.timeout}s`
}
Comment thread
waleedlatif1 marked this conversation as resolved.
Outdated
Comment thread
waleedlatif1 marked this conversation as resolved.
return result
},
},
},

Expand Down
40 changes: 30 additions & 10 deletions apps/sim/blocks/blocks/exa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
title: 'Use Autoprompt',
type: 'switch',
condition: { field: 'operation', value: 'exa_search' },
mode: 'advanced',
},
{
id: 'type',
Expand All @@ -62,20 +63,23 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
],
value: () => 'auto',
condition: { field: 'operation', value: 'exa_search' },
mode: 'advanced',
},
{
id: 'includeDomains',
title: 'Include Domains',
type: 'long-input',
placeholder: 'example.com, another.com (comma-separated)',
condition: { field: 'operation', value: 'exa_search' },
mode: 'advanced',
},
{
id: 'excludeDomains',
title: 'Exclude Domains',
type: 'long-input',
placeholder: 'exclude.com, another.com (comma-separated)',
condition: { field: 'operation', value: 'exa_search' },
mode: 'advanced',
},
{
id: 'category',
Expand All @@ -95,6 +99,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
],
value: () => '',
condition: { field: 'operation', value: 'exa_search' },
mode: 'advanced',
},
{
id: 'text',
Expand All @@ -107,12 +112,14 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
title: 'Include Highlights',
type: 'switch',
condition: { field: 'operation', value: 'exa_search' },
mode: 'advanced',
},
{
id: 'summary',
title: 'Include Summary',
type: 'switch',
condition: { field: 'operation', value: 'exa_search' },
mode: 'advanced',
},
{
id: 'livecrawl',
Expand All @@ -125,6 +132,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
],
value: () => 'never',
condition: { field: 'operation', value: 'exa_search' },
mode: 'advanced',
},
// Get Contents operation inputs
{
Expand All @@ -147,26 +155,30 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
type: 'long-input',
placeholder: 'Enter a query to guide the summary generation...',
condition: { field: 'operation', value: 'exa_get_contents' },
mode: 'advanced',
},
{
id: 'subpages',
title: 'Number of Subpages',
type: 'short-input',
placeholder: '5',
condition: { field: 'operation', value: 'exa_get_contents' },
mode: 'advanced',
},
{
id: 'subpageTarget',
title: 'Subpage Target Keywords',
type: 'long-input',
placeholder: 'docs, tutorial, about (comma-separated)',
condition: { field: 'operation', value: 'exa_get_contents' },
mode: 'advanced',
},
{
id: 'highlights',
title: 'Include Highlights',
type: 'switch',
condition: { field: 'operation', value: 'exa_get_contents' },
mode: 'advanced',
},
// Find Similar Links operation inputs
{
Expand Down Expand Up @@ -196,19 +208,22 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
type: 'long-input',
placeholder: 'example.com, another.com (comma-separated)',
condition: { field: 'operation', value: 'exa_find_similar_links' },
mode: 'advanced',
},
{
id: 'excludeDomains',
title: 'Exclude Domains',
type: 'long-input',
placeholder: 'exclude.com, another.com (comma-separated)',
condition: { field: 'operation', value: 'exa_find_similar_links' },
mode: 'advanced',
},
{
id: 'excludeSourceDomain',
title: 'Exclude Source Domain',
type: 'switch',
condition: { field: 'operation', value: 'exa_find_similar_links' },
mode: 'advanced',
},
{
id: 'category',
Expand All @@ -228,18 +243,21 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
],
value: () => '',
condition: { field: 'operation', value: 'exa_find_similar_links' },
mode: 'advanced',
},
{
id: 'highlights',
title: 'Include Highlights',
type: 'switch',
condition: { field: 'operation', value: 'exa_find_similar_links' },
mode: 'advanced',
},
{
id: 'summary',
title: 'Include Summary',
type: 'switch',
condition: { field: 'operation', value: 'exa_find_similar_links' },
mode: 'advanced',
},
{
id: 'livecrawl',
Expand All @@ -252,6 +270,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
],
value: () => 'never',
condition: { field: 'operation', value: 'exa_find_similar_links' },
mode: 'advanced',
},
// Answer operation inputs
{
Expand All @@ -267,6 +286,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
title: 'Include Text',
type: 'switch',
condition: { field: 'operation', value: 'exa_answer' },
mode: 'advanced',
},
// Research operation inputs
{
Expand Down Expand Up @@ -309,16 +329,6 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
],
config: {
tool: (params) => {
// Convert numResults to a number for operations that use it
if (params.numResults) {
params.numResults = Number(params.numResults)
}

// Convert subpages to a number if provided
if (params.subpages) {
params.subpages = Number(params.subpages)
}

switch (params.operation) {
case 'exa_search':
return 'exa_search'
Expand All @@ -334,6 +344,16 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
return 'exa_search'
}
},
params: (params) => {
const result: Record<string, unknown> = {}
if (params.numResults) {
result.numResults = Number(params.numResults)
}
if (params.subpages) {
result.subpages = Number(params.subpages)
}
return result
},
},
},
inputs: {
Expand Down
30 changes: 10 additions & 20 deletions apps/sim/blocks/blocks/grafana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,26 +606,6 @@ Return ONLY the folder title - no explanations, no quotes, no extra text.`,
],
config: {
tool: (params) => {
// Convert numeric string fields to numbers
if (params.panelId) {
params.panelId = Number(params.panelId)
}
if (params.annotationId) {
params.annotationId = Number(params.annotationId)
}
if (params.time) {
params.time = Number(params.time)
}
if (params.timeEnd) {
params.timeEnd = Number(params.timeEnd)
}
if (params.from) {
params.from = Number(params.from)
}
if (params.to) {
params.to = Number(params.to)
}

// Map subblock fields to tool parameter names
if (params.alertTitle) {
params.title = params.alertTitle
Expand All @@ -645,6 +625,16 @@ Return ONLY the folder title - no explanations, no quotes, no extra text.`,

return params.operation
},
params: (params) => {
const result: Record<string, unknown> = {}
if (params.panelId) result.panelId = Number(params.panelId)
if (params.annotationId) result.annotationId = Number(params.annotationId)
if (params.time) result.time = Number(params.time)
if (params.timeEnd) result.timeEnd = Number(params.timeEnd)
if (params.from) result.from = Number(params.from)
if (params.to) result.to = Number(params.to)
return result
},
},
},
inputs: {
Expand Down
10 changes: 5 additions & 5 deletions apps/sim/blocks/blocks/hunter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,6 @@ Return ONLY the search query text - no explanations.`,
],
config: {
tool: (params) => {
// Convert numeric parameters
if (params.limit) {
params.limit = Number(params.limit)
}

switch (params.operation) {
case 'hunter_discover':
return 'hunter_discover'
Expand All @@ -226,6 +221,11 @@ Return ONLY the search query text - no explanations.`,
return 'hunter_domain_search'
}
},
params: (params) => {
const result: Record<string, unknown> = {}
if (params.limit) result.limit = Number(params.limit)
return result
},
},
},
inputs: {
Expand Down
Loading