feat(ai): add Anthropic fast mode speed option (#58870)

This commit is contained in:
Aiden Cline
2026-10-24 23:23:10 -05:00
committed by GitHub
Unverified
parent 4c8f4fceda
commit b7321f7fcc
2 changed files with 22 additions and 2 deletions
@@ -83,6 +83,7 @@ const AnthropicCacheControl = Schema.Struct({
ttl: Schema.optional(Schema.Literals(["5m", "1h"])),
})
const AnthropicServiceTier = knownString<"auto" | "standard_only">()
const AnthropicSpeed = knownString<"fast" | "standard">()
const AnthropicTextBlock = Schema.Struct({
type: Schema.tag("text"),
@@ -359,6 +360,7 @@ const Options = Schema.Struct({
effort: Schema.optional(Schema.String),
service_tier: Schema.optional(AnthropicServiceTier),
serviceTier: Schema.optional(AnthropicServiceTier),
speed: Schema.optional(AnthropicSpeed),
metadata: Schema.optional(AnthropicMetadata),
container: Schema.optional(AnthropicContainer),
inference_geo: optionalNull(Schema.String),
@@ -402,6 +404,7 @@ const AnthropicBodyFields = {
inference_geo: Schema.optional(Schema.NullOr(Schema.String)),
metadata: Schema.optional(AnthropicMetadata),
service_tier: Schema.optional(AnthropicServiceTier),
speed: Schema.optional(AnthropicSpeed),
}
export const AnthropicMessagesBody = Schema.Struct(AnthropicBodyFields)
export type AnthropicMessagesBody = Schema.Schema.Type<typeof AnthropicMessagesBody>
@@ -1118,6 +1121,7 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques
inference_geo: options.inference_geo ?? options.inferenceGeo ?? undefined,
metadata: options.metadata,
service_tier: options.service_tier ?? options.serviceTier,
speed: options.speed,
}
if (!management) return body
return {
@@ -1644,7 +1648,7 @@ export const protocol = Protocol.make({
})
export const transport = <
Body extends Pick<AnthropicMessagesBody, "messages" | "context_management" | "thinking">,
Body extends Pick<AnthropicMessagesBody, "messages" | "context_management" | "thinking" | "speed">,
>() => {
const http = HttpTransport.httpJson<Body, string>({ framing })
return {
@@ -1671,7 +1675,9 @@ export const transport = <
}
}
function requiredBetaHeaders(body: Pick<AnthropicMessagesBody, "messages" | "context_management" | "thinking">) {
function requiredBetaHeaders(
body: Pick<AnthropicMessagesBody, "messages" | "context_management" | "thinking" | "speed">,
) {
// Always request interleaved thinking. The API accepts the header on any
// model and ignores it where unsupported, while manual-thinking models need
// it for thinking between tool calls.
@@ -1685,6 +1691,9 @@ function requiredBetaHeaders(body: Pick<AnthropicMessagesBody, "messages" | "con
if (body.messages.some((message) => message.role === "system" && message.output_config !== undefined))
betas.push("mid-conversation-output-config-2026-07-01")
// Opus 5.5 accepts `speed` without this header; earlier fast-mode models reject `speed` without it.
if (body.speed !== undefined) betas.push("fast-mode-2026-02-01")
const thinking = body.thinking
if (thinking && !isThinkingOff(thinking) && thinking.block_binding) betas.push(THINKING_BINDING_BETA)
return betas
@@ -243,6 +243,17 @@ describe("Anthropic Messages route", () => {
}),
)
it.effect("sends fast mode speed with its beta header", () =>
Effect.gen(function* () {
const fast = LLMRequest.update(request, { providerOptions: { speed: "fast" } })
const compiled = yield* compileRequest(fast)
const prepared = yield* AnthropicMessages.route.prepareTransport(compiled.body, fast)
expect(compiled.body.speed).toBe("fast")
expect(prepared.request.headers["anthropic-beta"]).toBe("interleaved-thinking-2025-05-14,fast-mode-2026-02-01")
}),
)
it.effect("forwards unknown values for pass-through string enums", () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(