Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/sim/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ API_ENCRYPTION_KEY=your_api_encryption_key # Use `openssl rand -hex 32` to gener
# PEOPLEDATALABS_API_KEY_COUNT=2 # Number of People Data Labs keys for hosted PDL blocks
# PEOPLEDATALABS_API_KEY_1= # People Data Labs API key #1
# PEOPLEDATALABS_API_KEY_2= # People Data Labs API key #2
# CONTEXT_DEV_API_KEY_COUNT=2 # Number of Context.dev keys for hosted Context.dev blocks
# CONTEXT_DEV_API_KEY_1= # Context.dev API key #1
# CONTEXT_DEV_API_KEY_2= # Context.dev API key #2

# File Storage (Optional - defaults to local disk; use S3 or Azure Blob for production)
# AWS_REGION=us-east-1 # Required with S3_BUCKET_NAME to enable S3. Use "auto" for Cloudflare R2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
AnthropicIcon,
BasetenIcon,
BrandfetchIcon,
ContextDevIcon,
DatagmaIcon,
DropcontactIcon,
EnrowIcon,
Expand Down Expand Up @@ -124,6 +125,13 @@ const PROVIDERS: (BYOKManagerProvider & { id: BYOKProviderId })[] = [
description: 'AI-powered search and research',
placeholder: 'Enter your Exa API key',
},
{
id: 'context_dev',
name: 'Context.dev',
icon: ContextDevIcon,
description: 'Web scraping, crawling, search, and brand intelligence',
placeholder: 'Enter your Context.dev API key',
},
{
id: 'serper',
name: 'Serper',
Expand Down Expand Up @@ -291,6 +299,7 @@ const PROVIDER_SECTIONS: BYOKProviderSection[] = [
ids: [
'firecrawl',
'exa',
'context_dev',
'serper',
'linkup',
'parallel_ai',
Expand Down
1 change: 1 addition & 0 deletions apps/sim/blocks/blocks/context_dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ Do not include any explanations, markdown formatting, or other text outside the
placeholder: 'Enter your Context.dev API key',
password: true,
required: true,
hideWhenHosted: true,
},
],
tools: {
Expand Down
1 change: 1 addition & 0 deletions apps/sim/lib/api/contracts/byok-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const byokProviderIdSchema = z.enum([
'falai',
'firecrawl',
'exa',
'context_dev',
'serper',
'linkup',
'perplexity',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/classify_naics.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevClassifyNaicsParams,
ContextDevClassifyNaicsResponse,
Expand All @@ -22,6 +23,8 @@ export const contextDevClassifyNaicsTool: ToolConfig<
description: 'Classify a brand into NAICS industry codes from its domain or company name.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevClassifyNaicsParams>(),

params: {
input: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/classify_sic.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevClassifySicParams,
ContextDevClassifySicResponse,
Expand All @@ -22,6 +23,8 @@ export const contextDevClassifySicTool: ToolConfig<
description: 'Classify a brand into SIC industry codes from its domain or company name.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevClassifySicParams>(),

params: {
input: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/crawl.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type { ContextDevCrawlParams, ContextDevCrawlResponse } from '@/tools/context_dev/types'
import { CRAWL_RESULT_OUTPUT_PROPERTIES } from '@/tools/context_dev/types'
import {
Expand All @@ -15,6 +16,8 @@ export const contextDevCrawlTool: ToolConfig<ContextDevCrawlParams, ContextDevCr
description: 'Crawl an entire website and return each discovered page as clean markdown.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevCrawlParams>(),

params: {
url: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/extract.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type { ContextDevExtractParams, ContextDevExtractResponse } from '@/tools/context_dev/types'
import {
CONTEXT_DEV_BASE_URL,
Expand All @@ -15,6 +16,8 @@ export const contextDevExtractTool: ToolConfig<ContextDevExtractParams, ContextD
description: 'Crawl a website and extract structured data matching a provided JSON schema.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevExtractParams>(),

params: {
url: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/extract_product.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevExtractProductParams,
ContextDevExtractProductResponse,
Expand All @@ -21,6 +22,8 @@ export const contextDevExtractProductTool: ToolConfig<
description: 'Detect and extract structured product details from a single product page URL.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevExtractProductParams>(),

params: {
url: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/extract_products.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevExtractProductsParams,
ContextDevExtractProductsResponse,
Expand All @@ -21,6 +22,8 @@ export const contextDevExtractProductsTool: ToolConfig<
description: "Extract the product catalog from a brand's website by domain (beta).",
version: '1.0.0',

hosting: contextDevHosting<ContextDevExtractProductsParams>(),

params: {
domain: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/get_brand.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type { ContextDevBrandResponse, ContextDevGetBrandParams } from '@/tools/context_dev/types'
import { BRAND_OUTPUT_PROPERTIES } from '@/tools/context_dev/types'
import {
Expand All @@ -18,6 +19,8 @@ export const contextDevGetBrandTool: ToolConfig<ContextDevGetBrandParams, Contex
'Retrieve brand data for a domain: logos, colors, backdrops, socials, address, and industry.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevGetBrandParams>(),

params: {
domain: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/get_brand_by_email.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevBrandResponse,
ContextDevGetBrandByEmailParams,
Expand All @@ -23,6 +24,8 @@ export const contextDevGetBrandByEmailTool: ToolConfig<
'Retrieve brand data from a work email address. Free/disposable emails are rejected (422).',
version: '1.0.0',

hosting: contextDevHosting<ContextDevGetBrandByEmailParams>(),

params: {
email: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/get_brand_by_name.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevBrandResponse,
ContextDevGetBrandByNameParams,
Expand All @@ -23,6 +24,8 @@ export const contextDevGetBrandByNameTool: ToolConfig<
'Retrieve brand data by company name: logos, colors, socials, address, and industry.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevGetBrandByNameParams>(),

params: {
name: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/get_brand_by_ticker.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevBrandResponse,
ContextDevGetBrandByTickerParams,
Expand All @@ -22,6 +23,8 @@ export const contextDevGetBrandByTickerTool: ToolConfig<
description: 'Retrieve brand data for a public company by its stock ticker symbol.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevGetBrandByTickerParams>(),

params: {
ticker: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/get_brand_simplified.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevGetBrandSimplifiedParams,
ContextDevGetBrandSimplifiedResponse,
Expand All @@ -22,6 +23,8 @@ export const contextDevGetBrandSimplifiedTool: ToolConfig<
description: 'Retrieve essential brand data for a domain: title, colors, logos, and backdrops.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevGetBrandSimplifiedParams>(),

params: {
domain: {
type: 'string',
Expand Down
54 changes: 54 additions & 0 deletions apps/sim/tools/context_dev/hosting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import { contextDevClassifyNaicsTool } from '@/tools/context_dev/classify_naics'
import { contextDevGetBrandTool } from '@/tools/context_dev/get_brand'
import { CONTEXT_DEV_CREDIT_USD } from '@/tools/context_dev/hosting'
import { contextDevScrapeMarkdownTool } from '@/tools/context_dev/scrape_markdown'
import { contextDevScreenshotTool } from '@/tools/context_dev/screenshot'
import type { ToolConfig } from '@/tools/types'

function cost(tool: ToolConfig<any, any>, params: any, output: Record<string, unknown>) {
const pricing = tool.hosting?.pricing
if (!pricing || pricing.type !== 'custom') throw new Error('Expected custom pricing')
const result = pricing.getCost(params, output)
return typeof result === 'number' ? { cost: result } : result
}

describe('Context.dev hosted key pricing', () => {
it('declares hosting with the shared env prefix and BYOK provider on every tool', () => {
for (const tool of [
contextDevScrapeMarkdownTool,
contextDevScreenshotTool,
contextDevGetBrandTool,
contextDevClassifyNaicsTool,
]) {
expect(tool.hosting?.envKeyPrefix).toBe('CONTEXT_DEV_API_KEY')
expect(tool.hosting?.byokProviderId).toBe('context_dev')
}
})

it('charges the reported credits at the per-credit rate for a 1-credit scrape', () => {
expect(cost(contextDevScrapeMarkdownTool, {}, { creditsConsumed: 1 }).cost).toBeCloseTo(
CONTEXT_DEV_CREDIT_USD
)
})

it('charges the reported credits at the per-credit rate for a 5-credit screenshot', () => {
expect(cost(contextDevScreenshotTool, {}, { creditsConsumed: 5 }).cost).toBeCloseTo(
5 * CONTEXT_DEV_CREDIT_USD
)
})

it('charges the reported credits at the per-credit rate for a 10-credit brand lookup', () => {
expect(cost(contextDevGetBrandTool, {}, { creditsConsumed: 10 }).cost).toBeCloseTo(
10 * CONTEXT_DEV_CREDIT_USD
)
})

it('charges zero when the response has no credit accounting', () => {
expect(cost(contextDevClassifyNaicsTool, {}, { creditsConsumed: null }).cost).toBe(0)
expect(cost(contextDevClassifyNaicsTool, {}, {}).cost).toBe(0)
})
})
42 changes: 42 additions & 0 deletions apps/sim/tools/context_dev/hosting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { ToolHostingConfig } from '@/tools/types'

/**
* Env var prefix for Context.dev hosted keys. Provide keys as
* `CONTEXT_DEV_API_KEY_COUNT` plus `CONTEXT_DEV_API_KEY_1..N`.
*/
export const CONTEXT_DEV_API_KEY_PREFIX = 'CONTEXT_DEV_API_KEY'

/**
* Dollar cost of a single Context.dev credit.
*
* Estimated from the $25/month Developer plan (10,000 credits = $0.0025/credit)
* — https://www.context.dev/pricing. Endpoints cost 1, 5, or 10 credits
* depending on operation; actual usage is read from each response's
* `key_metadata.credits_consumed` rather than hardcoded per endpoint.
*/
export const CONTEXT_DEV_CREDIT_USD = 0.0025

/**
* Build a Context.dev `hosting` config. Every Context.dev response reports the
* exact credits consumed via `key_metadata.credits_consumed`, already surfaced
* on tool output as `creditsConsumed` by `extractCreditMetadata` — so cost is
* read directly from the response rather than estimated per endpoint.
*/
export function contextDevHosting<P>(): ToolHostingConfig<P> {
return {
envKeyPrefix: CONTEXT_DEV_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'context_dev',
pricing: {
type: 'custom',
getCost: (_params, output) => {
const credits = (output.creditsConsumed as number | null) ?? 0
return { cost: credits * CONTEXT_DEV_CREDIT_USD, metadata: { credits } }
},
Comment thread
waleedlatif1 marked this conversation as resolved.
Comment thread
waleedlatif1 marked this conversation as resolved.
},
rateLimit: {
mode: 'per_request',
requestsPerMinute: 60,
},
}
Comment thread
waleedlatif1 marked this conversation as resolved.
}
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/identify_transaction.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevBrandResponse,
ContextDevIdentifyTransactionParams,
Expand All @@ -23,6 +24,8 @@ export const contextDevIdentifyTransactionTool: ToolConfig<
'Identify the brand behind a raw bank/card transaction descriptor and return its brand data.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevIdentifyTransactionParams>(),

params: {
transactionInfo: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/map.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type { ContextDevMapParams, ContextDevMapResponse } from '@/tools/context_dev/types'
import {
appendParam,
Expand All @@ -15,6 +16,8 @@ export const contextDevMapTool: ToolConfig<ContextDevMapParams, ContextDevMapRes
description: 'Build a sitemap of a domain and return every discovered page URL.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevMapParams>(),

params: {
domain: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/prefetch_by_email.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevPrefetchByEmailParams,
ContextDevPrefetchResponse,
Expand All @@ -21,6 +22,8 @@ export const contextDevPrefetchByEmailTool: ToolConfig<
"Queue an email's domain for brand-data prefetching to reduce later latency (subscribers; 0 credits). Free/disposable emails are rejected.",
version: '1.0.0',

hosting: contextDevHosting<ContextDevPrefetchByEmailParams>(),

params: {
email: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/prefetch_domain.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevPrefetchDomainParams,
ContextDevPrefetchResponse,
Expand All @@ -21,6 +22,8 @@ export const contextDevPrefetchDomainTool: ToolConfig<
'Queue a domain for brand-data prefetching to reduce latency on later requests (subscribers; 0 credits).',
version: '1.0.0',

hosting: contextDevHosting<ContextDevPrefetchDomainParams>(),

params: {
domain: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/scrape_fonts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevScrapeFontsParams,
ContextDevScrapeFontsResponse,
Expand All @@ -22,6 +23,8 @@ export const contextDevScrapeFontsTool: ToolConfig<
description: 'Extract the font families, usage stats, and font files used by a domain.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevScrapeFontsParams>(),

params: {
domain: {
type: 'string',
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/tools/context_dev/scrape_html.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { contextDevHosting } from '@/tools/context_dev/hosting'
import type {
ContextDevScrapeHtmlParams,
ContextDevScrapeHtmlResponse,
Expand All @@ -21,6 +22,8 @@ export const contextDevScrapeHtmlTool: ToolConfig<
description: 'Scrape any URL and return the raw HTML content of the page.',
version: '1.0.0',

hosting: contextDevHosting<ContextDevScrapeHtmlParams>(),

params: {
url: {
type: 'string',
Expand Down
Loading
Loading