diff --git a/apps/sim/app/api/workspaces/[id]/byok-keys/route.ts b/apps/sim/app/api/workspaces/[id]/byok-keys/route.ts index ff5cdab3dd..e3f34529a2 100644 --- a/apps/sim/app/api/workspaces/[id]/byok-keys/route.ts +++ b/apps/sim/app/api/workspaces/[id]/byok-keys/route.ts @@ -18,15 +18,13 @@ const VALID_PROVIDERS = [ 'anthropic', 'google', 'mistral', - 'exa', - 'browser_use', - 'serper', 'firecrawl', + 'exa', + 'serper', 'linkup', 'perplexity', 'jina', 'google_cloud', - 'elevenlabs', 'parallel_ai', 'brandfetch', ] as const diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/byok/byok.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/byok/byok.tsx index d3d52b81d8..1f8ec4bc1e 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/components/byok/byok.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/byok/byok.tsx @@ -16,8 +16,6 @@ import { import { AnthropicIcon, BrandfetchIcon, - BrowserUseIcon, - ElevenLabsIcon, ExaAIIcon, FirecrawlIcon, GeminiIcon, @@ -77,6 +75,13 @@ const PROVIDERS: { description: 'LLM calls and Knowledge Base OCR', placeholder: 'Enter your API key', }, + { + id: 'firecrawl', + name: 'Firecrawl', + icon: FirecrawlIcon, + description: 'Web scraping, crawling, search, and extraction', + placeholder: 'Enter your Firecrawl API key', + }, { id: 'exa', name: 'Exa', @@ -84,13 +89,6 @@ const PROVIDERS: { description: 'AI-powered search and research', placeholder: 'Enter your Exa API key', }, - { - id: 'browser_use', - name: 'Browser Use', - icon: BrowserUseIcon, - description: 'Browser automation tasks', - placeholder: 'Enter your Browser Use API key', - }, { id: 'serper', name: 'Serper', @@ -98,13 +96,6 @@ const PROVIDERS: { description: 'Google search API', placeholder: 'Enter your Serper API key', }, - { - id: 'firecrawl', - name: 'Firecrawl', - icon: FirecrawlIcon, - description: 'Web scraping, crawling, and data extraction', - placeholder: 'Enter your Firecrawl API key', - }, { id: 'linkup', name: 'Linkup', @@ -133,13 +124,6 @@ const PROVIDERS: { description: 'Web reading and search', placeholder: 'jina_...', }, - { - id: 'elevenlabs', - name: 'ElevenLabs', - icon: ElevenLabsIcon, - description: 'Text-to-speech generation', - placeholder: 'Enter your ElevenLabs API key', - }, { id: 'google_cloud', name: 'Google Cloud', diff --git a/apps/sim/blocks/blocks/browser_use.ts b/apps/sim/blocks/blocks/browser_use.ts index b5d4ceec0f..267aa97299 100644 --- a/apps/sim/blocks/blocks/browser_use.ts +++ b/apps/sim/blocks/blocks/browser_use.ts @@ -72,7 +72,6 @@ export const BrowserUseBlock: BlockConfig = { password: true, placeholder: 'Enter your BrowserUse API key', required: true, - hideWhenHosted: true, }, ], tools: { diff --git a/apps/sim/blocks/blocks/elevenlabs.ts b/apps/sim/blocks/blocks/elevenlabs.ts index ee41007f67..58d79fe67a 100644 --- a/apps/sim/blocks/blocks/elevenlabs.ts +++ b/apps/sim/blocks/blocks/elevenlabs.ts @@ -48,7 +48,6 @@ export const ElevenLabsBlock: BlockConfig = { placeholder: 'Enter your ElevenLabs API key', password: true, required: true, - hideWhenHosted: true, }, ], diff --git a/apps/sim/blocks/blocks/firecrawl.ts b/apps/sim/blocks/blocks/firecrawl.ts index d1537b0c2e..add2d60ff5 100644 --- a/apps/sim/blocks/blocks/firecrawl.ts +++ b/apps/sim/blocks/blocks/firecrawl.ts @@ -249,6 +249,23 @@ Example 2 - Product Data: password: true, required: true, hideWhenHosted: true, + condition: { + field: 'operation', + value: 'agent', + not: true, + }, + }, + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + placeholder: 'Enter your Firecrawl API key', + password: true, + required: true, + condition: { + field: 'operation', + value: 'agent', + }, }, ], tools: { @@ -444,7 +461,6 @@ Example 2 - Product Data: // Crawl output pages: { type: 'json', description: 'Crawled pages data' }, total: { type: 'number', description: 'Total pages found' }, - creditsUsed: { type: 'number', description: 'Credits consumed' }, // Map output success: { type: 'boolean', description: 'Operation success status' }, links: { type: 'json', description: 'Discovered URLs array' }, diff --git a/apps/sim/blocks/blocks/mistral_parse.ts b/apps/sim/blocks/blocks/mistral_parse.ts index 01f6fdc4fa..d7bb020a1b 100644 --- a/apps/sim/blocks/blocks/mistral_parse.ts +++ b/apps/sim/blocks/blocks/mistral_parse.ts @@ -68,6 +68,7 @@ export const MistralParseBlock: BlockConfig = { placeholder: 'Enter your Mistral API key', password: true, required: true, + hideWhenHosted: true, }, ], tools: { @@ -75,13 +76,12 @@ export const MistralParseBlock: BlockConfig = { config: { tool: () => 'mistral_parser', params: (params) => { - if (!params || !params.apiKey || params.apiKey.trim() === '') { - throw new Error('Mistral API key is required') + const parameters: Record = { + resultType: params.resultType || 'markdown', } - const parameters: Record = { - apiKey: params.apiKey.trim(), - resultType: params.resultType || 'markdown', + if (params.apiKey?.trim()) { + parameters.apiKey = params.apiKey.trim() } const inputMethod = params.inputMethod || 'url' @@ -195,6 +195,7 @@ export const MistralParseV2Block: BlockConfig = { placeholder: 'Enter your Mistral API key', password: true, required: true, + hideWhenHosted: true, }, ], tools: { @@ -206,13 +207,12 @@ export const MistralParseV2Block: BlockConfig = { fallbackToolId: 'mistral_parser_v2', }), params: (params) => { - if (!params || !params.apiKey || params.apiKey.trim() === '') { - throw new Error('Mistral API key is required') + const parameters: Record = { + resultType: params.resultType || 'markdown', } - const parameters: Record = { - apiKey: params.apiKey.trim(), - resultType: params.resultType || 'markdown', + if (params.apiKey?.trim()) { + parameters.apiKey = params.apiKey.trim() } // Use canonical document param directly diff --git a/apps/sim/tools/browser_use/run_task.ts b/apps/sim/tools/browser_use/run_task.ts index fd24b3ce05..9422282a00 100644 --- a/apps/sim/tools/browser_use/run_task.ts +++ b/apps/sim/tools/browser_use/run_task.ts @@ -1,6 +1,5 @@ import { createLogger } from '@sim/logger' import { getMaxExecutionTimeout } from '@/lib/core/execution-limits' -import { PlatformEvents } from '@/lib/core/telemetry' import type { BrowserUseRunTaskParams, BrowserUseRunTaskResponse } from '@/tools/browser_use/types' import type { ToolConfig, ToolResponse } from '@/tools/types' @@ -257,62 +256,6 @@ export const runTaskTool: ToolConfig { - if (!Array.isArray(output.steps)) { - throw new Error('Browser Use response missing steps array, cannot determine cost') - } - const INIT_COST = 0.01 - const STEP_COSTS: Record = { - 'browser-use-llm': 0.002, - 'browser-use-2.0': 0.006, - o3: 0.03, - 'o4-mini': 0.03, - 'gemini-3-pro-preview': 0.03, - 'gemini-3-flash-preview': 0.015, - 'gemini-flash-latest': 0.0075, - 'gemini-flash-lite-latest': 0.005, - 'gemini-2.5-flash': 0.0075, - 'gemini-2.5-pro': 0.03, - 'claude-sonnet-4-5-20250929': 0.05, - 'claude-opus-4-5-20251101': 0.05, - 'claude-3-7-sonnet-20250219': 0.05, - 'gpt-4o': 0.006, - 'gpt-4o-mini': 0.006, - 'gpt-4.1': 0.006, - 'gpt-4.1-mini': 0.006, - 'llama-4-maverick-17b-128e-instruct': 0.006, - } - const DEFAULT_STEP_COST = 0.006 - const model = (params.model as string) || 'browser-use-2.0' - const knownCost = STEP_COSTS[model] - if (!knownCost) { - logger.warn( - `Unknown Browser Use model "${model}", using default step cost $${DEFAULT_STEP_COST}` - ) - PlatformEvents.hostedKeyUnknownModelCost({ - toolId: 'browser_use_run_task', - modelName: model, - defaultCost: DEFAULT_STEP_COST, - }) - } - const stepCost = knownCost ?? DEFAULT_STEP_COST - const stepCount = output.steps.length - const total = INIT_COST + stepCount * stepCost - return { cost: total, metadata: { model, stepCount, stepCost, initCost: INIT_COST } } - }, - }, - rateLimit: { - mode: 'per_request', - requestsPerMinute: 100, - }, - }, - request: { url: 'https://api.browser-use.com/api/v2/tasks', method: 'POST', diff --git a/apps/sim/tools/elevenlabs/constants.ts b/apps/sim/tools/elevenlabs/constants.ts deleted file mode 100644 index fc0dd62da4..0000000000 --- a/apps/sim/tools/elevenlabs/constants.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const FLASH_TURBO_MODELS = new Set([ - 'eleven_turbo_v2', - 'eleven_turbo_v2_5', - 'eleven_flash_v2_5', -]) diff --git a/apps/sim/tools/elevenlabs/tts.ts b/apps/sim/tools/elevenlabs/tts.ts index bab31a5e3f..e0a42e010c 100644 --- a/apps/sim/tools/elevenlabs/tts.ts +++ b/apps/sim/tools/elevenlabs/tts.ts @@ -1,4 +1,3 @@ -import { FLASH_TURBO_MODELS } from '@/tools/elevenlabs/constants' import type { ElevenLabsTtsParams, ElevenLabsTtsResponse } from '@/tools/elevenlabs/types' import type { ToolConfig } from '@/tools/types' @@ -8,32 +7,6 @@ export const elevenLabsTtsTool: ToolConfig { - const text = params.text as string | undefined - if (!text) { - throw new Error('Missing text parameter, cannot determine character cost') - } - const characterCount = text.length - const modelId = (params.modelId as string) || 'eleven_monolingual_v1' - // Flash/Turbo: $0.08/1K chars, Standard/Multilingual/v3: $0.18/1K chars - // Scale tier additional character rates — https://elevenlabs.io/pricing/api - const costPer1KChars = FLASH_TURBO_MODELS.has(modelId) ? 0.08 : 0.18 - const cost = (characterCount / 1000) * costPer1KChars - return { cost, metadata: { characterCount, modelId, costPer1KChars } } - }, - }, - rateLimit: { - mode: 'per_request', - requestsPerMinute: 30, - }, - }, - params: { text: { type: 'string', diff --git a/apps/sim/tools/firecrawl/agent.ts b/apps/sim/tools/firecrawl/agent.ts index 3ecddfbf37..1a8dc959bf 100644 --- a/apps/sim/tools/firecrawl/agent.ts +++ b/apps/sim/tools/firecrawl/agent.ts @@ -55,27 +55,6 @@ export const agentTool: ToolConfig = { }, }, - hosting: { - envKeyPrefix: 'FIRECRAWL_API_KEY', - apiKeyParam: 'apiKey', - byokProviderId: 'firecrawl', - pricing: { - type: 'custom', - getCost: (_params, output) => { - if (output.creditsUsed == null) { - throw new Error('Firecrawl agent response missing creditsUsed field') - } - const creditsUsed = output.creditsUsed as number - const cost = creditsUsed * 0.001 - return { cost, metadata: { creditsUsed } } - }, - }, - rateLimit: { - mode: 'per_request', - requestsPerMinute: 100, - }, - }, - request: { method: 'POST', url: 'https://api.firecrawl.dev/v2/agent', @@ -210,10 +189,6 @@ export const agentTool: ToolConfig = { type: 'object', description: 'Extracted data from the agent', }, - creditsUsed: { - type: 'number', - description: 'Number of credits consumed by this agent task', - }, expiresAt: { type: 'string', description: 'Timestamp when the results expire (24 hours)', diff --git a/apps/sim/tools/firecrawl/crawl.ts b/apps/sim/tools/firecrawl/crawl.ts index 9d7d010580..bb2eae5b17 100644 --- a/apps/sim/tools/firecrawl/crawl.ts +++ b/apps/sim/tools/firecrawl/crawl.ts @@ -77,11 +77,18 @@ export const crawlTool: ToolConfig type: 'custom', getCost: (_params, output) => { if (output.creditsUsed == null) { - throw new Error('Firecrawl crawl response missing creditsUsed field') + throw new Error('Firecrawl response missing creditsUsed field') + } + + const creditsUsed = Number(output.creditsUsed) + if (Number.isNaN(creditsUsed)) { + throw new Error('Firecrawl response returned a non-numeric creditsUsed field') + } + + return { + cost: creditsUsed * 0.001, + metadata: { creditsUsed }, } - const creditsUsed = output.creditsUsed as number - const cost = creditsUsed * 0.001 - return { cost, metadata: { creditsUsed } } }, }, rateLimit: { @@ -222,9 +229,5 @@ export const crawlTool: ToolConfig }, }, total: { type: 'number', description: 'Total number of pages found during crawl' }, - creditsUsed: { - type: 'number', - description: 'Number of credits consumed by the crawl operation', - }, }, } diff --git a/apps/sim/tools/firecrawl/extract.ts b/apps/sim/tools/firecrawl/extract.ts index 97e763b814..db41780af1 100644 --- a/apps/sim/tools/firecrawl/extract.ts +++ b/apps/sim/tools/firecrawl/extract.ts @@ -87,11 +87,18 @@ export const extractTool: ToolConfig = { type: 'custom', getCost: (_params, output) => { if (output.creditsUsed == null) { - throw new Error('Firecrawl extract response missing creditsUsed field') + throw new Error('Firecrawl response missing creditsUsed field') + } + + const creditsUsed = Number(output.creditsUsed) + if (Number.isNaN(creditsUsed)) { + throw new Error('Firecrawl response returned a non-numeric creditsUsed field') + } + + return { + cost: creditsUsed * 0.001, + metadata: { creditsUsed }, } - const creditsUsed = output.creditsUsed as number - const cost = creditsUsed * 0.001 - return { cost, metadata: { creditsUsed } } }, }, rateLimit: { @@ -233,9 +240,5 @@ export const extractTool: ToolConfig = { type: 'object', description: 'Extracted structured data according to the schema or prompt', }, - creditsUsed: { - type: 'number', - description: 'Number of Firecrawl credits consumed by the extraction', - }, }, } diff --git a/apps/sim/tools/firecrawl/map.ts b/apps/sim/tools/firecrawl/map.ts index b88b78a0a4..e5a507556e 100644 --- a/apps/sim/tools/firecrawl/map.ts +++ b/apps/sim/tools/firecrawl/map.ts @@ -74,11 +74,18 @@ export const mapTool: ToolConfig = { type: 'custom', getCost: (_params, output) => { if (output.creditsUsed == null) { - throw new Error('Firecrawl map response missing creditsUsed field') + throw new Error('Firecrawl response missing creditsUsed field') + } + + const creditsUsed = Number(output.creditsUsed) + if (Number.isNaN(creditsUsed)) { + throw new Error('Firecrawl response returned a non-numeric creditsUsed field') + } + + return { + cost: creditsUsed * 0.001, + metadata: { creditsUsed }, } - const creditsUsed = output.creditsUsed as number - const cost = creditsUsed * 0.001 - return { cost, metadata: { creditsUsed } } }, }, rateLimit: { @@ -121,7 +128,7 @@ export const mapTool: ToolConfig = { output: { success: data.success, links: data.links || [], - creditsUsed: data.creditsUsed, + creditsUsed: 1, }, } }, @@ -138,6 +145,5 @@ export const mapTool: ToolConfig = { type: 'string', }, }, - creditsUsed: { type: 'number', description: 'Number of Firecrawl credits consumed' }, }, } diff --git a/apps/sim/tools/firecrawl/scrape.ts b/apps/sim/tools/firecrawl/scrape.ts index d23f8483a2..ed0a19aef4 100644 --- a/apps/sim/tools/firecrawl/scrape.ts +++ b/apps/sim/tools/firecrawl/scrape.ts @@ -39,11 +39,18 @@ export const scrapeTool: ToolConfig = { type: 'custom', getCost: (_params, output) => { if (output.creditsUsed == null) { - throw new Error('Firecrawl scrape response missing creditsUsed field') + throw new Error('Firecrawl response missing creditsUsed field') + } + + const creditsUsed = Number(output.creditsUsed) + if (Number.isNaN(creditsUsed)) { + throw new Error('Firecrawl response returned a non-numeric creditsUsed field') + } + + return { + cost: creditsUsed * 0.001, + metadata: { creditsUsed }, } - const creditsUsed = output.creditsUsed as number - const cost = creditsUsed * 0.001 - return { cost, metadata: { creditsUsed } } }, }, rateLimit: { @@ -116,6 +123,5 @@ export const scrapeTool: ToolConfig = { description: 'Page metadata including SEO and Open Graph information', properties: PAGE_METADATA_OUTPUT_PROPERTIES, }, - creditsUsed: { type: 'number', description: 'Number of Firecrawl credits consumed' }, }, } diff --git a/apps/sim/tools/firecrawl/search.ts b/apps/sim/tools/firecrawl/search.ts index f5222985b2..38f93955a2 100644 --- a/apps/sim/tools/firecrawl/search.ts +++ b/apps/sim/tools/firecrawl/search.ts @@ -31,11 +31,18 @@ export const searchTool: ToolConfig = { type: 'custom', getCost: (_params, output) => { if (output.creditsUsed == null) { - throw new Error('Firecrawl search response missing creditsUsed field') + throw new Error('Firecrawl response missing creditsUsed field') + } + + const creditsUsed = Number(output.creditsUsed) + if (Number.isNaN(creditsUsed)) { + throw new Error('Firecrawl response returned a non-numeric creditsUsed field') + } + + return { + cost: creditsUsed * 0.001, + metadata: { creditsUsed }, } - const creditsUsed = output.creditsUsed as number - const cost = creditsUsed * 0.001 - return { cost, metadata: { creditsUsed } } }, }, rateLimit: { @@ -93,6 +100,5 @@ export const searchTool: ToolConfig = { properties: SEARCH_RESULT_OUTPUT_PROPERTIES, }, }, - creditsUsed: { type: 'number', description: 'Number of Firecrawl credits consumed' }, }, } diff --git a/apps/sim/tools/firecrawl/types.ts b/apps/sim/tools/firecrawl/types.ts index 1853891ce4..ff2a44fe2b 100644 --- a/apps/sim/tools/firecrawl/types.ts +++ b/apps/sim/tools/firecrawl/types.ts @@ -167,7 +167,6 @@ export const CRAWL_OUTPUT_PROPERTIES = { }, }, total: { type: 'number', description: 'Total number of pages found during crawl' }, - creditsUsed: { type: 'number', description: 'Number of credits consumed by the crawl operation' }, } as const satisfies Record /** @@ -274,11 +273,6 @@ export const AGENT_OUTPUT_PROPERTIES = { type: 'object', description: 'Extracted data from the agent based on the prompt and schema', }, - creditsUsed: { - type: 'number', - description: 'Number of credits consumed by this agent task', - optional: true, - }, expiresAt: { type: 'string', description: 'ISO timestamp when the results expire (24 hours after completion)', @@ -448,7 +442,7 @@ export interface ScrapeResponse extends ToolResponse { statusCode: number error?: string } - creditsUsed: number + creditsUsed?: number } } @@ -471,7 +465,7 @@ export interface SearchResponse extends ToolResponse { error?: string } }> - creditsUsed: number + creditsUsed?: number } } @@ -494,7 +488,7 @@ export interface FirecrawlCrawlResponse extends ToolResponse { } }> total: number - creditsUsed: number + creditsUsed?: number } } @@ -502,7 +496,7 @@ export interface MapResponse extends ToolResponse { output: { success: boolean links: string[] - creditsUsed: number + creditsUsed?: number } } diff --git a/apps/sim/tools/mistral/parser.ts b/apps/sim/tools/mistral/parser.ts index c2727c235d..c4277dd560 100644 --- a/apps/sim/tools/mistral/parser.ts +++ b/apps/sim/tools/mistral/parser.ts @@ -16,15 +16,21 @@ const MISTRAL_OCR_HOSTING = { byokProviderId: 'mistral' as const, pricing: { type: 'custom' as const, - getCost: (_params: Record, output: Record) => { - // Mistral OCR: $2 per 1,000 pages ($0.002/page) for real-time API - // Batch inference is $1/1K pages but we call the real-time endpoint - // https://mistral.ai/pricing#api - const usageInfo = output.usage_info as { pages_processed?: number } | undefined - if (usageInfo?.pages_processed == null) { - throw new Error('Mistral OCR response missing pages_processed in usage_info') + getCost: (_params: unknown, output: Record) => { + // Mistral OCR 3 standard pricing: $2 per 1,000 pages ($0.002/page). + // Annotated pages are priced separately at $3 per 1,000 annotated pages, but this tool does + // not submit annotation requests. Source: https://docs.mistral.ai/models/ocr-3-25-12 + const rawUsageInfo = output.usage_info as { pages_processed?: number } | undefined + const transformedUsageInfo = ( + output.metadata as { usageInfo?: { pagesProcessed?: number } } | undefined + )?.usageInfo + const pagesProcessed = rawUsageInfo?.pages_processed ?? transformedUsageInfo?.pagesProcessed + + if (pagesProcessed == null) { + throw new Error( + 'Mistral OCR response missing pages_processed in usage_info or metadata.usageInfo.pagesProcessed' + ) } - const pagesProcessed = usageInfo.pages_processed const cost = pagesProcessed * 0.002 return { cost, metadata: { pagesProcessed } } }, @@ -40,6 +46,7 @@ export const mistralParserTool: ToolConfig { - const text = params.text as string | undefined - if (!text) { - throw new Error('Missing text parameter, cannot determine character cost') - } - const characterCount = text.length - const modelId = (params.modelId as string) || 'eleven_turbo_v2_5' - // Flash/Turbo: $0.08/1K chars, Standard/Multilingual/v3: $0.18/1K chars - // Scale tier additional character rates — https://elevenlabs.io/pricing/api - const costPer1KChars = FLASH_TURBO_MODELS.has(modelId) ? 0.08 : 0.18 - const cost = (characterCount / 1000) * costPer1KChars - return { cost, metadata: { characterCount, modelId, costPer1KChars } } - }, - }, - rateLimit: { - mode: 'per_request', - requestsPerMinute: 30, - }, - }, - params: { text: { type: 'string', diff --git a/apps/sim/tools/types.ts b/apps/sim/tools/types.ts index e491b12b8b..10382636b4 100644 --- a/apps/sim/tools/types.ts +++ b/apps/sim/tools/types.ts @@ -6,12 +6,10 @@ export type BYOKProviderId = | 'anthropic' | 'google' | 'mistral' - | 'exa' - | 'browser_use' - | 'serper' | 'firecrawl' + | 'exa' + | 'serper' | 'jina' - | 'elevenlabs' | 'perplexity' | 'google_cloud' | 'linkup'