Skip to content

Commit 2ba228a

Browse files
committed
fix(providers): correct defects found auditing the attachment and SDK changes
The mechanical rewrite that added `isFunctionToolCall` to every `tool_calls` read also rewrote three truthiness guards, where the filtered array was computed, discarded, and the unfiltered value used in the body. Filter once and use that value. The helper also landed between `trackForcedToolUsage`'s TSDoc block and its declaration, leaving that block documenting the wrong function. Raise the Bedrock ceiling from 3.75 MB to 4.5 MB. Converse caps an image at 3.75 MB and a document at 4.5 MB, and a single `maxBytes` cannot express both. Taking the lower bound looked conservative but regressed 3.75-4.5 MB documents, which Converse accepts and which work today. At the document bound every size that works now still works, and only genuinely-too-large files are rejected early; oversized images in that band keep surfacing as a Bedrock API error, exactly as they do without the entry. Both limits re-verified verbatim against the primary docs: Converse's Message reference ("Each image's size ... no more than 3.75 MB", "Each document's size must be no more than 4.5 MB") and Fireworks' vision guide ("Total base64-encoded images must be less than 10MB").
1 parent 3786320 commit 2ba228a

6 files changed

Lines changed: 31 additions & 34 deletions

File tree

apps/sim/providers/attachments.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ describe('provider large-file capability', () => {
310310
INLINE_ATTACHMENT_THRESHOLD_BYTES
311311
)
312312
expect(getProviderAttachmentMaxBytes('azure-openai')).toBe(INLINE_ATTACHMENT_THRESHOLD_BYTES)
313-
/** Bedrock Converse caps an image at 3.75MB — below the inline cap, so it needs its own entry. */
314-
expect(getProviderAttachmentMaxBytes('bedrock')).toBe(3_750_000)
313+
/** Bedrock Converse caps a document at 4.5MB — below the inline cap, so it needs its own entry. */
314+
expect(getProviderAttachmentMaxBytes('bedrock')).toBe(4_500_000)
315315
})
316316

317317
it('routes only oversized files on capable providers to the large-file path', () => {

apps/sim/providers/azure-openai/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ import type {
1313
ChatCompletionToolChoiceOption,
1414
} from 'openai/resources/chat/completions'
1515
import type { ReasoningEffort } from 'openai/resources/shared'
16-
17-
/** `verbosity` narrowed from `string` to a literal union in openai v5. */
18-
type ChatCompletionVerbosity = NonNullable<ChatCompletionCreateParams['verbosity']>
19-
2016
import { env } from '@/lib/core/config/env'
2117
import { createPinnedFetch, validateUrlWithDNS } from '@/lib/core/security/input-validation.server'
2218
import type { StreamingExecution } from '@/executor/types'
@@ -55,6 +51,9 @@ import {
5551
sumToolCosts,
5652
} from '@/providers/utils'
5753

54+
/** `verbosity` narrowed from `string` to a literal union in openai v5. */
55+
type ChatCompletionVerbosity = NonNullable<ChatCompletionCreateParams['verbosity']>
56+
5857
const logger = createLogger('AzureOpenAIProvider')
5958

6059
/**

apps/sim/providers/litellm/index.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,9 @@ export const litellmProvider: ProviderConfig = {
268268
response: any,
269269
toolChoice: string | { type: string; function?: { name: string }; name?: string; any?: any }
270270
) => {
271-
if (
272-
typeof toolChoice === 'object' &&
271+
const toolCallsResponse =
273272
response.choices[0]?.message?.tool_calls?.filter(isFunctionToolCall)
274-
) {
275-
const toolCallsResponse = response.choices[0].message.tool_calls
273+
if (typeof toolChoice === 'object' && toolCallsResponse?.length) {
276274
const result = trackForcedToolUsage(
277275
toolCallsResponse,
278276
toolChoice,

apps/sim/providers/mistral/index.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,9 @@ export const mistralProvider: ProviderConfig = {
203203
response: any,
204204
toolChoice: string | { type: string; function?: { name: string }; name?: string; any?: any }
205205
) => {
206-
if (
207-
typeof toolChoice === 'object' &&
206+
const toolCallsResponse =
208207
response.choices[0]?.message?.tool_calls?.filter(isFunctionToolCall)
209-
) {
210-
const toolCallsResponse = response.choices[0].message.tool_calls
208+
if (typeof toolChoice === 'object' && toolCallsResponse?.length) {
211209
const result = trackForcedToolUsage(
212210
toolCallsResponse,
213211
toolChoice,

apps/sim/providers/models.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3506,11 +3506,16 @@ export const PROVIDER_DEFINITIONS: Record<string, ProviderDefinition> = {
35063506
bedrock: {
35073507
id: 'bedrock',
35083508
/**
3509-
* Converse caps an image at 3.75 MB and a document at 4.5 MB; the lower bound is the safe
3510-
* single ceiling. There is no large-file path: the only non-inline source is `s3Location`,
3511-
* which takes an `s3://` URI read with the caller's IAM role, not a presigned HTTPS URL.
3509+
* Converse caps an image at 3.75 MB and a document at 4.5 MB. A single `maxBytes` cannot
3510+
* express both, so it carries the higher (document) bound: clamping to 3.75 MB would reject
3511+
* 3.75-4.5 MB documents that Converse accepts today, whereas at 4.5 MB every size that works
3512+
* now still works and only the genuinely-too-large are rejected early. Oversized images in
3513+
* that band still surface as a Bedrock API error, exactly as they do without this entry.
3514+
*
3515+
* There is no large-file path: the only non-inline Converse source is `s3Location`, which
3516+
* takes an `s3://` URI read with the caller's IAM role, not a presigned HTTPS URL.
35123517
*/
3513-
fileAttachment: { maxBytes: 3_750_000, strategy: 'inline' },
3518+
fileAttachment: { maxBytes: 4_500_000, strategy: 'inline' },
35143519
name: 'AWS Bedrock',
35153520
description: 'AWS Bedrock foundation models',
35163521
defaultModel: 'bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0',

apps/sim/providers/utils.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,17 +1235,6 @@ export function prepareToolsWithUsageControl(
12351235
}
12361236
}
12371237

1238-
/**
1239-
* Checks if a forced tool has been used in a response and manages the tool_choice accordingly
1240-
*
1241-
* @param toolCallsResponse Array of tool calls in the response
1242-
* @param originalToolChoice The original tool_choice setting used in the request
1243-
* @param logger Logger instance to use for logging
1244-
* @param provider Optional provider ID to adjust format for specific providers
1245-
* @param forcedTools Array of all tool IDs that should be forced in sequence
1246-
* @param usedForcedTools Array of tool IDs that have already been used
1247-
* @returns Object containing tracking information and next tool choice
1248-
*/
12491238
/**
12501239
* Narrows the SDK's `ChatCompletionMessageToolCall` union to its function variant.
12511240
*
@@ -1263,6 +1252,17 @@ export function isFunctionToolCall(
12631252
return 'function' in toolCall && toolCall.function != null
12641253
}
12651254

1255+
/**
1256+
* Checks if a forced tool has been used in a response and manages the tool_choice accordingly
1257+
*
1258+
* @param toolCallsResponse Array of tool calls in the response
1259+
* @param originalToolChoice The original tool_choice setting used in the request
1260+
* @param logger Logger instance to use for logging
1261+
* @param provider Optional provider ID to adjust format for specific providers
1262+
* @param forcedTools Array of all tool IDs that should be forced in sequence
1263+
* @param usedForcedTools Array of tool IDs that have already been used
1264+
* @returns Object containing tracking information and next tool choice
1265+
*/
12661266
export function trackForcedToolUsage(
12671267
toolCallsResponse: any[] | undefined,
12681268
originalToolChoice: any,
@@ -1579,11 +1579,8 @@ export function checkForForcedToolUsageOpenAI(
15791579
let hasUsedForcedTool = false
15801580
let updatedUsedForcedTools = [...usedForcedTools]
15811581

1582-
if (
1583-
typeof toolChoice === 'object' &&
1584-
response.choices[0]?.message?.tool_calls?.filter(isFunctionToolCall)
1585-
) {
1586-
const toolCallsResponse = response.choices[0].message.tool_calls
1582+
const toolCallsResponse = response.choices[0]?.message?.tool_calls?.filter(isFunctionToolCall)
1583+
if (typeof toolChoice === 'object' && toolCallsResponse?.length) {
15871584
const result = trackForcedToolUsage(
15881585
toolCallsResponse,
15891586
toolChoice,

0 commit comments

Comments
 (0)