From 299e314a288ca7993bae3585f2f2d97fe6ca7e16 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Sun, 23 Aug 2026 23:47:17 -0500 Subject: [PATCH] fix(ai): passthrough anthropic top-level body fields (#44604) --- .../ai/src/protocols/anthropic-messages.ts | 102 +++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/packages/ai/src/protocols/anthropic-messages.ts b/packages/ai/src/protocols/anthropic-messages.ts index f917d9aa108..6c22068278a 100644 --- a/packages/ai/src/protocols/anthropic-messages.ts +++ b/packages/ai/src/protocols/anthropic-messages.ts @@ -64,6 +64,19 @@ export interface OptionsInput { readonly [key: string]: unknown readonly thinking?: ThinkingInput readonly effort?: string + readonly service_tier?: "auto" | "standard_only" + readonly serviceTier?: "auto" | "standard_only" + // SDK Metadata:2649 {user_id?: string | null} + readonly metadata?: { readonly user_id?: string | null } + // SDK MessageCreateParamsContainer:2596 ContainerParams|string + readonly container?: string | { readonly id?: string | null; readonly skills?: ReadonlyArray> | null } + readonly inference_geo?: string | null + readonly inferenceGeo?: string | null + readonly cache_control?: { readonly type: "ephemeral"; readonly ttl?: "5m" | "1h" } + readonly cacheControl?: { readonly type: "ephemeral"; readonly ttl?: "5m" | "1h" } + // SDK OutputConfig:2684 {effort, format: JSONOutputFormat} + readonly output_config?: { readonly effort?: string | null; readonly format?: { readonly type: "json_schema"; readonly schema: Record } | null } + readonly outputConfig?: { readonly effort?: string | null; readonly format?: { readonly type: "json_schema"; readonly schema: Record } | null } } export type ProviderOptionsInput = OptionsInput @@ -264,10 +277,28 @@ const AnthropicThinking = Schema.Union([ }), ]) +// SDK OutputConfig:2684 {effort?: "low"|"medium"|"high"|"xhigh"|"max"|null, format?: JSONOutputFormat:2399} +const AnthropicJsonOutputFormat = Schema.Struct({ + type: Schema.Literal("json_schema"), + schema: JsonObject, +}) const AnthropicOutputConfig = Schema.Struct({ effort: Schema.optional(Schema.String), + format: Schema.optional(Schema.NullOr(AnthropicJsonOutputFormat)), }) +// SDK Metadata:2649 {user_id?: string|null} +const AnthropicMetadata = Schema.Struct({ user_id: optionalNull(Schema.String) }) + +// SDK MessageCreateParamsContainer:2596 ContainerParams|string; ContainerParams:2172 {id?, skills?} +const AnthropicContainer = Schema.Union([ + Schema.String, + Schema.Struct({ + id: optionalNull(Schema.String), + skills: optionalNull(Schema.Array(JsonObject)), + }), +]) + const AnthropicBodyFields = { model: Schema.String, system: optionalArray(AnthropicTextBlock), @@ -282,6 +313,12 @@ const AnthropicBodyFields = { stop_sequences: optionalArray(Schema.String), thinking: Schema.optional(AnthropicThinking), output_config: Schema.optional(AnthropicOutputConfig), + // SDK top-level passthrough: cache_control:4638, container:4643, inference_geo:4649, metadata:4654, service_tier:4670 + cache_control: Schema.optional(AnthropicCacheControl), + container: Schema.optional(Schema.NullOr(AnthropicContainer)), + inference_geo: Schema.optional(Schema.NullOr(Schema.String)), + metadata: Schema.optional(AnthropicMetadata), + service_tier: Schema.optional(Schema.Literals(["auto", "standard_only"])), } export const AnthropicMessagesBody = Schema.Struct(AnthropicBodyFields) export type AnthropicMessagesBody = Schema.Schema.Type @@ -820,10 +857,63 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* ( }) const resolveOptions = Effect.fn("AnthropicMessages.resolveOptions")(function* (request: LLMRequest) { - const input = request.providerOptions + const input = request.providerOptions as Record | undefined + const rawServiceTier = (input as Record | undefined)?.service_tier ?? (input as Record | undefined)?.serviceTier + const service_tier = + rawServiceTier === "auto" || rawServiceTier === "standard_only" + ? (rawServiceTier as "auto" | "standard_only") + : undefined + const rawMetadata = (input as Record | undefined)?.metadata + const metadata = + ProviderShared.isRecord(rawMetadata) && + (typeof rawMetadata.user_id === "string" || rawMetadata.user_id === null) + ? { user_id: rawMetadata.user_id as string | null } + : undefined + const container = + typeof (input as Record | undefined)?.container === "string" || + ProviderShared.isRecord((input as Record | undefined)?.container) + ? ((input as Record).container as string | { id?: string | null; skills?: ReadonlyArray> | null }) + : undefined + const rawInferenceGeo = + (input as Record | undefined)?.inference_geo ?? + (input as Record | undefined)?.inferenceGeo + const inference_geo = typeof rawInferenceGeo === "string" ? rawInferenceGeo : undefined + const rawCacheControl = + (input as Record | undefined)?.cache_control ?? + (input as Record | undefined)?.cacheControl + const cache_control = + ProviderShared.isRecord(rawCacheControl) && rawCacheControl.type === "ephemeral" + ? (rawCacheControl as { type: "ephemeral"; ttl?: "5m" | "1h" }) + : undefined + const rawOutputConfig = + (input as Record | undefined)?.output_config ?? + (input as Record | undefined)?.outputConfig + const outputConfigEffort = + typeof (input as Record | undefined)?.effort === "string" + ? ((input as Record).effort as string) + : ProviderShared.isRecord(rawOutputConfig) && typeof rawOutputConfig.effort === "string" + ? (rawOutputConfig.effort as string) + : undefined + const outputConfigFormat = + ProviderShared.isRecord(rawOutputConfig) && ProviderShared.isRecord(rawOutputConfig.format) + ? (rawOutputConfig.format as { type: "json_schema"; schema: Record }) + : undefined + const output_config = + outputConfigEffort === undefined && outputConfigFormat === undefined + ? undefined + : { + ...(outputConfigEffort === undefined ? {} : { effort: outputConfigEffort }), + ...(outputConfigFormat === undefined ? {} : { format: outputConfigFormat }), + } return { thinking: yield* resolveThinking(input?.thinking), - effort: typeof input?.effort === "string" ? input.effort : undefined, + effort: outputConfigEffort, + output_config, + service_tier, + metadata, + container, + inference_geo, + cache_control, } }) @@ -895,7 +985,13 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques top_k: generation?.topK, stop_sequences: generation?.stop, thinking: options.thinking, - output_config: options.effort === undefined ? undefined : { effort: options.effort }, + output_config: options.output_config, + // top-level passthrough per SDK MessageCreateParamsBase:4638,4643,4649,4654,4670 + cache_control: options.cache_control, + container: options.container, + inference_geo: options.inference_geo, + metadata: options.metadata, + service_tier: options.service_tier, } })