Skip to content

Commit bf2129a

Browse files
committed
fix(vertex): use adaptive thinking for Opus 4.8
1 parent 26c4447 commit bf2129a

3 files changed

Lines changed: 44 additions & 4 deletions

File tree

packages/types/src/providers/vertex.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ export const vertexModels = {
384384
cacheWritesPrice: 6.25, // $6.25 per million tokens
385385
cacheReadsPrice: 0.5, // $0.50 per million tokens
386386
supportsReasoningBudget: true,
387+
supportsReasoningBinary: true,
387388
supportsTemperature: false,
388389
// Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07')
389390
tiers: [
@@ -406,6 +407,7 @@ export const vertexModels = {
406407
cacheWritesPrice: 6.25, // $6.25 per million tokens
407408
cacheReadsPrice: 0.5, // $0.50 per million tokens
408409
supportsReasoningBudget: true,
410+
supportsReasoningBinary: true,
409411
supportsTemperature: false,
410412
// 4.8 inherits the same Vertex pricing structure as 4.7 — no breaking changes.
411413
// Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07')

src/api/providers/__tests__/anthropic-vertex.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,37 @@ describe("VertexHandler", () => {
11611161
undefined,
11621162
)
11631163
})
1164+
1165+
it("should use adaptive thinking for Claude Opus 4.8", async () => {
1166+
const opus48Handler = new AnthropicVertexHandler({
1167+
apiModelId: "claude-opus-4-8",
1168+
vertexProjectId: "test-project",
1169+
vertexRegion: "us-central1",
1170+
enableReasoningEffort: true,
1171+
})
1172+
1173+
const mockCreate = vitest.fn().mockImplementation(async () => ({
1174+
async *[Symbol.asyncIterator]() {
1175+
yield { type: "message_start", message: { usage: { input_tokens: 10, output_tokens: 5 } } }
1176+
},
1177+
}))
1178+
;(opus48Handler["client"].messages as any).create = mockCreate
1179+
1180+
await opus48Handler
1181+
.createMessage("You are a helpful assistant", [{ role: "user", content: "Hello" }])
1182+
.next()
1183+
1184+
expect(mockCreate).toHaveBeenCalledWith(
1185+
expect.objectContaining({
1186+
thinking: { type: "adaptive" },
1187+
}),
1188+
undefined,
1189+
)
1190+
1191+
const request = mockCreate.mock.calls[0][0]
1192+
expect(request.thinking).not.toHaveProperty("budget_tokens")
1193+
expect(request.temperature).toBeUndefined()
1194+
})
11641195
})
11651196

11661197
describe("native tool calling", () => {

src/api/providers/anthropic-vertex.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { ApiStream } from "../transform/stream"
1717
import { addCacheBreakpoints } from "../transform/caching/vertex"
1818
import { getModelParams } from "../transform/model-params"
1919
import { filterNonAnthropicBlocks } from "../transform/anthropic-filter"
20+
import { getAnthropicProviderReasoning } from "../transform/reasoning"
2021
import {
2122
convertOpenAIToolsToAnthropic,
2223
convertOpenAIToolChoiceToAnthropic,
@@ -95,7 +96,7 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
9596
* This ensures we stay under the 4-block limit while maintaining effective caching
9697
* for the most relevant context.
9798
*/
98-
const params: Anthropic.Messages.MessageCreateParamsStreaming = {
99+
const params = {
99100
model: id,
100101
max_tokens: maxTokens ?? ANTHROPIC_DEFAULT_MAX_TOKENS,
101102
temperature,
@@ -107,7 +108,7 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
107108
messages: supportsPromptCache ? addCacheBreakpoints(sanitizedMessages) : sanitizedMessages,
108109
stream: true,
109110
...nativeToolParams,
110-
}
111+
} as Anthropic.Messages.MessageCreateParamsStreaming
111112

112113
// and prompt caching
113114
const requestOptions = betas?.length ? { headers: { "anthropic-beta": betas.join(",") } } : undefined
@@ -240,6 +241,11 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
240241
settings: this.options,
241242
defaultTemperature: 0,
242243
})
244+
const thinking = getAnthropicProviderReasoning({
245+
model: info,
246+
reasoningBudget: params.reasoningBudget,
247+
settings: this.options,
248+
})
243249

244250
// Build betas array for request headers
245251
const betas: string[] = []
@@ -258,6 +264,7 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
258264
info,
259265
betas: betas.length > 0 ? betas : undefined,
260266
...params,
267+
reasoning: thinking,
261268
}
262269
}
263270

@@ -271,7 +278,7 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
271278
reasoning: thinking,
272279
} = this.getModel()
273280

274-
const params: Anthropic.Messages.MessageCreateParamsNonStreaming = {
281+
const params = {
275282
model: id,
276283
max_tokens: maxTokens,
277284
temperature,
@@ -285,7 +292,7 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
285292
},
286293
],
287294
stream: false,
288-
}
295+
} as Anthropic.Messages.MessageCreateParamsNonStreaming
289296

290297
const response = await this.client.messages.create(params)
291298
const content = response.content[0]

0 commit comments

Comments
 (0)