Skip to content

Commit 1e77422

Browse files
committed
test(providers): cover between_tools across Anthropic tool-loop turns
1 parent e818dc8 commit 1e77422

1 file changed

Lines changed: 83 additions & 6 deletions

File tree

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

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,6 @@ describe('executeAnthropicProviderRequest none thinking level', () => {
340340
return create.mock.calls[0][0] as Anthropic.Messages.MessageCreateParams
341341
}
342342

343-
it('sends bare between_tools thinking on claude-sonnet-5-5', async () => {
344-
const payload = await sendWithThinkingNone('claude-sonnet-5-5')
345-
expect(payload.thinking).toEqual({ type: 'between_tools' })
346-
expect(payload.output_config).toBeUndefined()
347-
})
348-
349343
it.each(['claude-sonnet-5', 'claude-opus-5-5'])(
350344
'sends no thinking config on %s',
351345
async (model) => {
@@ -796,6 +790,89 @@ describe('streaming', () => {
796790
}
797791
})
798792
})
793+
794+
/**
795+
* Both tool loops rebuild the request for every turn after a tool call, so
796+
* Sonnet 5.5's `none` mapping must survive past the first request: a later
797+
* turn without it would silently run adaptive thinking at the API default.
798+
*/
799+
describe('executeAnthropicProviderRequest none thinking level across tool turns', () => {
800+
const lookupTool = {
801+
id: 'lookup',
802+
name: 'lookup',
803+
description: 'Lookup',
804+
params: {},
805+
parameters: { type: 'object', properties: {}, required: [] },
806+
}
807+
const toolTurn = message(
808+
[{ type: 'tool_use', id: 'tool-1', name: 'lookup', input: {} }],
809+
'tool_use'
810+
)
811+
const answerTurn = message([{ type: 'text', text: 'done' }], 'end_turn')
812+
813+
function expectBareBetweenTools(payloads: Anthropic.Messages.MessageCreateParams[]) {
814+
expect(payloads).toHaveLength(2)
815+
for (const payload of payloads) {
816+
expect(payload.thinking).toEqual({ type: 'between_tools' })
817+
expect(payload.output_config).toBeUndefined()
818+
}
819+
}
820+
821+
it('sends bare between_tools on every non-streaming turn', async () => {
822+
mockExecuteTool.mockResolvedValue({ success: true, output: { value: 'tool result' } })
823+
const create = vi.fn().mockResolvedValueOnce(toolTurn).mockResolvedValueOnce(answerTurn)
824+
825+
await executeAnthropicProviderRequest(
826+
{
827+
model: 'claude-sonnet-5-5',
828+
apiKey: 'test-key',
829+
maxTokens: 1024,
830+
thinkingLevel: 'none',
831+
agentEvents: true,
832+
messages: [{ role: 'user', content: 'Look this up' }],
833+
tools: [lookupTool],
834+
},
835+
{
836+
providerId: 'anthropic',
837+
providerLabel: 'Anthropic',
838+
createClient: () => ({ messages: { create } }) as never,
839+
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
840+
}
841+
)
842+
843+
expectBareBetweenTools(create.mock.calls.map((call) => call[0]))
844+
})
845+
846+
it('sends bare between_tools on every streaming turn', async () => {
847+
mockExecuteTool.mockResolvedValue({ success: true, output: { value: 'tool result' } })
848+
const createStream = vi
849+
.fn()
850+
.mockReturnValueOnce(stream([{ type: 'message_stop' }], toolTurn))
851+
.mockReturnValueOnce(stream([{ type: 'message_stop' }], answerTurn))
852+
853+
const result = (await executeAnthropicProviderRequest(
854+
{
855+
model: 'claude-sonnet-5-5',
856+
apiKey: 'test-key',
857+
stream: true,
858+
maxTokens: 1024,
859+
thinkingLevel: 'none',
860+
agentEvents: true,
861+
messages: [{ role: 'user', content: 'Look this up' }],
862+
tools: [lookupTool],
863+
},
864+
{
865+
providerId: 'anthropic',
866+
providerLabel: 'Anthropic',
867+
createClient: () => ({ messages: { stream: createStream } }) as never,
868+
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
869+
}
870+
)) as StreamingExecution
871+
await collectEvents(result)
872+
873+
expectBareBetweenTools(createStream.mock.calls.map((call) => call[0]))
874+
})
875+
})
799876
})
800877

801878
/**

0 commit comments

Comments
 (0)