Skip to content

Commit 96438c3

Browse files
authored
feat(tools): add firecrawl search, add conditional sub-block rendering to tool input for agents (#456)
* added firecrawl search * take into account conditional subblocks in tool input for agents * update turborepo * added docs
1 parent 10a4566 commit 96438c3

File tree

9 files changed

+244
-22
lines changed

9 files changed

+244
-22
lines changed

apps/docs/content/docs/tools/firecrawl.mdx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Firecrawl
3-
description: Scrape website content
3+
description: Scrape or search the web
44
---
55

66
import { BlockInfoCard } from "@/components/ui/block-info-card"
@@ -51,7 +51,7 @@ The Firecrawl integration allows your agents to access and process web content p
5151

5252
## Usage Instructions
5353

54-
Extract content from any website with advanced web scraping capabilities and content filtering. Retrieve clean, structured data from web pages with options to focus on main content.
54+
Extract content from any website with advanced web scraping or search the web for information. Retrieve clean, structured data from web pages with options to focus on main content, or intelligently search for information across the web.
5555

5656

5757

@@ -77,6 +77,24 @@ Extract structured content from web pages with comprehensive metadata support. C
7777
| `html` | string |
7878
| `metadata` | string |
7979

80+
### `firecrawl_search`
81+
82+
Search for information on the web using Firecrawl
83+
84+
#### Input
85+
86+
| Parameter | Type | Required | Description |
87+
| --------- | ---- | -------- | ----------- |
88+
| `apiKey` | string | Yes | Firecrawl API key |
89+
| `query` | string | Yes | The search query to use |
90+
91+
#### Output
92+
93+
| Parameter | Type |
94+
| --------- | ---- |
95+
| `data` | string |
96+
| `warning` | string |
97+
8098

8199

82100
## Block Configuration
@@ -85,7 +103,7 @@ Extract structured content from web pages with comprehensive metadata support. C
85103

86104
| Parameter | Type | Required | Description |
87105
| --------- | ---- | -------- | ----------- |
88-
| `apiKey` | string | Yes | API Key - Enter your Firecrawl API key |
106+
| `apiKey` | string | Yes | |
89107

90108

91109

@@ -97,6 +115,8 @@ Extract structured content from web pages with comprehensive metadata support. C
97115
|`markdown` | string | markdown of the response |
98116
|`html` | any | html of the response |
99117
|`metadata` | json | metadata of the response |
118+
|`data` | json | data of the response |
119+
|`warning` | any | warning of the response |
100120

101121

102122
## Notes

apps/sim/app/w/[id]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,69 @@ const getToolDisplayParams = (toolId: string): ToolParam[] => {
7777
}))
7878
}
7979

80+
// Get filtered parameters based on block conditions
81+
const getFilteredToolParams = (
82+
blockType: string,
83+
toolId: string,
84+
currentOperation?: string,
85+
toolParams?: Record<string, string>
86+
): ToolParam[] => {
87+
const tool = getTool(toolId)
88+
const block = getAllBlocks().find((block) => block.type === blockType)
89+
90+
if (!tool || !block) return []
91+
92+
const allParams = Object.entries(tool.params)
93+
.filter(([_, param]) => param.requiredForToolCall || param.optionalToolInput)
94+
.map(([paramId, param]) => ({
95+
id: paramId,
96+
type: param.type,
97+
description: param.description,
98+
requiredForToolCall: param.requiredForToolCall ?? false,
99+
optionalToolInput: param.optionalToolInput ?? false,
100+
}))
101+
102+
const evaluateCondition = (condition: any, currentValues: Record<string, any>): boolean => {
103+
const fieldValue = currentValues[condition.field]
104+
let result = false
105+
106+
if (Array.isArray(condition.value)) {
107+
result = condition.value.includes(fieldValue)
108+
} else {
109+
result = fieldValue === condition.value
110+
}
111+
112+
if (condition.not) {
113+
result = !result
114+
}
115+
116+
return result
117+
}
118+
119+
return allParams.filter((param) => {
120+
const subBlock = block.subBlocks.find((sb) => sb.id === param.id)
121+
122+
if (!subBlock || !subBlock.condition) {
123+
return true
124+
}
125+
126+
const currentValues: Record<string, any> = {
127+
operation: currentOperation,
128+
...toolParams,
129+
}
130+
131+
const condition = subBlock.condition
132+
let mainConditionResult = evaluateCondition(condition, currentValues)
133+
134+
if (condition.and) {
135+
const andConditionResult = evaluateCondition(condition.and, currentValues)
136+
mainConditionResult = mainConditionResult && andConditionResult
137+
}
138+
139+
return mainConditionResult
140+
})
141+
}
142+
80143
// Keep this for backward compatibility - only get strictly required parameters
81144
const getRequiredToolParams = (toolId: string): ToolParam[] => {
82145
const tool = getTool(toolId)
@@ -335,7 +398,9 @@ export function ToolInput({
335398
const defaultOperation = operationOptions.length > 0 ? operationOptions[0].id : undefined
336399

337400
const toolId = getToolIdFromBlock(toolBlock.type) || toolBlock.type
338-
const displayParams = toolId ? getToolDisplayParams(toolId) : []
401+
const displayParams = toolId
402+
? getFilteredToolParams(toolBlock.type, toolId, defaultOperation, {})
403+
: []
339404

340405
// Use the helper function to initialize parameters with blockId as instanceId
341406
const initialParams = initializeToolParams(
@@ -729,7 +794,7 @@ export function ToolInput({
729794
const requiredParams = isCustomTool
730795
? getCustomToolParams(tool.schema)
731796
: toolId
732-
? getRequiredToolParams(toolId)
797+
? getFilteredToolParams(tool.type, toolId, tool.operation, tool.params)
733798
: []
734799

735800
// Check if the tool has any expandable content

apps/sim/blocks/blocks/firecrawl.ts

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,62 @@
11
import { FirecrawlIcon } from '@/components/icons'
2-
import type { ScrapeResponse } from '@/tools/firecrawl/types'
2+
import type { ScrapeResponse, SearchResponse } from '@/tools/firecrawl/types'
33
import type { BlockConfig } from '../types'
44

5-
export const FirecrawlBlock: BlockConfig<ScrapeResponse> = {
5+
type FirecrawlResponse = ScrapeResponse | SearchResponse
6+
7+
export const FirecrawlBlock: BlockConfig<FirecrawlResponse> = {
68
type: 'firecrawl',
79
name: 'Firecrawl',
8-
description: 'Scrape website content',
10+
description: 'Scrape or search the web',
911
longDescription:
10-
'Extract content from any website with advanced web scraping capabilities and content filtering. Retrieve clean, structured data from web pages with options to focus on main content.',
12+
'Extract content from any website with advanced web scraping or search the web for information. Retrieve clean, structured data from web pages with options to focus on main content, or intelligently search for information across the web.',
1113
docsLink: 'https://docs.simstudio.ai/tools/firecrawl',
1214
category: 'tools',
1315
bgColor: '#181C1E',
1416
icon: FirecrawlIcon,
1517
subBlocks: [
18+
{
19+
id: 'operation',
20+
title: 'Operation',
21+
type: 'dropdown',
22+
layout: 'full',
23+
options: [
24+
{ label: 'Scrape', id: 'scrape' },
25+
{ label: 'Search', id: 'search' },
26+
],
27+
value: () => 'scrape',
28+
},
1629
{
1730
id: 'url',
1831
title: 'Website URL',
1932
type: 'short-input',
2033
layout: 'full',
2134
placeholder: 'Enter the webpage URL to scrape',
35+
condition: {
36+
field: 'operation',
37+
value: 'scrape',
38+
},
2239
},
2340
{
2441
id: 'onlyMainContent',
2542
title: 'Only Main Content',
2643
type: 'switch',
2744
layout: 'half',
45+
condition: {
46+
field: 'operation',
47+
value: 'scrape',
48+
},
49+
},
50+
{
51+
id: 'query',
52+
title: 'Search Query',
53+
type: 'short-input',
54+
layout: 'full',
55+
placeholder: 'Enter the search query',
56+
condition: {
57+
field: 'operation',
58+
value: 'search',
59+
},
2860
},
2961
{
3062
id: 'apiKey',
@@ -36,19 +68,37 @@ export const FirecrawlBlock: BlockConfig<ScrapeResponse> = {
3668
},
3769
],
3870
tools: {
39-
access: ['firecrawl_scrape'],
71+
access: ['firecrawl_scrape', 'firecrawl_search'],
72+
config: {
73+
tool: (params) => {
74+
switch (params.operation) {
75+
case 'scrape':
76+
return 'firecrawl_scrape'
77+
case 'search':
78+
return 'firecrawl_search'
79+
default:
80+
return 'firecrawl_scrape'
81+
}
82+
},
83+
},
4084
},
4185
inputs: {
4286
apiKey: { type: 'string', required: true },
43-
url: { type: 'string', required: true },
87+
operation: { type: 'string', required: true },
88+
url: { type: 'string', required: false },
89+
query: { type: 'string', required: false },
4490
scrapeOptions: { type: 'json', required: false },
4591
},
4692
outputs: {
4793
response: {
4894
type: {
95+
// Scrape output
4996
markdown: 'string',
5097
html: 'any',
5198
metadata: 'json',
99+
// Search output
100+
data: 'json',
101+
warning: 'any',
52102
},
53103
},
54104
},

apps/sim/tools/firecrawl/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import { scrapeTool } from './scrape'
2+
import { searchTool } from './search'
23

3-
export { scrapeTool }
4+
export { scrapeTool, searchTool }

apps/sim/tools/firecrawl/search.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import type { ToolConfig } from '../types'
2+
import type { SearchParams, SearchResponse } from './types'
3+
4+
export const searchTool: ToolConfig<SearchParams, SearchResponse> = {
5+
id: 'firecrawl_search',
6+
name: 'Firecrawl Search',
7+
description: 'Search for information on the web using Firecrawl',
8+
version: '1.0.0',
9+
10+
params: {
11+
apiKey: {
12+
type: 'string',
13+
required: true,
14+
requiredForToolCall: true,
15+
description: 'Firecrawl API key',
16+
},
17+
query: {
18+
type: 'string',
19+
required: true,
20+
description: 'The search query to use',
21+
},
22+
},
23+
24+
request: {
25+
method: 'POST',
26+
url: 'https://api.firecrawl.dev/v1/search',
27+
headers: (params) => ({
28+
'Content-Type': 'application/json',
29+
Authorization: `Bearer ${params.apiKey}`,
30+
}),
31+
body: (params) => ({
32+
query: params.query,
33+
}),
34+
},
35+
36+
transformResponse: async (response: Response) => {
37+
const data = await response.json()
38+
39+
if (!data.success) {
40+
throw new Error(data.error?.message || 'Unknown error occurred')
41+
}
42+
43+
return {
44+
success: true,
45+
output: {
46+
data: data.data,
47+
warning: data.warning,
48+
},
49+
}
50+
},
51+
52+
transformError: (error) => {
53+
const message = error.error?.message || error.message
54+
const code = error.error?.type || error.code
55+
return `${message} (${code})`
56+
},
57+
}

apps/sim/tools/firecrawl/types.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ export interface ScrapeParams {
99
}
1010
}
1111

12+
export interface SearchParams {
13+
apiKey: string
14+
query: string
15+
}
16+
1217
export interface ScrapeResponse extends ToolResponse {
1318
output: {
1419
markdown: string
@@ -30,3 +35,26 @@ export interface ScrapeResponse extends ToolResponse {
3035
}
3136
}
3237
}
38+
39+
export interface SearchResponse extends ToolResponse {
40+
output: {
41+
data: Array<{
42+
title: string
43+
description: string
44+
url: string
45+
markdown?: string
46+
html?: string
47+
rawHtml?: string
48+
links?: string[]
49+
screenshot?: string
50+
metadata: {
51+
title: string
52+
description: string
53+
sourceURL: string
54+
statusCode: number
55+
error?: string
56+
}
57+
}>
58+
warning?: string
59+
}
60+
}

apps/sim/tools/registry.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
import { elevenLabsTtsTool } from './elevenlabs'
1818
import { exaAnswerTool, exaFindSimilarLinksTool, exaGetContentsTool, exaSearchTool } from './exa'
1919
import { fileParseTool } from './file'
20-
import { scrapeTool } from './firecrawl'
20+
import { scrapeTool, searchTool } from './firecrawl'
2121
import { functionExecuteTool } from './function'
2222
import {
2323
githubCommentTool,
@@ -109,6 +109,7 @@ export const tools: Record<string, ToolConfig> = {
109109
vision_tool: visionTool,
110110
file_parser: fileParseTool,
111111
firecrawl_scrape: scrapeTool,
112+
firecrawl_search: searchTool,
112113
google_search: googleSearchTool,
113114
jina_read_url: readUrlTool,
114115
linkup_search: linkupSearchTool,

0 commit comments

Comments
 (0)