Skip to content

Commit df34c67

Browse files
authored
feat(models): add current frontier models (#8777)
* feat(models): add current frontier models * fix(providers): preserve proxy thinking and Mistral answer history * fix(mistral): preserve native continuation and saved answers
1 parent 37f5cdf commit df34c67

28 files changed

Lines changed: 1164 additions & 162 deletions

‎apps/docs/content/docs/workflows/blocks/agent.mdx‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,20 +158,21 @@ Live tool-call chips stream for **OpenAI, Anthropic, Azure Anthropic, Google, Ve
158158

159159
| Provider | Streamed thinking | Models |
160160
|----------|-------------------|--------|
161-
| OpenAI | Summaries only — Requires OpenAI organization verification; falls back to no summaries. | `gpt-6-astra`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5-pro`, `gpt-5.5`, `gpt-5.4-pro`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, `gpt-5.3-codex`, `gpt-5.2-pro`, `gpt-5.2`, `gpt-5.1`, `gpt-5-pro`, `gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `o4-mini`, `o3`, `o3-mini`, `o1` |
162-
| Anthropic | Summaries only — These generations omit full thinking; Sim requests summarized thinking on streaming runs. | `claude-fable-5-1`, `claude-fable-5`, `claude-sonnet-5-5`, `claude-sonnet-5`, `claude-opus-5-5`, `claude-opus-5`, `claude-opus-4-8`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-sonnet-4-6`, `claude-opus-4-5`, `claude-sonnet-4-5`, `claude-haiku-4-5` |
163-
| Azure OpenAI | Summaries only — Requires OpenAI organization verification; falls back to no summaries. | `azure/gpt-6-astra`, `azure/gpt-5.6-sol`, `azure/gpt-5.6-terra`, `azure/gpt-5.6-luna`, `azure/gpt-5.5`, `azure/gpt-5.4-pro`, `azure/gpt-5.4`, `azure/gpt-5.4-mini`, `azure/gpt-5.4-nano`, `azure/gpt-5.2`, `azure/gpt-5.1`, `azure/gpt-5.1-codex`, `azure/gpt-5`, `azure/gpt-5-mini`, `azure/gpt-5-nano`, `azure/o3`, `azure/o4-mini` |
164-
| Azure Anthropic | Summaries only — These generations omit full thinking; Sim requests summarized thinking on streaming runs. | `azure-anthropic/claude-fable-5-1`, `azure-anthropic/claude-opus-5`, `azure-anthropic/claude-opus-4-8`, `azure-anthropic/claude-opus-4-7`, `azure-anthropic/claude-opus-4-6`, `azure-anthropic/claude-opus-4-5`, `azure-anthropic/claude-sonnet-5`, `azure-anthropic/claude-sonnet-4-6`, `azure-anthropic/claude-sonnet-4-5`, `azure-anthropic/claude-opus-4-1`, `azure-anthropic/claude-haiku-4-5` |
161+
| OpenAI | Summaries only — Requires OpenAI organization verification; falls back to no summaries. | `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5-pro`, `gpt-5.5`, `gpt-5.4-pro`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, `gpt-5.3-codex`, `gpt-5.2-pro`, `gpt-5.2`, `gpt-5.1`, `gpt-5-pro`, `gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `o4-mini`, `o3`, `o3-mini`, `o1` |
162+
| Anthropic | Summaries only — These generations omit full thinking; Sim requests summarized thinking on streaming runs. | `claude-fable-5-1`, `claude-fable-5`, `claude-sonnet-5-5`, `claude-sonnet-5`, `claude-opus-5-5`, `claude-opus-5`, `claude-opus-4-8`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-sonnet-4-6`, `claude-opus-4-5`, `claude-sonnet-4-5`, `claude-haiku-5-5`, `claude-haiku-4-5` |
163+
| Azure OpenAI | Summaries only — Requires OpenAI organization verification; falls back to no summaries. | `azure/gpt-6.1-sol`, `azure/gpt-6-sol`, `azure/gpt-6-luna`, `azure/gpt-6-astra`, `azure/gpt-5.6-sol`, `azure/gpt-5.6-terra`, `azure/gpt-5.6-luna`, `azure/gpt-5.5`, `azure/gpt-5.4-pro`, `azure/gpt-5.4`, `azure/gpt-5.4-mini`, `azure/gpt-5.4-nano`, `azure/gpt-5.2`, `azure/gpt-5.1`, `azure/gpt-5.1-codex`, `azure/gpt-5`, `azure/gpt-5-mini`, `azure/gpt-5-nano`, `azure/o3`, `azure/o4-mini` |
164+
| Azure Anthropic | Summaries only — These generations omit full thinking; Sim requests summarized thinking on streaming runs. | `azure-anthropic/claude-fable-5-1`, `azure-anthropic/claude-opus-5-5`, `azure-anthropic/claude-sonnet-5-5`, `azure-anthropic/claude-haiku-5-5`, `azure-anthropic/claude-opus-5`, `azure-anthropic/claude-opus-4-8`, `azure-anthropic/claude-opus-4-7`, `azure-anthropic/claude-opus-4-6`, `azure-anthropic/claude-opus-4-5`, `azure-anthropic/claude-sonnet-5`, `azure-anthropic/claude-sonnet-4-6`, `azure-anthropic/claude-sonnet-4-5`, `azure-anthropic/claude-opus-4-1`, `azure-anthropic/claude-haiku-4-5` |
165165
| Google | Summaries only | `gemini-3.8-flash`, `gemini-3.7-flash`, `gemini-3.6-flash`, `gemini-3.5-flash-lite`, `gemini-3.5-flash`, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.5-flash-lite` |
166166
| Vertex AI | Summaries only | `vertex/gemini-3.8-flash`, `vertex/gemini-3.7-flash`, `vertex/gemini-3.6-flash`, `vertex/gemini-3.5-flash-lite`, `vertex/gemini-3.5-flash`, `vertex/gemini-3.1-pro-preview`, `vertex/gemini-3.1-flash-lite`, `vertex/gemini-3-flash-preview`, `vertex/gemini-2.5-pro`, `vertex/gemini-2.5-flash`, `vertex/gemini-2.5-flash-lite` |
167167
| DeepSeek | Full thinking deltas | `deepseek-v4-pro`, `deepseek-flash`, `deepseek-v4-flash`, `deepseek-reasoner` |
168168
| xAI | Full thinking deltas | `grok-4.6`, `grok-4.5`, `grok-4.3`, `grok-4.20-multi-agent-0309` |
169+
| xAI | Summaries only | `grok-4.7` |
169170
| Cerebras | Full thinking deltas | `cerebras/qwen-3.8-27b` |
170171
| Groq | Full thinking deltas | `groq/openai/gpt-oss-120b`, `groq/openai/gpt-oss-20b`, `groq/openai/gpt-oss-safeguard-20b`, `groq/qwen/qwen3.8-27b`, `groq/qwen/qwen3.6-27b` |
171172
| Meta | Not streamed | `muse-spark-1.3`, `muse-spark-1.1` |
172173
| Kimi | Full thinking deltas | `kimi-k3`, `kimi-k2.6` |
173-
| Kie | Summaries only | `kie/claude-opus-5-5`, `kie/claude-opus-5`, `kie/claude-fable-5`, `kie/claude-sonnet-5`, `kie/claude-opus-4-8`, `kie/claude-opus-4-7`, `kie/claude-opus-4-6`, `kie/claude-sonnet-4-6`, `kie/claude-opus-4-5`, `kie/claude-sonnet-4-5`, `kie/claude-haiku-4-5`, `kie/gpt-6-astra`, `kie/gpt-6-sol`, `kie/gpt-6-luna`, `kie/gpt-5-6-sol`, `kie/gpt-5-6-terra`, `kie/gpt-5-6-luna`, `kie/gpt-5-5`, `kie/grok-4-6`, `kie/grok-4-5`, `kie/grok-4-3`, `kie/kimi-k3` |
174-
| Z.ai | Full thinking deltas | `glm-5.3`, `glm-5.3-flash`, `glm-5.2`, `glm-5.1`, `glm-5`, `glm-5-turbo`, `glm-4.7`, `glm-4.6`, `glm-4.5`, `glm-4.5-air` |
174+
| Kie | Summaries only | `kie/claude-sonnet-5-5`, `kie/claude-opus-5-5`, `kie/claude-opus-5`, `kie/claude-fable-5`, `kie/claude-sonnet-5`, `kie/claude-opus-4-8`, `kie/claude-opus-4-7`, `kie/claude-opus-4-6`, `kie/claude-sonnet-4-6`, `kie/claude-opus-4-5`, `kie/claude-sonnet-4-5`, `kie/claude-haiku-4-5`, `kie/gpt-6-1-sol`, `kie/gpt-6-astra`, `kie/gpt-6-sol`, `kie/gpt-6-luna`, `kie/gpt-5-6-sol`, `kie/gpt-5-6-terra`, `kie/gpt-5-6-luna`, `kie/gpt-5-5`, `kie/grok-4-6`, `kie/grok-4-5`, `kie/grok-4-3`, `kie/kimi-k3` |
175+
| Z.ai | Full thinking deltas | `glm-5.3`, `glm-5.3-flashx`, `glm-5.3-flash`, `glm-5.2`, `glm-5.1`, `glm-5`, `glm-5-turbo`, `glm-4.7`, `glm-4.6`, `glm-4.5`, `glm-4.5-air` |
175176

176177
{/* agent-stream-capabilities:end */}
177178

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

Lines changed: 94 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -747,14 +747,10 @@ describe('streaming', () => {
747747
})
748748

749749
/**
750-
* Both tool loops rebuild the request for every turn after a tool call, so
751-
* the `none` mapping must hold past the first request. Claude Sonnet 5.5
752-
* rejects `thinking.type: "disabled"` and names `between_tools` (which takes
753-
* no effort or display field) as its lowest setting; a later turn without it
754-
* would silently run adaptive thinking. Every other model keeps `none` as
755-
* "send no thinking config".
750+
* Both tool loops rebuild requests after tool calls. Explicit none modes
751+
* must survive later turns or default-thinking models resume thinking.
756752
*/
757-
describe('executeAnthropicProviderRequest none thinking level across tool turns', () => {
753+
describe('Anthropic tool exchanges', () => {
758754
const lookupTool = {
759755
id: 'lookup',
760756
name: 'lookup',
@@ -767,24 +763,31 @@ describe('streaming', () => {
767763
message([{ type: 'text', text: 'done' }], 'end_turn'),
768764
]
769765

770-
/** Runs a tool exchange and returns every request body sent over the SDK boundary. */
771-
async function runToolExchange(model: string, streaming: boolean) {
766+
/** Runs a tool exchange and returns the SDK request bodies and settled output. */
767+
async function runToolExchange(
768+
model: string,
769+
streaming: boolean,
770+
thinkingLevel = 'none',
771+
forceTool = false,
772+
responseTurns = turns
773+
) {
772774
mockExecuteTool.mockResolvedValue({ success: true, output: { value: 'tool result' } })
773775
const sent: Anthropic.Messages.MessageCreateParams[] = []
774776
const nextTurn = (payload: Anthropic.Messages.MessageCreateParams) => {
775777
sent.push(payload)
776-
return turns[sent.length - 1]
778+
return responseTurns[sent.length - 1]
777779
}
778780
const result = await executeAnthropicProviderRequest(
779781
{
780782
model,
781783
apiKey: 'test-key',
782784
stream: streaming,
783-
maxTokens: 1024,
784-
thinkingLevel: 'none',
785+
maxTokens: 4096,
786+
thinkingLevel,
787+
temperature: 0.5,
785788
agentEvents: true,
786789
messages: [{ role: 'user', content: 'Look this up' }],
787-
tools: [lookupTool],
790+
tools: [{ ...lookupTool, usageControl: forceTool ? 'force' : 'auto' }],
788791
},
789792
{
790793
providerId: 'anthropic',
@@ -802,13 +805,18 @@ describe('streaming', () => {
802805
}
803806
)
804807
if (streaming) await collectEvents(result as StreamingExecution)
805-
return sent
808+
return {
809+
sent,
810+
output: streaming
811+
? (result as StreamingExecution).execution.output
812+
: (result as ProviderResponse),
813+
}
806814
}
807815

808816
it.each([false, true])(
809817
'sends bare between_tools on every turn (streaming: %s)',
810818
async (streaming) => {
811-
const sent = await runToolExchange('claude-sonnet-5-5', streaming)
819+
const { sent } = await runToolExchange('claude-sonnet-5-5', streaming)
812820
expect(sent).toHaveLength(2)
813821
for (const payload of sent) {
814822
expect(payload.thinking).toEqual({ type: 'between_tools' })
@@ -820,11 +828,81 @@ describe('streaming', () => {
820828
it.each(['claude-sonnet-5', 'claude-opus-5-5'])(
821829
'sends no thinking config on %s',
822830
async (model) => {
823-
const sent = await runToolExchange(model, false)
831+
const { sent } = await runToolExchange(model, false)
824832
expect(sent).toHaveLength(2)
825833
for (const payload of sent) expect(payload.thinking).toBeUndefined()
826834
}
827835
)
836+
837+
it.each([false, true])(
838+
'disables Haiku 5.5 default thinking on every tool turn (streaming: %s)',
839+
async (streaming) => {
840+
const { sent } = await runToolExchange('claude-haiku-5-5', streaming)
841+
expect(sent).toHaveLength(2)
842+
for (const payload of sent) {
843+
expect(payload.thinking).toEqual({ type: 'disabled' })
844+
expect(payload.output_config).toBeUndefined()
845+
expect(payload.temperature).toBeUndefined()
846+
}
847+
}
848+
)
849+
850+
it.each([false, true])(
851+
'uses adaptive Haiku 5.5 thinking and releases the executed forced tool (streaming: %s)',
852+
async (streaming) => {
853+
const { sent } = await runToolExchange('claude-haiku-5-5', streaming, 'max', true)
854+
expect(sent).toHaveLength(2)
855+
for (const payload of sent) {
856+
expect(payload.thinking).toEqual({ type: 'adaptive', display: 'summarized' })
857+
expect(payload.output_config).toEqual({ effort: 'max' })
858+
expect(payload.temperature).toBeUndefined()
859+
}
860+
expect(sent[0].tool_choice).toEqual({ type: 'tool', name: 'lookup' })
861+
expect(sent[1].tool_choice).toBeUndefined()
862+
}
863+
)
864+
865+
it.each([false, true])(
866+
'prices Haiku prompts below the long-context tier separately (streaming: %s)',
867+
async (streaming) => {
868+
const responseTurns = turns.map((turn) => ({
869+
...turn,
870+
usage: { input_tokens: 60000, output_tokens: 2000 },
871+
}))
872+
const { output } = await runToolExchange(
873+
'claude-haiku-5-5',
874+
streaming,
875+
'none',
876+
false,
877+
responseTurns
878+
)
879+
expect(output.tokens).toMatchObject({ input: 120000, output: 4000 })
880+
expect(output.cost).toMatchObject({ input: 0.012, output: 0.002, total: 0.014 })
881+
}
882+
)
883+
884+
it.each([false, true])(
885+
'prices mixed Haiku prompt tiers using each turn including cache reads (streaming: %s)',
886+
async (streaming) => {
887+
const responseTurns = turns.map((turn, index) => ({
888+
...turn,
889+
usage: {
890+
input_tokens: index === 0 ? 60000 : 10000,
891+
output_tokens: 2000,
892+
cache_read_input_tokens: index === 0 ? 10000 : 100000,
893+
},
894+
}))
895+
const { output } = await runToolExchange(
896+
'claude-haiku-5-5',
897+
streaming,
898+
'none',
899+
false,
900+
responseTurns
901+
)
902+
expect(output.tokens).toMatchObject({ input: 70000, output: 4000, cacheRead: 110000 })
903+
expect(output.cost).toMatchObject({ input: 0.0161, output: 0.006, total: 0.0221 })
904+
}
905+
)
828906
})
829907
})
830908

‎apps/sim/providers/anthropic/core.ts‎

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ const ANTHROPIC_THINKING_OUTPUT_HEADROOM = 4096
146146
* Fable 5, Fable 5.1, and Opus 5.5 support ONLY adaptive thinking (always on; type: "disabled" is rejected).
147147
* Sonnet 5.5 is adaptive by default and rejects type: "disabled"; its lowest setting is "between_tools".
148148
* Sonnet 5 supports ONLY adaptive thinking (manual budget_tokens returns a 400 error).
149+
* Haiku 5.5 supports adaptive thinking and rejects manual budget_tokens.
149150
* Opus 5, Opus 4.8, and Opus 4.7 support ONLY adaptive thinking (no extended thinking / budget_tokens).
150151
* Opus 4.6 and Sonnet 4.6 support both extended and adaptive thinking — use adaptive.
151152
* Opus 4.5 supports effort but NOT adaptive thinking — it uses budget_tokens with type: "enabled".
@@ -155,6 +156,7 @@ function supportsAdaptiveThinking(modelId: string): boolean {
155156
return (
156157
normalizedModel.includes('fable-5') ||
157158
normalizedModel.includes('sonnet-5') ||
159+
normalizedModel.includes('haiku-5-5') ||
158160
normalizedModel.includes('opus-5') ||
159161
normalizedModel.includes('opus-4-8') ||
160162
normalizedModel.includes('opus-4.8') ||
@@ -175,9 +177,9 @@ function supportsAdaptiveThinking(modelId: string): boolean {
175177
* - Other models: Uses budget_tokens-based extended thinking
176178
*
177179
* The `none` level returns null (send no thinking config) unless the model
178-
* declares `capabilities.thinking.noneMode`: Sonnet 5.5 rejects
179-
* `type: "disabled"`, so `none` becomes `type: "between_tools"`, which turns
180-
* off up-front thinking and takes no effort or display field.
180+
* declares `capabilities.thinking.noneMode`: Sonnet 5.5 uses `between_tools`,
181+
* while Haiku 5.5 requires `disabled` to turn off its default thinking.
182+
* Neither mode takes an effort or display field.
181183
*
182184
* The newest Claude generations default `thinking.display` to `omitted`
183185
* (empty thinking blocks, no thinking deltas). Their registry entries mark
@@ -201,6 +203,7 @@ export function buildThinkingConfig(
201203
}
202204

203205
if (thinkingLevel === 'none') {
206+
if (capability.noneMode === 'disabled') return { thinking: { type: 'disabled' } }
204207
if (capability.noneMode !== 'between_tools') return null
205208
return {
206209
// double-cast-allowed: @anthropic-ai/sdk 0.115 predates the between_tools thinking type (typed from 0.129)
@@ -221,7 +224,9 @@ export function buildThinkingConfig(
221224
...(requestSummarizedDisplay ? { display: 'summarized' as const } : {}),
222225
},
223226
// Levels are validated against the model's capability list above.
224-
outputConfig: { effort: thinkingLevel as Anthropic.Messages.OutputConfig['effort'] },
227+
...(thinkingLevel !== 'enabled' && {
228+
outputConfig: { effort: thinkingLevel as Anthropic.Messages.OutputConfig['effort'] },
229+
}),
225230
}
226231
}
227232

@@ -424,7 +429,7 @@ export async function executeAnthropicProviderRequest(
424429
payload.temperature = undefined
425430

426431
if (request.thinkingLevel === 'none') {
427-
logger.info(`Using between_tools thinking for model: ${modelId}`)
432+
logger.info(`Using ${thinkingConfig.thinking.type} thinking for model: ${modelId}`)
428433
} else {
429434
const isAdaptive = thinkingConfig.thinking.type === 'adaptive'
430435
logger.info(
@@ -440,10 +445,11 @@ export async function executeAnthropicProviderRequest(
440445

441446
if (anthropicTools?.length) {
442447
payload.tools = anthropicTools
443-
// Per Anthropic docs: forced tool_choice (type: "tool" or "any") is incompatible with
444-
// thinking. Only auto and none are supported when thinking is enabled.
445-
if (payload.thinking) {
446-
// Per Anthropic docs: only 'auto' (default) and 'none' work with thinking.
448+
const restrictForcedTools =
449+
payload.thinking &&
450+
payload.thinking.type !== 'disabled' &&
451+
!getThinkingCapability(request.model)?.forcedToolUse
452+
if (restrictForcedTools) {
447453
if (toolChoice === 'none') {
448454
payload.tool_choice = { type: 'none' }
449455
}
@@ -871,15 +877,7 @@ export async function executeAnthropicProviderRequest(
871877
messages: currentMessages,
872878
}
873879

874-
// Per Anthropic docs: forced tool_choice is incompatible with thinking.
875-
// Only auto and none are supported when thinking is enabled.
876-
const thinkingEnabled = !!payload.thinking
877-
if (
878-
!thinkingEnabled &&
879-
typeof originalToolChoice === 'object' &&
880-
hasUsedForcedTool &&
881-
forcedTools.length > 0
882-
) {
880+
if (typeof originalToolChoice === 'object' && hasUsedForcedTool && forcedTools.length > 0) {
883881
const remainingTools = forcedTools.filter((tool) => !usedForcedTools.includes(tool))
884882

885883
if (remainingTools.length > 0) {
@@ -892,11 +890,7 @@ export async function executeAnthropicProviderRequest(
892890
nextPayload.tool_choice = undefined
893891
logger.info('All forced tools have been used, removing tool_choice parameter')
894892
}
895-
} else if (
896-
!thinkingEnabled &&
897-
hasUsedForcedTool &&
898-
typeof originalToolChoice === 'object'
899-
) {
893+
} else if (hasUsedForcedTool && typeof originalToolChoice === 'object') {
900894
nextPayload.tool_choice = undefined
901895
logger.info(
902896
'Removing tool_choice parameter for subsequent requests after forced tool was used'

‎apps/sim/providers/anthropic/streaming-tool-loop.ts‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,8 @@ export function createAnthropicStreamingToolLoopStream(
180180
turnPayload.tool_choice = { type: 'none' }
181181
}
182182

183-
// Forced tool_choice vs thinking — same rules as silent loop.
184-
const thinkingEnabled = !!payload.thinking
185183
if (
186184
!finalSynthesis &&
187-
!thinkingEnabled &&
188185
typeof originalToolChoice === 'object' &&
189186
hasUsedForcedTool &&
190187
forcedToolNames.length > 0
@@ -197,7 +194,6 @@ export function createAnthropicStreamingToolLoopStream(
197194
}
198195
} else if (
199196
!finalSynthesis &&
200-
!thinkingEnabled &&
201197
hasUsedForcedTool &&
202198
typeof originalToolChoice === 'object'
203199
) {

0 commit comments

Comments
 (0)