Skip to content
Merged
39 changes: 39 additions & 0 deletions apps/sim/app/api/tools/firecrawl/crawl/[jobId]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { type NextRequest, NextResponse } from 'next/server'

export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ jobId: string }> }
) {
const { jobId } = await params
const authHeader = request.headers.get('authorization')

if (!authHeader) {
return NextResponse.json({ error: 'Authorization header is required' }, { status: 401 })
}

try {
const response = await fetch(`https://api.firecrawl.dev/v1/crawl/${jobId}`, {
method: 'GET',
headers: {
Authorization: authHeader,
'Content-Type': 'application/json',
},
})

const data = await response.json()

if (!response.ok) {
return NextResponse.json(
{ error: data.error || data.message || 'Failed to get crawl status' },
{ status: response.status }
)
}

return NextResponse.json(data)
} catch (error: any) {
return NextResponse.json(
{ error: `Failed to fetch crawl status: ${error.message}` },
{ status: 500 }
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import type { SubBlockConfig } from '@/blocks/types'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
import { useSubBlockValue } from '../../hooks/use-sub-block-value'
import { type SlackChannelInfo, SlackChannelSelector } from './components/slack-channel-selector'

interface ChannelSelectorInputProps {
Expand All @@ -25,7 +26,10 @@ export function ChannelSelectorInput({
isPreview = false,
previewValue,
}: ChannelSelectorInputProps) {
const { getValue, setValue } = useSubBlockStore()
const { getValue } = useSubBlockStore()

// Use the proper hook to get the current value and setter (same as file-selector)
const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlock.id)
const [selectedChannelId, setSelectedChannelId] = useState<string>('')
const [_channelInfo, setChannelInfo] = useState<SlackChannelInfo | null>(null)

Expand All @@ -47,9 +51,9 @@ export function ChannelSelectorInput({
}

// Use preview value when in preview mode, otherwise use store value
const value = isPreview ? previewValue : getValue(blockId, subBlock.id)
const value = isPreview ? previewValue : storeValue

// Get the current value from the store or prop value if in preview mode
// Get the current value from the store or prop value if in preview mode (same pattern as file-selector)
useEffect(() => {
if (isPreview && previewValue !== undefined) {
const value = previewValue
Expand All @@ -64,12 +68,12 @@ export function ChannelSelectorInput({
}
}, [blockId, subBlock.id, getValue, isPreview, previewValue])

// Handle channel selection
// Handle channel selection (same pattern as file-selector)
const handleChannelChange = (channelId: string, info?: SlackChannelInfo) => {
setSelectedChannelId(channelId)
setChannelInfo(info || null)
if (!isPreview) {
setValue(blockId, subBlock.id, channelId)
setStoreValue(channelId)
}
onChannelSelect?.(channelId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ const SCOPE_DESCRIPTIONS: Record<string, string> = {
'guilds.members.read': 'Read your Discord guild members',
read: 'Read access to your workspace',
write: 'Write access to your Linear workspace',
'channels:read': 'Read your Slack channels',
'groups:read': 'Read your Slack private channels',
'chat:write': 'Write to your invited Slack channels',
'chat:write.public': 'Write to your public Slack channels',
'users:read': 'Read your Slack users',
'search:read': 'Read your Slack search',
'files:read': 'Read your Slack files',
'links:read': 'Read your Slack links',
'links:write': 'Write to your Slack links',
'channels:read': 'View public channels',
'channels:history': 'Read channel messages',
'groups:read': 'View private channels',
'groups:history': 'Read private messages',
'chat:write': 'Send messages',
'chat:write.public': 'Post to public channels',
'users:read': 'View workspace users',
'files:write': 'Upload files',
'canvases:write': 'Create canvas documents',
}

// Convert OAuth scope to user-friendly description
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1006,9 +1006,9 @@ export function ToolInput({
case 'channel-selector':
return (
<ChannelSelectorInput
blockId={uniqueBlockId}
blockId={blockId}
subBlock={{
id: param.id,
id: `tool-${toolIndex || 0}-${param.id}`,
type: 'channel-selector' as const,
title: param.id,
provider: uiComponent.provider || 'slack',
Expand All @@ -1023,9 +1023,9 @@ export function ToolInput({
case 'project-selector':
return (
<ProjectSelectorInput
blockId={uniqueBlockId}
blockId={blockId}
subBlock={{
id: param.id,
id: `tool-${toolIndex || 0}-${param.id}`,
type: 'project-selector' as const,
title: param.id,
provider: uiComponent.provider || 'jira',
Expand Down Expand Up @@ -1632,7 +1632,7 @@ export function ToolInput({
{param.required && param.visibility === 'user-only' && (
<span className='ml-1 text-red-500'>*</span>
)}
{!param.required && (
{(!param.required || param.visibility !== 'user-only') && (
<span className='ml-1 text-muted-foreground/60 text-xs'>
(Optional)
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -896,4 +896,4 @@ export function SearchModal({
</DialogPortal>
</Dialog>
)
}
}
30 changes: 28 additions & 2 deletions apps/sim/blocks/blocks/exa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
bgColor: '#1F40ED',
icon: ExaAIIcon,
subBlocks: [
// Operation selector
{
id: 'operation',
title: 'Operation',
Expand All @@ -24,6 +23,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
{ label: 'Get Contents', id: 'exa_get_contents' },
{ label: 'Find Similar Links', id: 'exa_find_similar_links' },
{ label: 'Answer', id: 'exa_answer' },
{ label: 'Research', id: 'exa_research' },
],
value: () => 'exa_search',
},
Expand Down Expand Up @@ -129,6 +129,22 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
layout: 'full',
condition: { field: 'operation', value: 'exa_answer' },
},
// Research operation inputs
{
id: 'query',
title: 'Research Query',
type: 'long-input',
layout: 'full',
placeholder: 'Enter your research topic or question...',
condition: { field: 'operation', value: 'exa_research' },
},
{
id: 'includeText',
title: 'Include Full Text',
type: 'switch',
layout: 'full',
condition: { field: 'operation', value: 'exa_research' },
},
// API Key (common)
{
id: 'apiKey',
Expand All @@ -140,7 +156,13 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
},
],
tools: {
access: ['exa_search', 'exa_get_contents', 'exa_find_similar_links', 'exa_answer'],
access: [
'exa_search',
'exa_get_contents',
'exa_find_similar_links',
'exa_answer',
'exa_research',
],
config: {
tool: (params) => {
// Convert numResults to a number for operations that use it
Expand All @@ -157,6 +179,8 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
return 'exa_find_similar_links'
case 'exa_answer':
return 'exa_answer'
case 'exa_research':
return 'exa_research'
default:
return 'exa_search'
}
Expand Down Expand Up @@ -186,5 +210,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
// Answer output
answer: 'string',
citations: 'json',
// Research output
research: 'json',
},
}
38 changes: 35 additions & 3 deletions apps/sim/blocks/blocks/firecrawl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const FirecrawlBlock: BlockConfig<FirecrawlResponse> = {
options: [
{ label: 'Scrape', id: 'scrape' },
{ label: 'Search', id: 'search' },
{ label: 'Crawl', id: 'crawl' },
],
value: () => 'scrape',
},
Expand All @@ -29,10 +30,10 @@ export const FirecrawlBlock: BlockConfig<FirecrawlResponse> = {
title: 'Website URL',
type: 'short-input',
layout: 'full',
placeholder: 'Enter the webpage URL to scrape',
placeholder: 'Enter the website URL',
condition: {
field: 'operation',
value: 'scrape',
value: ['scrape', 'crawl'],
},
},
{
Expand All @@ -45,6 +46,17 @@ export const FirecrawlBlock: BlockConfig<FirecrawlResponse> = {
value: 'scrape',
},
},
{
id: 'limit',
title: 'Page Limit',
type: 'short-input',
layout: 'half',
placeholder: '100',
condition: {
field: 'operation',
value: 'crawl',
},
},
{
id: 'query',
title: 'Search Query',
Expand All @@ -66,24 +78,40 @@ export const FirecrawlBlock: BlockConfig<FirecrawlResponse> = {
},
],
tools: {
access: ['firecrawl_scrape', 'firecrawl_search'],
access: ['firecrawl_scrape', 'firecrawl_search', 'firecrawl_crawl'],
config: {
tool: (params) => {
switch (params.operation) {
case 'scrape':
return 'firecrawl_scrape'
case 'search':
return 'firecrawl_search'
case 'crawl':
return 'firecrawl_crawl'
default:
return 'firecrawl_scrape'
}
},
params: (params) => {
const { operation, limit, ...rest } = params

switch (operation) {
case 'crawl':
return {
...rest,
limit: limit ? Number.parseInt(limit) : undefined,
}
default:
return rest
}
},
},
},
inputs: {
apiKey: { type: 'string', required: true },
operation: { type: 'string', required: true },
url: { type: 'string', required: false },
limit: { type: 'string', required: false },
query: { type: 'string', required: false },
scrapeOptions: { type: 'json', required: false },
},
Expand All @@ -95,5 +123,9 @@ export const FirecrawlBlock: BlockConfig<FirecrawlResponse> = {
// Search output
data: 'json',
warning: 'any',
// Crawl output
pages: 'json',
total: 'number',
creditsUsed: 'number',
},
}
Loading
Loading