Repository navigation
refactor(ai): use OpenAIChat assistant hook and drop OpenRouterBody cast - #57616
Conversation
There was a problem hiding this comment.
Thanks, the reasoning-alignment fix works. I ran the updated OpenRouter test against the base and it fails there, with reasoning coming back undefined. With this PR all OpenRouter tests pass, and packages/ai type-checks.
Public API is unchanged; this is internal to the OpenRouter provider body builder.
One regression to fix before merging. Unknown pass-through options in providerOptions used to override the lowered body, and now the body overrides them. OpenAIChat.fromRequest emits keys like temperature even when their value is undefined, so options such as providerOptions: { temperature: 0.1 } are now silently dropped even when the request doesn't set them (details inline).
| ? { include: false } | ||
| : known.usage | ||
| return { | ||
| ...options, |
There was a problem hiding this comment.
This flips the precedence between pass-through options and the lowered body. Before, the result was { ...body, messages, ...bodyOptions(...) }, so unknown providerOptions could override body fields. Now ...body comes after ...options. OpenAIChat.fromRequest emits keys such as temperature, top_p and max_tokens even when their value is undefined, so providerOptions: { temperature: 0.1 } now vanishes from the request even though the request never set a temperature. I checked: base sends "temperature": 0.1, and this PR omits it. Spreading ...options after ...body, as before, would keep the old behaviour.
There was a problem hiding this comment.
body should win
Problem
OpenRouterlowered assistant reasoning details in a post-processing pass overbody.messagesusingsourceAssistants[assistantIndex++], and cast the returned payloadas OpenRouterBody(whose rest record usedSchema.Any). WhenOpenAIChat.fromRequestskipped an empty assistant message during lowering,assistantIndexfell out of alignment withrequest.messages.Change
reasoningandreasoning_detailsinsideOpenAIChat.fromRequest'sassistantlowering hook so each lowered assistant message is paired with its exact sourceMessage.lenient(...)schemas and typeOpenRouterBodywithOptions.fields+JsonObjectsoprotocol.body.fromreturns a strongly-typedOpenRouterBodywithoutas OpenRouterBody.protocol.body.from(request) OpenAIChat.fromRequest(request, { cacheControl: cacheControl(), + assistant: (source, message) => attachReasoningDetails(source, message), }) - zip body.messages with sourceAssistants[assistantIndex++] - return { ...body, messages, ...bodyOptions(...) } as OpenRouterBody + bodyOptions(body, request.providerOptions, request.generation?.maxTokens) + decodeOptions(openrouter) + return { ...options, ...body, ...knownOptions }Out of scope
OpenAIChat.protocol.streamis unchanged).