( modelString: string, thinkingLevel: ThinkingLevel, messages?: MuxMessage[], _lostResponseIds?: (id: string) => boolean, muxProviderOptions?: MuxProviderOptions, workspaceId?: string, // Optional for non-OpenAI providers openaiTruncationMode?: OpenAIResponsesProviderOptions["truncation"], providersConfig?: ProvidersConfigMap | null, routeProvider?: ProviderName, promptCacheScope?: string )
| 217 | * @returns Provider options object for AI SDK |
| 218 | */ |
| 219 | export function buildProviderOptions( |
| 220 | modelString: string, |
| 221 | thinkingLevel: ThinkingLevel, |
| 222 | messages?: MuxMessage[], |
| 223 | _lostResponseIds?: (id: string) => boolean, |
| 224 | muxProviderOptions?: MuxProviderOptions, |
| 225 | workspaceId?: string, // Optional for non-OpenAI providers |
| 226 | openaiTruncationMode?: OpenAIResponsesProviderOptions["truncation"], |
| 227 | providersConfig?: ProvidersConfigMap | null, |
| 228 | routeProvider?: ProviderName, |
| 229 | promptCacheScope?: string |
| 230 | ): ProviderOptions { |
| 231 | // Caller is responsible for enforcing thinking policy before calling this function. |
| 232 | // agentSession.ts is the canonical enforcement point. |
| 233 | const effectiveThinking = thinkingLevel; |
| 234 | // Parse origin from normalized model string |
| 235 | const normalizedModel = normalizeToCanonical(modelString); |
| 236 | const [origin, modelName] = normalizedModel.split(":", 2); |
| 237 | |
| 238 | if (!origin || !modelName) { |
| 239 | log.debug("buildProviderOptions: No origin or model name found, returning empty"); |
| 240 | return {}; |
| 241 | } |
| 242 | |
| 243 | const providerOptionsNamespaceKey = resolveProviderOptionsNamespaceKey(origin, routeProvider); |
| 244 | |
| 245 | // SDK payload-family selection: passthrough gateways use origin payloads, |
| 246 | // while transforming gateways use the route provider's payload schema. |
| 247 | const formatProvider = |
| 248 | providerOptionsNamespaceKey === origin ? origin : (routeProvider ?? origin); |
| 249 | |
| 250 | // Resolve aliases to their base model for capability detection while keeping |
| 251 | // the original modelString for provider routing and metadata lookups. |
| 252 | const capabilityModel = resolveModelForMetadata(normalizedModel, providersConfig ?? null); |
| 253 | const [, resolvedCapabilityModelName] = capabilityModel.split(":", 2); |
| 254 | const capModelName = resolvedCapabilityModelName || modelName; |
| 255 | |
| 256 | log.debug("buildProviderOptions", { |
| 257 | modelString, |
| 258 | origin, |
| 259 | routeProvider, |
| 260 | providerOptionsNamespaceKey, |
| 261 | formatProvider, |
| 262 | modelName, |
| 263 | capabilityModel, |
| 264 | capModelName, |
| 265 | thinkingLevel, |
| 266 | }); |
| 267 | |
| 268 | // Build Anthropic-specific options |
| 269 | if (formatProvider === "anthropic") { |
| 270 | // Anthropic prompt caching is already applied on Mux's manual cache markers |
| 271 | // (cached system message, conversation tail, last tool) deeper in the |
| 272 | // request pipeline. Do not also send top-level cacheControl here: the SDK |
| 273 | // serializes it to a top-level cache_control block, which adds an extra |
| 274 | // breakpoint on direct Anthropic requests. |
| 275 | |
| 276 | // Opus 4.5+, Sonnet 4.6, and Sonnet 5 use the effort parameter for reasoning control. |
no test coverage detected