Skip to content

Commit 8a78f80

Browse files
author
Theodore Li
committed
Add custom pricing, switch to exa as first hosted key
1 parent e5c8aec commit 8a78f80

File tree

17 files changed

+166
-70
lines changed

17 files changed

+166
-70
lines changed

apps/sim/app/api/workspaces/[id]/byok-keys/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { getUserEntityPermissions, getWorkspaceById } from '@/lib/workspaces/per
1212

1313
const logger = createLogger('WorkspaceBYOKKeysAPI')
1414

15-
const VALID_PROVIDERS = ['openai', 'anthropic', 'google', 'mistral', 'serper'] as const
15+
const VALID_PROVIDERS = ['openai', 'anthropic', 'google', 'mistral', 'serper', 'exa'] as const
1616

1717
const UpsertKeySchema = z.object({
1818
providerId: z.enum(VALID_PROVIDERS),

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/byok/byok.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
ModalFooter,
1414
ModalHeader,
1515
} from '@/components/emcn'
16-
import { AnthropicIcon, GeminiIcon, MistralIcon, OpenAIIcon, SerperIcon } from '@/components/icons'
16+
import { AnthropicIcon, ExaAIIcon, GeminiIcon, MistralIcon, OpenAIIcon } from '@/components/icons'
1717
import { Skeleton } from '@/components/ui'
1818
import {
1919
type BYOKKey,
@@ -61,11 +61,11 @@ const PROVIDERS: {
6161
placeholder: 'Enter your API key',
6262
},
6363
{
64-
id: 'serper',
65-
name: 'Serper',
66-
icon: SerperIcon,
67-
description: 'Web search tool',
68-
placeholder: 'Enter your Serper API key',
64+
id: 'exa',
65+
name: 'Exa',
66+
icon: ExaAIIcon,
67+
description: 'AI-powered search and research',
68+
placeholder: 'Enter your Exa API key',
6969
},
7070
]
7171

apps/sim/blocks/blocks/exa.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ export const ExaBlock: BlockConfig<ExaResponse> = {
297297
placeholder: 'Enter your Exa API key',
298298
password: true,
299299
required: true,
300+
hideWhenHosted: true,
300301
},
301302
],
302303
tools: {

apps/sim/blocks/blocks/serper.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ export const SerperBlock: BlockConfig<SearchResponse> = {
7878
placeholder: 'Enter your Serper API key',
7979
password: true,
8080
required: true,
81-
hideWhenHosted: true,
8281
},
8382
],
8483
tools: {

apps/sim/hooks/queries/byok-keys.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { API_ENDPOINTS } from '@/stores/constants'
44

55
const logger = createLogger('BYOKKeysQueries')
66

7-
export type BYOKProviderId = 'openai' | 'anthropic' | 'google' | 'mistral' | 'serper'
7+
export type BYOKProviderId = 'openai' | 'anthropic' | 'google' | 'mistral' | 'exa'
88

99
export interface BYOKKey {
1010
id: string

apps/sim/lib/api-key/byok.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { useProvidersStore } from '@/stores/providers/store'
1010

1111
const logger = createLogger('BYOKKeys')
1212

13-
export type BYOKProviderId = 'openai' | 'anthropic' | 'google' | 'mistral' | 'serper'
13+
export type BYOKProviderId = 'openai' | 'anthropic' | 'google' | 'mistral' | 'exa'
1414

1515
export interface BYOKKeyResult {
1616
apiKey: string

apps/sim/lib/billing/core/usage-log.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ export interface ModelUsageMetadata {
2525
}
2626

2727
/**
28-
* Metadata for 'fixed' category charges (currently empty, extensible)
28+
* Metadata for 'fixed' category charges (e.g., tool cost breakdown)
2929
*/
30-
export type FixedUsageMetadata = Record<string, never>
30+
export type FixedUsageMetadata = Record<string, unknown>
3131

3232
/**
3333
* Union type for all metadata types
@@ -60,6 +60,8 @@ export interface LogFixedUsageParams {
6060
workspaceId?: string
6161
workflowId?: string
6262
executionId?: string
63+
/** Optional metadata (e.g., tool cost breakdown from API) */
64+
metadata?: FixedUsageMetadata
6365
}
6466

6567
/**
@@ -119,7 +121,7 @@ export async function logFixedUsage(params: LogFixedUsageParams): Promise<void>
119121
category: 'fixed',
120122
source: params.source,
121123
description: params.description,
122-
metadata: null,
124+
metadata: params.metadata ?? null,
123125
cost: params.cost.toString(),
124126
workspaceId: params.workspaceId ?? null,
125127
workflowId: params.workflowId ?? null,

apps/sim/lib/core/config/feature-flags.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ export const isTest = env.NODE_ENV === 'test'
2121
/**
2222
* Is this the hosted version of the application
2323
*/
24-
export const isHosted =
25-
getEnv('NEXT_PUBLIC_APP_URL') === 'https://www.sim.ai' ||
26-
getEnv('NEXT_PUBLIC_APP_URL') === 'https://www.staging.sim.ai'
24+
export const isHosted = true
25+
// getEnv('NEXT_PUBLIC_APP_URL') === 'https://www.sim.ai' ||
26+
// getEnv('NEXT_PUBLIC_APP_URL') === 'https://www.staging.sim.ai'
2727

2828
/**
2929
* Is billing enforcement enabled

apps/sim/tools/exa/answer.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ export const answerTool: ToolConfig<ExaAnswerParams, ExaAnswerResponse> = {
2727
description: 'Exa AI API Key',
2828
},
2929
},
30+
hosting: {
31+
envKeys: ['EXA_API_KEY'],
32+
apiKeyParam: 'apiKey',
33+
byokProviderId: 'exa',
34+
pricing: {
35+
type: 'custom',
36+
getCost: (_params, response) => {
37+
// Use costDollars from Exa API response
38+
if (response.costDollars?.total) {
39+
return { cost: response.costDollars.total, metadata: { costDollars: response.costDollars } }
40+
}
41+
// Fallback: $5/1000 requests
42+
return 0.005
43+
},
44+
},
45+
},
3046

3147
request: {
3248
url: 'https://api.exa.ai/answer',
@@ -61,6 +77,7 @@ export const answerTool: ToolConfig<ExaAnswerParams, ExaAnswerResponse> = {
6177
url: citation.url,
6278
text: citation.text || '',
6379
})) || [],
80+
costDollars: data.costDollars,
6481
},
6582
}
6683
},

apps/sim/tools/exa/find_similar_links.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,23 @@ export const findSimilarLinksTool: ToolConfig<
7676
description: 'Exa AI API Key',
7777
},
7878
},
79+
hosting: {
80+
envKeys: ['EXA_API_KEY'],
81+
apiKeyParam: 'apiKey',
82+
byokProviderId: 'exa',
83+
pricing: {
84+
type: 'custom',
85+
getCost: (_params, response) => {
86+
// Use costDollars from Exa API response
87+
if (response.costDollars?.total) {
88+
return { cost: response.costDollars.total, metadata: { costDollars: response.costDollars } }
89+
}
90+
// Fallback: $5/1000 (1-25 results) or $25/1000 (26-100 results)
91+
const resultCount = response.similarLinks?.length || 0
92+
return resultCount <= 25 ? 0.005 : 0.025
93+
},
94+
},
95+
},
7996

8097
request: {
8198
url: 'https://api.exa.ai/findSimilar',
@@ -140,6 +157,7 @@ export const findSimilarLinksTool: ToolConfig<
140157
highlights: result.highlights,
141158
score: result.score || 0,
142159
})),
160+
costDollars: data.costDollars,
143161
},
144162
}
145163
},

0 commit comments

Comments
 (0)