Skip to content

Commit ddb83c3

Browse files
committed
fix optional hosted key
1 parent cb0d8b5 commit ddb83c3

2 files changed

Lines changed: 50 additions & 5 deletions

File tree

apps/sim/tools/params.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,45 @@ describe('Tool Parameters Utils', () => {
209209
expect(selfHostedSchema.properties.apiKey.description).not.toContain('hosted key')
210210
})
211211

212+
it.concurrent('keeps the key required for conditionally hosted tools', () => {
213+
const enabled = Object.assign(
214+
(params: Record<string, unknown>) => params.provider === 'falai',
215+
{
216+
condition: { field: 'provider', operator: 'equals' as const, value: 'falai' },
217+
}
218+
)
219+
const conditionalTool = {
220+
...mockToolConfig,
221+
id: 'conditional_hosted_tool',
222+
params: {
223+
apiKey: {
224+
type: 'string',
225+
required: true,
226+
visibility: 'user-only' as ParameterVisibility,
227+
description: 'Provider API Key',
228+
},
229+
},
230+
hosting: {
231+
enabled,
232+
envKeyPrefix: 'FALAI_API_KEY',
233+
apiKeyParam: 'apiKey',
234+
byokProviderId: 'falai',
235+
pricing: { type: 'per_request' as const, cost: 0.01 },
236+
rateLimit: { mode: 'per_request' as const, requestsPerMinute: 100 },
237+
},
238+
}
239+
240+
const schema = createUserToolSchema(conditionalTool, {
241+
surface: 'copilot',
242+
hostedKeySupport: true,
243+
})
244+
245+
// Injection only happens when the predicate passes at runtime, so the
246+
// schema must not promise a hosted key for every configuration.
247+
expect(schema.required).toContain('apiKey')
248+
expect(schema.properties.apiKey.description).not.toContain('hosted key')
249+
})
250+
212251
it.concurrent('does not relax required keys on tools without hosting', () => {
213252
const plainTool = {
214253
...mockToolConfig,

apps/sim/tools/params.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,14 @@ export interface UserToolSchemaOptions {
131131
surface?: 'default' | 'copilot'
132132
/**
133133
* Set when the deployment provides hosted API keys for tools with a
134-
* `hosting` config. The hosted key param then stays in the schema only as an
135-
* optional bring-your-own-key override instead of a required argument — the
136-
* executor injects the hosted key server-side after validation, and the key
137-
* value itself is never exposed to the model or the mothership.
134+
* `hosting` config. For unconditionally hosted tools the key param then
135+
* stays in the schema only as an optional bring-your-own-key override
136+
* instead of a required argument — the executor injects the hosted key
137+
* server-side after validation, and the key value itself is never exposed
138+
* to the model or the mothership. Tools with a conditional
139+
* `hosting.enabled` predicate keep the key required, since injection only
140+
* happens for configurations that satisfy the predicate (mirrors the VFS
141+
* `conditional_hosted_or_byok` auth mode).
138142
*/
139143
hostedKeySupport?: boolean
140144
}
@@ -514,7 +518,9 @@ export function createUserToolSchema(
514518
): ToolSchema {
515519
const surface = options.surface ?? 'default'
516520
const hostedApiKeyParam =
517-
options.hostedKeySupport && toolConfig.hosting ? toolConfig.hosting.apiKeyParam : undefined
521+
options.hostedKeySupport && toolConfig.hosting && !toolConfig.hosting.enabled
522+
? toolConfig.hosting.apiKeyParam
523+
: undefined
518524
const schema: ToolSchema = {
519525
type: 'object',
520526
properties: {},

0 commit comments

Comments
 (0)