fix(openrouter): preserve reasoning details#796
Conversation
9ac10fd to
a05ac48
Compare
4b47895 to
a18e86c
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a18e86c0e5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ReqLLM.Message.ReasoningDetails.to_openai_compatible(detail) | ||
| end | ||
|
|
||
| defp encode_reasoning_detail_for_openai(_detail), do: nil |
There was a problem hiding this comment.
Preserve raw reasoning detail maps during encoding
When a caller reuses a legacy or persisted context whose reasoning_details are already raw OpenAI-compatible maps, the normal request path now enables encode_reasoning_details?: true and this catch-all filters every non-%ReasoningDetails{} entry out. That means those conversations silently stop sending the prior reasoning metadata on the next OpenAI-compatible request; before this change the raw maps were passed through unchanged.
Useful? React with 👍 / 👎.
| reasoning_details = decode_openai_reasoning_details(details, model.provider) | ||
| [ReqLLM.StreamChunk.meta(%{reasoning_details: reasoning_details})] |
There was a problem hiding this comment.
Don't pre-normalize MiniMax stream details
For MiniMax streaming responses that include delta.reasoning_details, this now converts the raw MiniMax wire maps into generic %ReasoningDetails{} before ReqLLM.Providers.Minimax.decode_stream_event/2 pipes the chunks through its MiniMax-specific normalizer. That normalizer expects raw maps with string keys like "id" and "text"; given a struct, it treats it as a map and loses the text/signature fields, corrupting streamed MiniMax reasoning continuity.
Useful? React with 👍 / 👎.
Description
This PR preserves OpenAI-compatible
reasoning_detailsacross ReqLLM's provider boundary.OpenRouter can return
reasoning_detailsas OpenAI-compatible wire maps with provider-specific metadata such astype, signatures, encrypted-signature markers, indexes, and other opaque fields. ReqLLM already has a normalized%ReqLLM.Message.ReasoningDetails{}struct withprovider_data; this change makes that contract explicit and lossless across decode, context storage, and provider-boundary re-encoding.This change:
reasoning_detailsinto%ReqLLM.Message.ReasoningDetails{}.provider_datafor lossless round-trips.reasoning_detailsas the internal representation by default.encode_context_to_openai_format/3option,encode_reasoning_details?: true, for callers that intentionally need OpenAI-compatible wire maps.#791 has landed. This branch has been rebased onto current
agentjido/mainas a single reasoning-details commit.Type of Change
Breaking Changes
None expected.
The internal representation becomes stricter and more consistent: OpenAI-compatible
reasoning_detailsdecoded byReqLLM.Provider.Defaultsare normalized to%ReqLLM.Message.ReasoningDetails{}. Existing raw maps are still tolerated in provider-specific encoders where they were already accepted.Testing
mix test)mix quality)Ran focused tests:
Ran full tests:
Ran project quality gate:
GitHub CI is green on commit
a18e86c0e5d8359309ee9e632936bc50cf4f157e.Model Compatibility
No live model compatibility fixtures were recorded for this PR.
The change is local decode/encode behavior for OpenAI-compatible reasoning metadata and provider-boundary request rendering. It is covered by unit/provider tests for:
Checklist
CHANGELOG.md(it is auto-generated by git_ops)Docs note: no docs were updated because this is an internal provider-boundary correctness fix for existing
reasoning_detailsdata, not a new public user-facing API.