From a69d0301435c9831151797489d5ba0aa26f58827 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 18:39:01 -0700 Subject: [PATCH 1/6] fix(parallel): align integration with Parallel AI API docs --- .../content/docs/en/tools/parallel_ai.mdx | 36 +++--- apps/sim/blocks/blocks/parallel.ts | 104 ++++++++++++----- apps/sim/tools/parallel/deep_research.ts | 62 +++++----- apps/sim/tools/parallel/extract.ts | 63 +++++++--- apps/sim/tools/parallel/index.ts | 2 + apps/sim/tools/parallel/search.ts | 108 +++++++++++++----- apps/sim/tools/parallel/types.ts | 61 ++++++---- 7 files changed, 301 insertions(+), 135 deletions(-) diff --git a/apps/docs/content/docs/en/tools/parallel_ai.mdx b/apps/docs/content/docs/en/tools/parallel_ai.mdx index 733b9bc239..c36b86a264 100644 --- a/apps/docs/content/docs/en/tools/parallel_ai.mdx +++ b/apps/docs/content/docs/en/tools/parallel_ai.mdx @@ -44,20 +44,24 @@ Search the web using Parallel AI. Provides comprehensive search results with int | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `objective` | string | Yes | The search objective or question to answer | -| `search_queries` | string | No | Optional comma-separated list of search queries to execute | -| `processor` | string | No | Processing method: base or pro \(default: base\) | -| `max_results` | number | No | Maximum number of results to return \(default: 5\) | -| `max_chars_per_result` | number | No | Maximum characters per result \(default: 1500\) | +| `search_queries` | json | No | Array of search queries to execute | +| `mode` | string | No | Search mode: one-shot, agentic, or fast \(default: one-shot\) | +| `max_results` | number | No | Maximum number of results to return \(default: 10\) | +| `max_chars_per_result` | number | No | Maximum characters per result excerpt \(minimum: 1000\) | +| `include_domains` | string | No | Comma-separated list of domains to restrict search results to | +| `exclude_domains` | string | No | Comma-separated list of domains to exclude from search results | | `apiKey` | string | Yes | Parallel AI API Key | #### Output | Parameter | Type | Description | | --------- | ---- | ----------- | +| `search_id` | string | Unique identifier for this search request | | `results` | array | Search results with excerpts from relevant pages | | ↳ `url` | string | The URL of the search result | | ↳ `title` | string | The title of the search result | -| ↳ `excerpts` | array | Text excerpts from the page | +| ↳ `publish_date` | string | Publication date of the page \(YYYY-MM-DD\) | +| ↳ `excerpts` | array | LLM-optimized excerpts from the page | ### `parallel_extract` @@ -68,31 +72,33 @@ Extract targeted information from specific URLs using Parallel AI. Processes pro | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `urls` | string | Yes | Comma-separated list of URLs to extract information from | -| `objective` | string | Yes | What information to extract from the provided URLs | -| `excerpts` | boolean | Yes | Include relevant excerpts from the content | -| `full_content` | boolean | Yes | Include full page content | +| `objective` | string | No | What information to extract from the provided URLs | +| `excerpts` | boolean | No | Include relevant excerpts from the content \(default: true\) | +| `full_content` | boolean | No | Include full page content as markdown \(default: false\) | | `apiKey` | string | Yes | Parallel AI API Key | #### Output | Parameter | Type | Description | | --------- | ---- | ----------- | +| `extract_id` | string | Unique identifier for this extraction request | | `results` | array | Extracted information from the provided URLs | | ↳ `url` | string | The source URL | | ↳ `title` | string | The title of the page | -| ↳ `content` | string | Extracted content | -| ↳ `excerpts` | array | Relevant text excerpts | +| ↳ `publish_date` | string | Publication date \(YYYY-MM-DD\) | +| ↳ `excerpts` | array | Relevant text excerpts in markdown | +| ↳ `full_content` | string | Full page content as markdown | ### `parallel_deep_research` -Conduct comprehensive deep research across the web using Parallel AI. Synthesizes information from multiple sources with citations. Can take up to 15 minutes to complete. +Conduct comprehensive deep research across the web using Parallel AI. Synthesizes information from multiple sources with citations. Can take up to 45 minutes to complete. #### Input | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `input` | string | Yes | Research query or question \(up to 15,000 characters\) | -| `processor` | string | No | Compute level: base, lite, pro, ultra, ultra2x, ultra4x, ultra8x \(default: base\) | +| `processor` | string | No | Processing tier: pro, ultra, pro-fast, ultra-fast \(default: pro\) | | `include_domains` | string | No | Comma-separated list of domains to restrict research to \(source policy\) | | `exclude_domains` | string | No | Comma-separated list of domains to exclude from research \(source policy\) | | `apiKey` | string | Yes | Parallel AI API Key | @@ -101,17 +107,17 @@ Conduct comprehensive deep research across the web using Parallel AI. Synthesize | Parameter | Type | Description | | --------- | ---- | ----------- | -| `status` | string | Task status \(completed, failed\) | +| `status` | string | Task status \(completed, failed, running\) | | `run_id` | string | Unique ID for this research task | | `message` | string | Status message | | `content` | object | Research results \(structured based on output_schema\) | | `basis` | array | Citations and sources with reasoning and confidence levels | -| ↳ `field` | string | Output field name | +| ↳ `field` | string | Output field dot-notation path | | ↳ `reasoning` | string | Explanation for the result | | ↳ `citations` | array | Array of sources | | ↳ `url` | string | Source URL | | ↳ `title` | string | Source title | | ↳ `excerpts` | array | Relevant excerpts from the source | -| ↳ `confidence` | string | Confidence level indicator | +| ↳ `confidence` | string | Confidence level \(high, medium\) | diff --git a/apps/sim/blocks/blocks/parallel.ts b/apps/sim/blocks/blocks/parallel.ts index 96453d37b6..cd8649cf50 100644 --- a/apps/sim/blocks/blocks/parallel.ts +++ b/apps/sim/blocks/blocks/parallel.ts @@ -9,7 +9,7 @@ export const ParallelBlock: BlockConfig = { authMode: AuthMode.ApiKey, longDescription: 'Integrate Parallel AI into the workflow. Can search the web, extract information from URLs, and conduct deep research.', - docsLink: 'https://docs.parallel.ai/', + docsLink: 'https://docs.sim.ai/tools/parallel-ai', category: 'tools', bgColor: '#E0E0E0', icon: ParallelIcon, @@ -56,7 +56,7 @@ export const ParallelBlock: BlockConfig = { title: 'Extract Objective', type: 'long-input', placeholder: 'What information to extract from the URLs?', - required: true, + required: false, condition: { field: 'operation', value: 'extract' }, }, { @@ -89,6 +89,37 @@ export const ParallelBlock: BlockConfig = { required: true, condition: { field: 'operation', value: 'deep_research' }, }, + { + id: 'search_mode', + title: 'Search Mode', + type: 'dropdown', + options: [ + { label: 'One-Shot', id: 'one-shot' }, + { label: 'Agentic', id: 'agentic' }, + { label: 'Fast', id: 'fast' }, + ], + value: () => 'one-shot', + condition: { field: 'operation', value: 'search' }, + mode: 'advanced', + }, + { + id: 'search_include_domains', + title: 'Include Domains', + type: 'short-input', + placeholder: 'Comma-separated domains to include (e.g., .edu, example.com)', + required: false, + condition: { field: 'operation', value: 'search' }, + mode: 'advanced', + }, + { + id: 'search_exclude_domains', + title: 'Exclude Domains', + type: 'short-input', + placeholder: 'Comma-separated domains to exclude', + required: false, + condition: { field: 'operation', value: 'search' }, + mode: 'advanced', + }, { id: 'include_domains', title: 'Include Domains', @@ -96,6 +127,7 @@ export const ParallelBlock: BlockConfig = { placeholder: 'Comma-separated domains to include', required: false, condition: { field: 'operation', value: 'deep_research' }, + mode: 'advanced', }, { id: 'exclude_domains', @@ -104,37 +136,37 @@ export const ParallelBlock: BlockConfig = { placeholder: 'Comma-separated domains to exclude', required: false, condition: { field: 'operation', value: 'deep_research' }, + mode: 'advanced', }, { - id: 'processor', - title: 'Processor', + id: 'research_processor', + title: 'Research Processor', type: 'dropdown', options: [ - { label: 'Lite', id: 'lite' }, - { label: 'Base', id: 'base' }, - { label: 'Core', id: 'core' }, - { label: 'Core 2x', id: 'core2x' }, { label: 'Pro', id: 'pro' }, { label: 'Ultra', id: 'ultra' }, - { label: 'Ultra 2x', id: 'ultra2x' }, - { label: 'Ultra 4x', id: 'ultra4x' }, + { label: 'Pro Fast', id: 'pro-fast' }, + { label: 'Ultra Fast', id: 'ultra-fast' }, ], - value: () => 'base', - condition: { field: 'operation', value: ['search', 'deep_research'] }, + value: () => 'pro', + condition: { field: 'operation', value: 'deep_research' }, + mode: 'advanced', }, { id: 'max_results', title: 'Max Results', type: 'short-input', - placeholder: '5', + placeholder: '10', condition: { field: 'operation', value: 'search' }, + mode: 'advanced', }, { id: 'max_chars_per_result', - title: 'Max Chars', + title: 'Max Chars Per Result', type: 'short-input', placeholder: '1500', condition: { field: 'operation', value: 'search' }, + mode: 'advanced', }, { id: 'apiKey', @@ -149,8 +181,6 @@ export const ParallelBlock: BlockConfig = { 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': return 'parallel_search' @@ -174,21 +204,30 @@ export const ParallelBlock: BlockConfig = { .filter((query: string) => query.length > 0) if (queries.length > 0) { result.search_queries = queries - } else { - result.search_queries = undefined } } + if (params.search_mode && params.search_mode !== 'one-shot') { + result.mode = params.search_mode + } 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 (params.search_include_domains) result.include_domains = params.search_include_domains + if (params.search_exclude_domains) result.exclude_domains = params.search_exclude_domains } if (operation === 'extract') { + if (params.extract_objective) result.objective = params.extract_objective result.excerpts = !(params.excerpts === 'false' || params.excerpts === false) result.full_content = params.full_content === 'true' || params.full_content === true } + if (operation === 'deep_research') { + result.input = params.research_input + if (params.research_processor) result.processor = params.research_processor + } + return result }, }, @@ -202,29 +241,34 @@ export const ParallelBlock: BlockConfig = { excerpts: { type: 'boolean', description: 'Include excerpts' }, full_content: { type: 'boolean', description: 'Include full content' }, research_input: { type: 'string', description: 'Deep research query' }, - include_domains: { type: 'string', description: 'Domains to include' }, - exclude_domains: { type: 'string', description: 'Domains to exclude' }, - processor: { type: 'string', description: 'Processing method' }, + include_domains: { type: 'string', description: 'Domains to include (deep research)' }, + exclude_domains: { type: 'string', description: 'Domains to exclude (deep research)' }, + search_include_domains: { type: 'string', description: 'Domains to include (search)' }, + search_exclude_domains: { type: 'string', description: 'Domains to exclude (search)' }, + search_mode: { type: 'string', description: 'Search mode (one-shot, agentic, fast)' }, + research_processor: { type: 'string', description: 'Research processing tier' }, max_results: { type: 'number', description: 'Maximum number of results' }, max_chars_per_result: { type: 'number', description: 'Maximum characters per result' }, apiKey: { type: 'string', description: 'Parallel AI API key' }, }, outputs: { - results: { type: 'string', description: 'Search or extract results (JSON stringified)' }, + results: { + type: 'json', + description: 'Search or extract results (array of url, title, excerpts)', + }, + search_id: { type: 'string', description: 'Search request ID (for search)' }, + extract_id: { type: 'string', description: 'Extract request ID (for extract)' }, status: { type: 'string', description: 'Task status (for deep research)' }, run_id: { type: 'string', description: 'Task run ID (for deep research)' }, message: { type: 'string', description: 'Status message (for deep research)' }, content: { - type: 'string', - description: 'Research content (for deep research, JSON stringified)', + type: 'json', + description: 'Research content (for deep research, structured based on output_schema)', }, basis: { - type: 'string', - description: 'Citations and sources (for deep research, JSON stringified)', - }, - metadata: { - type: 'string', - description: 'Task metadata (for deep research, JSON stringified)', + type: 'json', + description: + 'Citations and sources with field, reasoning, citations, confidence (for deep research)', }, }, } diff --git a/apps/sim/tools/parallel/deep_research.ts b/apps/sim/tools/parallel/deep_research.ts index 1533af232e..8a2fdb6112 100644 --- a/apps/sim/tools/parallel/deep_research.ts +++ b/apps/sim/tools/parallel/deep_research.ts @@ -8,7 +8,7 @@ export const deepResearchTool: ToolConfig { const body: Record = { input: params.input, - processor: params.processor || 'base', + processor: params.processor || 'pro', + task_spec: { + output_schema: 'auto', + }, } - const taskSpec: Record = {} - - taskSpec.output_schema = 'auto' - - body.task_spec = taskSpec - if (params.include_domains || params.exclude_domains) { const sourcePolicy: Record = {} @@ -91,14 +87,21 @@ export const deepResearchTool: ToolConfig { + if (!response.ok) { + const errorText = await response.text() + throw new Error( + `Parallel AI deep research task creation failed: ${response.status} - ${errorText}` + ) + } + const data = await response.json() return { success: true, output: { - run_id: data.run_id, - status: data.status, - message: `Research task ${data.status}, waiting for completion...`, + run_id: data.run_id ?? null, + status: data.status ?? null, + message: `Research task ${data.status ?? 'created'}, waiting for completion...`, content: {}, basis: [], }, @@ -122,13 +125,16 @@ export const deepResearchTool: ToolConfig = { }, objective: { type: 'string', - required: true, + required: false, visibility: 'user-or-llm', description: 'What information to extract from the provided URLs', }, excerpts: { type: 'boolean', - required: true, - visibility: 'user-only', - description: 'Include relevant excerpts from the content', + required: false, + visibility: 'user-or-llm', + description: 'Include relevant excerpts from the content (default: true)', }, full_content: { type: 'boolean', - required: true, - visibility: 'user-only', - description: 'Include full page content', + required: false, + visibility: 'user-or-llm', + description: 'Include full page content as markdown (default: false)', }, apiKey: { type: 'string', @@ -50,7 +50,6 @@ export const extractTool: ToolConfig = { 'parallel-beta': 'search-extract-2025-10-10', }), body: (params) => { - // Convert comma-separated URLs to array const urlArray = params.urls .split(',') .map((url) => url.trim()) @@ -58,10 +57,9 @@ export const extractTool: ToolConfig = { const body: Record = { urls: urlArray, - objective: params.objective, } - // Add optional parameters if provided + if (params.objective) body.objective = params.objective if (params.excerpts !== undefined) body.excerpts = params.excerpts if (params.full_content !== undefined) body.full_content = params.full_content @@ -70,17 +68,44 @@ export const extractTool: ToolConfig = { }, transformResponse: async (response: Response) => { + if (!response.ok) { + const errorText = await response.text() + throw new Error(`Parallel AI extract failed: ${response.status} - ${errorText}`) + } + const data = await response.json() + if (!data.results) { + return { + success: false, + output: { + error: 'No results returned from extraction', + results: [], + extract_id: data.extract_id ?? null, + }, + } + } + return { success: true, output: { - results: data.results || [], + extract_id: data.extract_id ?? null, + results: data.results.map((result: Record) => ({ + url: result.url ?? null, + title: result.title ?? null, + publish_date: result.publish_date ?? null, + excerpts: result.excerpts ?? [], + full_content: result.full_content ?? null, + })), }, } }, outputs: { + extract_id: { + type: 'string', + description: 'Unique identifier for this extraction request', + }, results: { type: 'array', description: 'Extracted information from the provided URLs', @@ -88,12 +113,22 @@ export const extractTool: ToolConfig = { type: 'object', properties: { url: { type: 'string', description: 'The source URL' }, - title: { type: 'string', description: 'The title of the page' }, - content: { type: 'string', description: 'Extracted content' }, + title: { type: 'string', description: 'The title of the page', optional: true }, + publish_date: { + type: 'string', + description: 'Publication date (YYYY-MM-DD)', + optional: true, + }, excerpts: { type: 'array', - description: 'Relevant text excerpts', + description: 'Relevant text excerpts in markdown', items: { type: 'string' }, + optional: true, + }, + full_content: { + type: 'string', + description: 'Full page content as markdown', + optional: true, }, }, }, diff --git a/apps/sim/tools/parallel/index.ts b/apps/sim/tools/parallel/index.ts index 7e9c9abb74..585123cf6c 100644 --- a/apps/sim/tools/parallel/index.ts +++ b/apps/sim/tools/parallel/index.ts @@ -5,3 +5,5 @@ import { searchTool } from '@/tools/parallel/search' export const parallelSearchTool = searchTool export const parallelExtractTool = extractTool export const parallelDeepResearchTool = deepResearchTool + +export * from './types' diff --git a/apps/sim/tools/parallel/search.ts b/apps/sim/tools/parallel/search.ts index 6cd919a140..23accb7767 100644 --- a/apps/sim/tools/parallel/search.ts +++ b/apps/sim/tools/parallel/search.ts @@ -16,28 +16,40 @@ export const searchTool: ToolConfig = { description: 'The search objective or question to answer', }, search_queries: { - type: 'string', + type: 'json', required: false, visibility: 'user-or-llm', - description: 'Optional comma-separated list of search queries to execute', + description: 'Array of search queries to execute', }, - processor: { + mode: { type: 'string', required: false, visibility: 'user-only', - description: 'Processing method: base or pro (default: base)', + description: 'Search mode: one-shot, agentic, or fast (default: one-shot)', }, max_results: { type: 'number', required: false, visibility: 'user-only', - description: 'Maximum number of results to return (default: 5)', + description: 'Maximum number of results to return (default: 10)', }, max_chars_per_result: { type: 'number', required: false, visibility: 'user-only', - description: 'Maximum characters per result (default: 1500)', + description: 'Maximum characters per result excerpt (minimum: 1000)', + }, + include_domains: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of domains to restrict search results to', + }, + exclude_domains: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated list of domains to exclude from search results', }, apiKey: { type: 'string', @@ -60,44 +72,83 @@ export const searchTool: ToolConfig = { objective: params.objective, } - // Only include search_queries if it's not empty - if ( - params.search_queries !== undefined && - params.search_queries !== null && - params.search_queries.length > 0 - ) { - body.search_queries = params.search_queries + if (params.search_queries) { + if (Array.isArray(params.search_queries)) { + body.search_queries = params.search_queries + } else if (typeof params.search_queries === 'string') { + const queries = params.search_queries + .split(',') + .map((q: string) => q.trim()) + .filter((q: string) => q.length > 0) + if (queries.length > 0) body.search_queries = queries + } } - // Add optional parameters if provided - if (params.processor) body.processor = params.processor + if (params.mode) body.mode = params.mode if (params.max_results) body.max_results = Number(params.max_results) - if (params.max_chars_per_result) - body.max_chars_per_result = Number(params.max_chars_per_result) + if (params.max_chars_per_result) { + body.excerpts = { max_chars_per_result: Number(params.max_chars_per_result) } + } + + const sourcePolicy: Record = {} + if (params.include_domains) { + sourcePolicy.include_domains = params.include_domains + .split(',') + .map((d: string) => d.trim()) + .filter((d: string) => d.length > 0) + } + if (params.exclude_domains) { + sourcePolicy.exclude_domains = params.exclude_domains + .split(',') + .map((d: string) => d.trim()) + .filter((d: string) => d.length > 0) + } + if (Object.keys(sourcePolicy).length > 0) { + body.source_policy = sourcePolicy + } return body }, }, transformResponse: async (response: Response) => { + if (!response.ok) { + const errorText = await response.text() + throw new Error(`Parallel AI search failed: ${response.status} - ${errorText}`) + } + const data = await response.json() + if (!data.results) { + return { + success: false, + output: { + error: 'No results returned from search', + results: [], + search_id: data.search_id ?? null, + }, + } + } + return { success: true, output: { - results: data.results.map((result: unknown) => { - const resultObj = result as Record - return { - url: resultObj.url || '', - title: resultObj.title || '', - excerpts: resultObj.excerpts || [], - } - }), + search_id: data.search_id ?? null, + results: data.results.map((result: Record) => ({ + url: result.url ?? null, + title: result.title ?? null, + publish_date: result.publish_date ?? null, + excerpts: result.excerpts ?? [], + })), }, } }, outputs: { + search_id: { + type: 'string', + description: 'Unique identifier for this search request', + }, results: { type: 'array', description: 'Search results with excerpts from relevant pages', @@ -106,9 +157,14 @@ export const searchTool: ToolConfig = { properties: { url: { type: 'string', description: 'The URL of the search result' }, title: { type: 'string', description: 'The title of the search result' }, + publish_date: { + type: 'string', + description: 'Publication date of the page (YYYY-MM-DD)', + optional: true, + }, excerpts: { type: 'array', - description: 'Text excerpts from the page', + description: 'LLM-optimized excerpts from the page', items: { type: 'string' }, }, }, diff --git a/apps/sim/tools/parallel/types.ts b/apps/sim/tools/parallel/types.ts index bca8fd437f..0c363bd3c9 100644 --- a/apps/sim/tools/parallel/types.ts +++ b/apps/sim/tools/parallel/types.ts @@ -1,39 +1,51 @@ +import type { ToolResponse } from '@/tools/types' + export interface ParallelSearchParams { objective: string - search_queries: string[] - processor?: string + search_queries?: string[] | string + mode?: string max_results?: number max_chars_per_result?: number + include_domains?: string + exclude_domains?: string apiKey: string } export interface ParallelSearchResult { url: string title: string + publish_date?: string | null excerpts: string[] } -export interface ParallelSearchResponse { - results: ParallelSearchResult[] +export interface ParallelSearchResponse extends ToolResponse { + output: { + search_id: string | null + results: ParallelSearchResult[] + } } export interface ParallelExtractParams { urls: string - objective: string - excerpts: boolean - full_content: boolean + objective?: string + excerpts?: boolean + full_content?: boolean apiKey: string } export interface ParallelExtractResult { url: string - title: string - content?: string + title?: string | null + publish_date?: string | null excerpts?: string[] + full_content?: string | null } -export interface ParallelExtractResponse { - results: ParallelExtractResult[] +export interface ParallelExtractResponse extends ToolResponse { + output: { + extract_id: string | null + results: ParallelExtractResult[] + } } export interface ParallelDeepResearchParams { @@ -45,17 +57,22 @@ export interface ParallelDeepResearchParams { } export interface ParallelDeepResearchBasis { - url: string - title: string - excerpt: string - confidence?: number + field: string + reasoning: string + citations: { + url: string + title: string + excerpts: string[] + }[] + confidence: string } -export interface ParallelDeepResearchResponse { - status: string - run_id: string - message?: string - content?: Record - basis?: ParallelDeepResearchBasis[] - metadata?: Record +export interface ParallelDeepResearchResponse extends ToolResponse { + output: { + status: string + run_id: string + message: string + content: Record + basis: ParallelDeepResearchBasis[] + } } From 56dac47a90f4e20bfc0f1a898eb34e190b1bd524 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 18:48:01 -0700 Subject: [PATCH 2/6] fix(parallel): keep processor subBlock ID for backwards compatibility --- apps/sim/blocks/blocks/parallel.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sim/blocks/blocks/parallel.ts b/apps/sim/blocks/blocks/parallel.ts index cd8649cf50..e210c6dc36 100644 --- a/apps/sim/blocks/blocks/parallel.ts +++ b/apps/sim/blocks/blocks/parallel.ts @@ -139,7 +139,7 @@ export const ParallelBlock: BlockConfig = { mode: 'advanced', }, { - id: 'research_processor', + id: 'processor', title: 'Research Processor', type: 'dropdown', options: [ @@ -225,7 +225,7 @@ export const ParallelBlock: BlockConfig = { if (operation === 'deep_research') { result.input = params.research_input - if (params.research_processor) result.processor = params.research_processor + if (params.processor) result.processor = params.processor } return result @@ -246,7 +246,7 @@ export const ParallelBlock: BlockConfig = { search_include_domains: { type: 'string', description: 'Domains to include (search)' }, search_exclude_domains: { type: 'string', description: 'Domains to exclude (search)' }, search_mode: { type: 'string', description: 'Search mode (one-shot, agentic, fast)' }, - research_processor: { type: 'string', description: 'Research processing tier' }, + processor: { type: 'string', description: 'Research processing tier' }, max_results: { type: 'number', description: 'Maximum number of results' }, max_chars_per_result: { type: 'number', description: 'Maximum characters per result' }, apiKey: { type: 'string', description: 'Parallel AI API key' }, From 586b13fa55ad503ecdc4c28d531526e1d24b789d Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 18:59:11 -0700 Subject: [PATCH 3/6] fix(parallel): move error field to top level per ToolResponse interface --- apps/sim/tools/parallel/extract.ts | 2 +- apps/sim/tools/parallel/search.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/tools/parallel/extract.ts b/apps/sim/tools/parallel/extract.ts index 91061e606d..8a16b6a699 100644 --- a/apps/sim/tools/parallel/extract.ts +++ b/apps/sim/tools/parallel/extract.ts @@ -78,8 +78,8 @@ export const extractTool: ToolConfig = { if (!data.results) { return { success: false, + error: 'No results returned from extraction', output: { - error: 'No results returned from extraction', results: [], extract_id: data.extract_id ?? null, }, diff --git a/apps/sim/tools/parallel/search.ts b/apps/sim/tools/parallel/search.ts index 23accb7767..b375380b08 100644 --- a/apps/sim/tools/parallel/search.ts +++ b/apps/sim/tools/parallel/search.ts @@ -122,8 +122,8 @@ export const searchTool: ToolConfig = { if (!data.results) { return { success: false, + error: 'No results returned from search', output: { - error: 'No results returned from search', results: [], search_id: data.search_id ?? null, }, From 2df13b6caac0bb9bb95c0164e005d945e32ad608 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 19:28:20 -0700 Subject: [PATCH 4/6] fix(parallel): guard research_input and prevent domain leakage across operations --- apps/sim/blocks/blocks/parallel.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sim/blocks/blocks/parallel.ts b/apps/sim/blocks/blocks/parallel.ts index e210c6dc36..025d0307c9 100644 --- a/apps/sim/blocks/blocks/parallel.ts +++ b/apps/sim/blocks/blocks/parallel.ts @@ -213,8 +213,8 @@ export const ParallelBlock: BlockConfig = { if (params.max_chars_per_result) { result.max_chars_per_result = Number(params.max_chars_per_result) } - if (params.search_include_domains) result.include_domains = params.search_include_domains - if (params.search_exclude_domains) result.exclude_domains = params.search_exclude_domains + result.include_domains = params.search_include_domains || undefined + result.exclude_domains = params.search_exclude_domains || undefined } if (operation === 'extract') { @@ -224,7 +224,7 @@ export const ParallelBlock: BlockConfig = { } if (operation === 'deep_research') { - result.input = params.research_input + if (params.research_input) result.input = params.research_input if (params.processor) result.processor = params.processor } From ca74f2912f7dadfcaf501979b4d27b35feb9acb6 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 19:39:20 -0700 Subject: [PATCH 5/6] fix(parallel): make url/title nullable in types to match transformResponse --- apps/sim/tools/parallel/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sim/tools/parallel/types.ts b/apps/sim/tools/parallel/types.ts index 0c363bd3c9..e1f1707f21 100644 --- a/apps/sim/tools/parallel/types.ts +++ b/apps/sim/tools/parallel/types.ts @@ -12,8 +12,8 @@ export interface ParallelSearchParams { } export interface ParallelSearchResult { - url: string - title: string + url: string | null + title: string | null publish_date?: string | null excerpts: string[] } @@ -34,7 +34,7 @@ export interface ParallelExtractParams { } export interface ParallelExtractResult { - url: string + url: string | null title?: string | null publish_date?: string | null excerpts?: string[] From f2a41dacf29e176d7fb3a90c8fb59fddbbbf77b1 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 19:44:38 -0700 Subject: [PATCH 6/6] fix(parallel): revert search_queries param type to string for backwards compatibility --- apps/docs/content/docs/en/tools/parallel_ai.mdx | 2 +- apps/sim/tools/parallel/search.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/docs/content/docs/en/tools/parallel_ai.mdx b/apps/docs/content/docs/en/tools/parallel_ai.mdx index c36b86a264..55dbfaf10e 100644 --- a/apps/docs/content/docs/en/tools/parallel_ai.mdx +++ b/apps/docs/content/docs/en/tools/parallel_ai.mdx @@ -44,7 +44,7 @@ Search the web using Parallel AI. Provides comprehensive search results with int | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `objective` | string | Yes | The search objective or question to answer | -| `search_queries` | json | No | Array of search queries to execute | +| `search_queries` | string | No | Comma-separated list of search queries to execute | | `mode` | string | No | Search mode: one-shot, agentic, or fast \(default: one-shot\) | | `max_results` | number | No | Maximum number of results to return \(default: 10\) | | `max_chars_per_result` | number | No | Maximum characters per result excerpt \(minimum: 1000\) | diff --git a/apps/sim/tools/parallel/search.ts b/apps/sim/tools/parallel/search.ts index b375380b08..ef73769446 100644 --- a/apps/sim/tools/parallel/search.ts +++ b/apps/sim/tools/parallel/search.ts @@ -16,10 +16,10 @@ export const searchTool: ToolConfig = { description: 'The search objective or question to answer', }, search_queries: { - type: 'json', + type: 'string', required: false, visibility: 'user-or-llm', - description: 'Array of search queries to execute', + description: 'Comma-separated list of search queries to execute', }, mode: { type: 'string',