mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -238,7 +238,7 @@ 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: { /* ... */ },
|
||||
}
|
||||
@@ -246,6 +246,8 @@ export const ServiceBlock: BlockConfig = {
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
@@ -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'
|
||||
@@ -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: {
|
||||
|
||||
@@ -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'
|
||||
@@ -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: {
|
||||
|
||||
@@ -309,20 +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) {
|
||||
params.file = normalizedFile
|
||||
}
|
||||
|
||||
switch (params.operation) {
|
||||
case 'dropbox_upload':
|
||||
return 'dropbox_upload'
|
||||
@@ -348,6 +334,16 @@ 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)
|
||||
const normalizedFile = normalizeFileInput(params.file, { single: true })
|
||||
if (normalizedFile) {
|
||||
result.file = normalizedFile
|
||||
}
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
|
||||
@@ -457,24 +457,19 @@ 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)
|
||||
if (params.timeout && typeof params.timeout === 'string') {
|
||||
result.timeout = params.timeout.endsWith('s') ? params.timeout : `${params.timeout}s`
|
||||
}
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
title: 'Use Autoprompt',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
@@ -62,6 +63,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
],
|
||||
value: () => 'auto',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'includeDomains',
|
||||
@@ -69,6 +71,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
type: 'long-input',
|
||||
placeholder: 'example.com, another.com (comma-separated)',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'excludeDomains',
|
||||
@@ -76,6 +79,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
type: 'long-input',
|
||||
placeholder: 'exclude.com, another.com (comma-separated)',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'category',
|
||||
@@ -95,6 +99,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
],
|
||||
value: () => '',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'text',
|
||||
@@ -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',
|
||||
@@ -125,6 +132,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
],
|
||||
value: () => 'never',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Get Contents operation inputs
|
||||
{
|
||||
@@ -147,6 +155,7 @@ 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',
|
||||
@@ -154,6 +163,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
type: 'short-input',
|
||||
placeholder: '5',
|
||||
condition: { field: 'operation', value: 'exa_get_contents' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'subpageTarget',
|
||||
@@ -161,12 +171,14 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
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
|
||||
{
|
||||
@@ -196,6 +208,7 @@ 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',
|
||||
@@ -203,12 +216,14 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
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',
|
||||
@@ -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',
|
||||
@@ -252,6 +270,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
],
|
||||
value: () => 'never',
|
||||
condition: { field: 'operation', value: 'exa_find_similar_links' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Answer operation inputs
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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'
|
||||
@@ -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: {
|
||||
|
||||
@@ -606,45 +606,23 @@ 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
|
||||
}
|
||||
if (params.folderTitle) {
|
||||
params.title = params.folderTitle
|
||||
}
|
||||
if (params.folderUidNew) {
|
||||
params.uid = params.folderUidNew
|
||||
}
|
||||
if (params.annotationTags) {
|
||||
params.tags = params.annotationTags
|
||||
}
|
||||
if (params.annotationDashboardUid) {
|
||||
params.dashboardUid = params.annotationDashboardUid
|
||||
}
|
||||
|
||||
if (params.alertTitle) params.title = params.alertTitle
|
||||
if (params.folderTitle) params.title = params.folderTitle
|
||||
if (params.folderUidNew) params.uid = params.folderUidNew
|
||||
if (params.annotationTags) params.tags = params.annotationTags
|
||||
if (params.annotationDashboardUid) params.dashboardUid = params.annotationDashboardUid
|
||||
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: {
|
||||
|
||||
@@ -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'
|
||||
@@ -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: {
|
||||
|
||||
@@ -826,16 +826,6 @@ Return ONLY the JSON array - no explanations or markdown formatting.`,
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
// Convert page_size to a number if provided
|
||||
if (params.page_size) {
|
||||
params.page_size = Number(params.page_size)
|
||||
}
|
||||
|
||||
// Convert notify_incident_channel from string to boolean
|
||||
if (params.notify_incident_channel !== undefined) {
|
||||
params.notify_incident_channel = params.notify_incident_channel === 'true'
|
||||
}
|
||||
|
||||
switch (params.operation) {
|
||||
case 'incidentio_incidents_list':
|
||||
return 'incidentio_incidents_list'
|
||||
@@ -929,6 +919,14 @@ Return ONLY the JSON array - no explanations or markdown formatting.`,
|
||||
return 'incidentio_incidents_list'
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
if (params.page_size) result.page_size = Number(params.page_size)
|
||||
if (params.notify_incident_channel !== undefined) {
|
||||
result.notify_incident_channel = params.notify_incident_channel === 'true'
|
||||
}
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
|
||||
@@ -169,17 +169,7 @@ export const LemlistBlock: BlockConfig<LemlistResponse> = {
|
||||
access: ['lemlist_get_activities', 'lemlist_get_lead', 'lemlist_send_email'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
if (params.limit) {
|
||||
params.limit = Number(params.limit)
|
||||
}
|
||||
if (params.offset) {
|
||||
params.offset = Number(params.offset)
|
||||
}
|
||||
// Map filterLeadId to leadId for get_activities tool
|
||||
if (params.filterLeadId) {
|
||||
params.leadId = params.filterLeadId
|
||||
}
|
||||
|
||||
if (params.filterLeadId) params.leadId = params.filterLeadId
|
||||
switch (params.operation) {
|
||||
case 'get_activities':
|
||||
return 'lemlist_get_activities'
|
||||
@@ -191,6 +181,12 @@ export const LemlistBlock: BlockConfig<LemlistResponse> = {
|
||||
return 'lemlist_get_activities'
|
||||
}
|
||||
},
|
||||
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: {
|
||||
|
||||
@@ -149,66 +149,48 @@ export const ParallelBlock: BlockConfig<ToolResponse> = {
|
||||
access: ['parallel_search', 'parallel_extract', 'parallel_deep_research'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
if (params.extract_objective) params.objective = params.extract_objective
|
||||
if (params.research_input) params.input = params.research_input
|
||||
switch (params.operation) {
|
||||
case 'search':
|
||||
// Convert search_queries from comma-separated string to array (if provided)
|
||||
if (params.search_queries && typeof params.search_queries === 'string') {
|
||||
const queries = params.search_queries
|
||||
.split(',')
|
||||
.map((query: string) => query.trim())
|
||||
.filter((query: string) => query.length > 0)
|
||||
// Only set if we have actual queries
|
||||
if (queries.length > 0) {
|
||||
params.search_queries = queries
|
||||
} else {
|
||||
params.search_queries = undefined
|
||||
}
|
||||
}
|
||||
|
||||
// Convert numeric parameters
|
||||
if (params.max_results) {
|
||||
params.max_results = Number(params.max_results)
|
||||
}
|
||||
if (params.max_chars_per_result) {
|
||||
params.max_chars_per_result = Number(params.max_chars_per_result)
|
||||
}
|
||||
|
||||
return 'parallel_search'
|
||||
|
||||
case 'extract':
|
||||
// Map extract_objective to objective for the tool
|
||||
params.objective = params.extract_objective
|
||||
|
||||
// Convert boolean strings to actual booleans with defaults
|
||||
if (params.excerpts === 'true' || params.excerpts === true) {
|
||||
params.excerpts = true
|
||||
} else if (params.excerpts === 'false' || params.excerpts === false) {
|
||||
params.excerpts = false
|
||||
} else {
|
||||
// Default to true if not provided
|
||||
params.excerpts = true
|
||||
}
|
||||
|
||||
if (params.full_content === 'true' || params.full_content === true) {
|
||||
params.full_content = true
|
||||
} else if (params.full_content === 'false' || params.full_content === false) {
|
||||
params.full_content = false
|
||||
} else {
|
||||
// Default to false if not provided
|
||||
params.full_content = false
|
||||
}
|
||||
|
||||
return 'parallel_extract'
|
||||
|
||||
case 'deep_research':
|
||||
// Map research_input to input for the tool
|
||||
params.input = params.research_input
|
||||
return 'parallel_deep_research'
|
||||
|
||||
default:
|
||||
return 'parallel_search'
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
const operation = params.operation
|
||||
|
||||
if (operation === 'search') {
|
||||
if (params.search_queries && typeof params.search_queries === 'string') {
|
||||
const queries = params.search_queries
|
||||
.split(',')
|
||||
.map((query: string) => query.trim())
|
||||
.filter((query: string) => query.length > 0)
|
||||
if (queries.length > 0) {
|
||||
result.search_queries = queries
|
||||
} else {
|
||||
result.search_queries = undefined
|
||||
}
|
||||
}
|
||||
if (params.max_results) result.max_results = Number(params.max_results)
|
||||
if (params.max_chars_per_result) {
|
||||
result.max_chars_per_result = Number(params.max_chars_per_result)
|
||||
}
|
||||
}
|
||||
|
||||
if (operation === 'extract') {
|
||||
result.excerpts = !(params.excerpts === 'false' || params.excerpts === false)
|
||||
result.full_content = params.full_content === 'true' || params.full_content === true
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
|
||||
@@ -1185,22 +1185,15 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
// Convert numeric parameters
|
||||
if (params.limit) params.limit = Number(params.limit)
|
||||
if (params.offset) params.offset = Number(params.offset)
|
||||
if (params.rolloutPercentage) params.rolloutPercentage = Number(params.rolloutPercentage)
|
||||
|
||||
// Map projectIdParam to projectId for get_project operation
|
||||
// Field renames in tool() are safe (they copy values, not coerce types)
|
||||
// and are needed for serialization-time validation of required fields
|
||||
if (params.operation === 'posthog_get_project' && params.projectIdParam) {
|
||||
params.projectId = params.projectIdParam
|
||||
}
|
||||
|
||||
// Map personalApiKey to apiKey for all private endpoint tools
|
||||
if (params.personalApiKey) {
|
||||
params.apiKey = params.personalApiKey
|
||||
}
|
||||
|
||||
// Map featureFlagId to flagId for feature flag operations
|
||||
const flagOps = [
|
||||
'posthog_get_feature_flag',
|
||||
'posthog_update_feature_flag',
|
||||
@@ -1210,7 +1203,6 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
params.flagId = params.featureFlagId
|
||||
}
|
||||
|
||||
// Map surveyType to type for survey operations
|
||||
if (
|
||||
(params.operation === 'posthog_create_survey' ||
|
||||
params.operation === 'posthog_update_survey') &&
|
||||
@@ -1219,37 +1211,30 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
params.type = params.surveyType
|
||||
}
|
||||
|
||||
// Map isStatic for cohorts
|
||||
if (params.operation === 'posthog_create_cohort' && params.isStatic !== undefined) {
|
||||
params.is_static = params.isStatic
|
||||
}
|
||||
|
||||
// Map dateMarker to date_marker for annotations
|
||||
if (params.operation === 'posthog_create_annotation' && params.dateMarker) {
|
||||
params.date_marker = params.dateMarker
|
||||
}
|
||||
|
||||
// Map propertyType to property_type
|
||||
if (params.operation === 'posthog_update_property_definition' && params.propertyType) {
|
||||
params.property_type = params.propertyType
|
||||
}
|
||||
|
||||
// Map insightQuery to query for insights
|
||||
if (params.operation === 'posthog_create_insight' && params.insightQuery) {
|
||||
params.query = params.insightQuery
|
||||
}
|
||||
|
||||
// Map insightTags to tags for insights
|
||||
if (params.operation === 'posthog_create_insight' && params.insightTags) {
|
||||
params.tags = params.insightTags
|
||||
}
|
||||
|
||||
// Map distinctIdFilter to distinctId for list_persons
|
||||
if (params.operation === 'posthog_list_persons' && params.distinctIdFilter) {
|
||||
params.distinctId = params.distinctIdFilter
|
||||
}
|
||||
|
||||
// Map experiment date fields
|
||||
if (params.operation === 'posthog_create_experiment') {
|
||||
if (params.experimentStartDate) {
|
||||
params.startDate = params.experimentStartDate
|
||||
@@ -1259,7 +1244,6 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
}
|
||||
}
|
||||
|
||||
// Map survey date fields
|
||||
if (
|
||||
params.operation === 'posthog_create_survey' ||
|
||||
params.operation === 'posthog_update_survey'
|
||||
@@ -1272,13 +1256,17 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
}
|
||||
}
|
||||
|
||||
// Convert responsesLimit to number
|
||||
if (params.responsesLimit) {
|
||||
params.responsesLimit = Number(params.responsesLimit)
|
||||
}
|
||||
|
||||
return params.operation as string
|
||||
},
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
if (params.limit) result.limit = Number(params.limit)
|
||||
if (params.offset) result.offset = Number(params.offset)
|
||||
if (params.rolloutPercentage) result.rolloutPercentage = Number(params.rolloutPercentage)
|
||||
if (params.responsesLimit) result.responsesLimit = Number(params.responsesLimit)
|
||||
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -602,11 +602,6 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
// Convert numeric fields
|
||||
if (params.limit) {
|
||||
params.limit = Number(params.limit)
|
||||
}
|
||||
|
||||
// Return the appropriate tool based on operation
|
||||
switch (params.operation) {
|
||||
case 'sentry_issues_list':
|
||||
@@ -637,6 +632,11 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
return 'sentry_issues_list'
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
if (params.limit) result.limit = Number(params.limit)
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
|
||||
@@ -755,43 +755,24 @@ export const SpotifyBlock: BlockConfig<ToolResponse> = {
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
// Convert numeric parameters
|
||||
if (params.limit) {
|
||||
params.limit = Number(params.limit)
|
||||
}
|
||||
if (params.volume_percent) {
|
||||
params.volume_percent = Number(params.volume_percent)
|
||||
}
|
||||
if (params.range_start) {
|
||||
params.range_start = Number(params.range_start)
|
||||
}
|
||||
if (params.insert_before) {
|
||||
params.insert_before = Number(params.insert_before)
|
||||
}
|
||||
if (params.range_length) {
|
||||
params.range_length = Number(params.range_length)
|
||||
}
|
||||
if (params.position_ms) {
|
||||
params.position_ms = Number(params.position_ms)
|
||||
}
|
||||
// Map followType to type for check_following
|
||||
if (params.followType) {
|
||||
params.type = params.followType
|
||||
}
|
||||
// Map newName to name for update_playlist
|
||||
if (params.newName) {
|
||||
params.name = params.newName
|
||||
}
|
||||
// Map playUris to uris for play
|
||||
if (params.playUris) {
|
||||
params.uris = params.playUris
|
||||
}
|
||||
// Normalize file input for cover image
|
||||
if (params.coverImage !== undefined) {
|
||||
params.coverImage = normalizeFileInput(params.coverImage, { single: true })
|
||||
}
|
||||
if (params.followType) params.type = params.followType
|
||||
if (params.newName) params.name = params.newName
|
||||
if (params.playUris) params.uris = params.playUris
|
||||
return params.operation || 'spotify_search'
|
||||
},
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
if (params.limit) result.limit = Number(params.limit)
|
||||
if (params.volume_percent) result.volume_percent = Number(params.volume_percent)
|
||||
if (params.range_start) result.range_start = Number(params.range_start)
|
||||
if (params.insert_before) result.insert_before = Number(params.insert_before)
|
||||
if (params.range_length) result.range_length = Number(params.range_length)
|
||||
if (params.position_ms) result.position_ms = Number(params.position_ms)
|
||||
if (params.coverImage !== undefined) {
|
||||
result.coverImage = normalizeFileInput(params.coverImage, { single: true })
|
||||
}
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
|
||||
@@ -64,11 +64,6 @@ export const WikipediaBlock: BlockConfig<WikipediaResponse> = {
|
||||
access: ['wikipedia_summary', 'wikipedia_search', 'wikipedia_content', 'wikipedia_random'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
// Convert searchLimit to a number for search operation
|
||||
if (params.searchLimit) {
|
||||
params.searchLimit = Number(params.searchLimit)
|
||||
}
|
||||
|
||||
switch (params.operation) {
|
||||
case 'wikipedia_summary':
|
||||
return 'wikipedia_summary'
|
||||
@@ -82,6 +77,11 @@ export const WikipediaBlock: BlockConfig<WikipediaResponse> = {
|
||||
return 'wikipedia_summary'
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
if (params.searchLimit) result.searchLimit = Number(params.searchLimit)
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
|
||||
@@ -442,11 +442,6 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
// Convert numeric parameters
|
||||
if (params.maxResults) {
|
||||
params.maxResults = Number(params.maxResults)
|
||||
}
|
||||
|
||||
switch (params.operation) {
|
||||
case 'youtube_search':
|
||||
return 'youtube_search'
|
||||
@@ -470,6 +465,11 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
return 'youtube_search'
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
if (params.maxResults) result.maxResults = Number(params.maxResults)
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
|
||||
Reference in New Issue
Block a user