Skip to content

Commit 621bf55

Browse files
committed
refactor(models): use catalog capabilities for forced tool support
1 parent c2ea621 commit 621bf55

3 files changed

Lines changed: 15 additions & 85 deletions

File tree

apps/sim/providers/anthropic/core.request.test.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -296,13 +296,8 @@ describe('executeAnthropicProviderRequest forced tool use', () => {
296296
expect(payload.tool_choice).toEqual({ type: 'tool', name: 'publish' })
297297
})
298298

299-
it.each([
300-
'claude-fable-5-1',
301-
'claude-fable-5-1-20260901',
302-
'azure-anthropic/claude-fable-5-1',
303-
'claude-mythos-5-1',
304-
])('drops forced tool_choice on %s because the API rejects it', async (model) => {
305-
const { payload, warn } = await runWithForcedTool(model)
299+
it('drops forced tool_choice when the catalog model disables Force', async () => {
300+
const { payload, warn } = await runWithForcedTool('claude-fable-5-1')
306301
expect(payload.tools?.map((tool) => tool.name)).toEqual(['publish'])
307302
expect(payload).not.toHaveProperty('tool_choice')
308303
expect(warn).toHaveBeenCalledWith(expect.stringContaining('rejects forced tool_choice'))

apps/sim/providers/models.test.ts

Lines changed: 7 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
PROVIDER_DEFINITIONS,
1717
supportsForcedToolUse,
1818
updateFireworksModels,
19-
updateOpenRouterModels,
2019
} from '@/providers/models'
2120
import { supportsPromptCaching } from '@/providers/utils'
2221

@@ -65,57 +64,14 @@ describe('catalog featured model metadata', () => {
6564
})
6665

6766
describe('forced tool use capability', () => {
68-
it('keeps Auto and None support when a model disables Force', () => {
69-
expect(getModelCapabilities('claude-fable-5-1')).toMatchObject({
70-
toolUsageControl: true,
71-
forcedToolUse: false,
72-
})
73-
})
74-
75-
it.each([
76-
'claude-fable-5-1',
77-
'CLAUDE-FABLE-5-1-20260901',
78-
'azure-anthropic/claude-fable-5-1',
79-
'azure-anthropic/claude-fable-5-1-20260901',
80-
'bedrock/anthropic.claude-fable-5-1-v1:0',
81-
'claude-mythos-5-1',
82-
'claude-mythos-5-1-20260901',
83-
])('disables forced tool use for %s', (model) => {
84-
expect(getModelCapabilities(model)).toMatchObject({
85-
toolUsageControl: true,
86-
forcedToolUse: false,
87-
})
88-
expect(supportsForcedToolUse(model)).toBe(false)
89-
})
90-
91-
it('adds only known alias capabilities to provider defaults', () => {
92-
expect(getModelCapabilities('claude-mythos-5-1')).toEqual({
93-
...PROVIDER_DEFINITIONS.anthropic.capabilities,
94-
forcedToolUse: false,
95-
})
96-
})
97-
98-
it('inherits alias capabilities for dynamic models and respects explicit overrides', () => {
99-
const originalModels = PROVIDER_DEFINITIONS.openrouter.models
100-
const modelId = 'anthropic/claude-fable-5-1'
101-
try {
102-
updateOpenRouterModels([modelId])
103-
expect(getModelCapabilities(modelId)?.forcedToolUse).toBe(false)
104-
expect(supportsForcedToolUse(modelId)).toBe(false)
105-
106-
PROVIDER_DEFINITIONS.openrouter.models[0].capabilities.forcedToolUse = true
107-
expect(getModelCapabilities(modelId)?.forcedToolUse).toBe(true)
108-
expect(supportsForcedToolUse(modelId)).toBe(true)
109-
} finally {
110-
PROVIDER_DEFINITIONS.openrouter.models = originalModels
111-
}
112-
})
113-
114-
it.each(['claude-fable-5-10', 'claude-mythos-5-10', 'claude-not-fable-5-1'])(
115-
'does not apply alias restrictions to unrelated model %s',
67+
it.each(['claude-fable-5-1', 'CLAUDE-FABLE-5-1'])(
68+
'disables Force while keeping Auto and None support for %s',
11669
(model) => {
117-
expect(getModelCapabilities(model)).toEqual(PROVIDER_DEFINITIONS.anthropic.capabilities)
118-
expect(supportsForcedToolUse(model)).toBe(true)
70+
expect(getModelCapabilities(model)).toMatchObject({
71+
toolUsageControl: true,
72+
forcedToolUse: false,
73+
})
74+
expect(supportsForcedToolUse(model)).toBe(false)
11975
}
12076
)
12177

apps/sim/providers/models.ts

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,6 @@ export function getProviderFileAttachment(providerId: string): ProviderFileAttac
166166
return PROVIDER_DEFINITIONS[providerId]?.fileAttachment ?? DEFAULT_FILE_ATTACHMENT
167167
}
168168

169-
const CLAUDE_5_1_TOOL_CAPABILITIES = { forcedToolUse: false } as const satisfies ModelCapabilities
170-
171-
/** Known capabilities for model aliases; explicit catalog capabilities take precedence. */
172-
const MODEL_CAPABILITY_FALLBACKS = [
173-
{
174-
pattern: /(?:^|[/.])claude-(?:fable|mythos)-5-1(?:$|[-:])/,
175-
capabilities: CLAUDE_5_1_TOOL_CAPABILITIES,
176-
},
177-
] satisfies { pattern: RegExp; capabilities: ModelCapabilities }[]
178-
179169
export const PROVIDER_DEFINITIONS: Record<string, ProviderDefinition> = {
180170
fireworks: {
181171
id: 'fireworks',
@@ -926,7 +916,7 @@ export const PROVIDER_DEFINITIONS: Record<string, ProviderDefinition> = {
926916
updatedAt: '2026-09-04',
927917
},
928918
capabilities: {
929-
...CLAUDE_5_1_TOOL_CAPABILITIES,
919+
forcedToolUse: false,
930920
nativeStructuredOutputs: true,
931921
maxOutputTokens: 128000,
932922
promptCaching: { minimumCacheableTokens: 512 },
@@ -4397,36 +4387,25 @@ export function getModelPricing(modelId: string): ModelPricing | null {
43974387
}
43984388

43994389
export function getModelCapabilities(modelId: string): ModelCapabilities | null {
4400-
const normalizedModel = modelId.toLowerCase()
4401-
const fallbackCapabilities = MODEL_CAPABILITY_FALLBACKS.find(({ pattern }) =>
4402-
pattern.test(normalizedModel)
4403-
)?.capabilities
4404-
44054390
for (const provider of Object.values(PROVIDER_DEFINITIONS)) {
4406-
const model = provider.models.find((m) => m.id.toLowerCase() === normalizedModel)
4391+
const model = provider.models.find((m) => m.id.toLowerCase() === modelId.toLowerCase())
44074392
if (model) {
4408-
const capabilities: ModelCapabilities = {
4409-
...provider.capabilities,
4410-
...fallbackCapabilities,
4411-
...model.capabilities,
4412-
}
4393+
const capabilities: ModelCapabilities = { ...provider.capabilities, ...model.capabilities }
44134394
return capabilities
44144395
}
44154396
}
44164397

44174398
for (const provider of Object.values(PROVIDER_DEFINITIONS)) {
44184399
if (provider.modelPatterns) {
44194400
for (const pattern of provider.modelPatterns) {
4420-
if (pattern.test(normalizedModel)) {
4421-
return fallbackCapabilities
4422-
? { ...provider.capabilities, ...fallbackCapabilities }
4423-
: provider.capabilities || null
4401+
if (pattern.test(modelId.toLowerCase())) {
4402+
return provider.capabilities || null
44244403
}
44254404
}
44264405
}
44274406
}
44284407

4429-
return fallbackCapabilities || null
4408+
return null
44304409
}
44314410

44324411
export function getModelsWithTemperatureSupport(): string[] {

0 commit comments

Comments
 (0)