feat(openai): Reasoning translation for responses to chat completions - #1014
s-akhtar-baig wants to merge 24 commits into
Conversation
|
Unsigned commits: 64fee79. Please sign your commits. |
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
eac84ad to
cd8bde4
Compare
c8f8865 to
ae91290
Compare
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
…hat_completions filter Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
ae91290 to
7aedf8f
Compare
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
praxis-bot
left a comment
There was a problem hiding this comment.
praxis-bot review: feat(openai): Reasoning translation for responses to chat completions
Clean feature addition. The reasoning dialect abstraction is well-structured, validation is thorough, and test coverage is strong across request validation, response extraction, dialect fallback, size limits, and the end-to-end integration path. The resolve_vllm_reasoning field-priority logic correctly handles all combinations of current/deprecated/null/empty/malformed field states.
One medium finding on the response path.
| Severity | Count |
|---|---|
| Medium | 1 |
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
leseb
left a comment
There was a problem hiding this comment.
[P1] Reasoning breaks stored continuations. Emitted reasoning items are persisted and rehydrated, but Chat translation rejects type: "reasoning" as unsupported. previous_response_id and agentic tool continuations therefore return 400 after a reasoning-bearing response. Emission, rejection
[P1] Streaming silently discards vLLM reasoning. Streaming requests pass validation, but ChatDelta does not model vLLM’s delta.reasoning; unknown fields are ignored. Either translate reasoning deltas or reject streaming when the dialect is enabled. Validation, stream delta
[P2] Malformed summary controls are silently accepted. summary and generate_summary use Value::as_str, making booleans, objects, arrays, and numbers indistinguishable from absent fields. Requests such as "summary": true are forwarded with the option silently dropped. reasoning.rs
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
|
Thanks, @leseb, for reviewing this PR! I have updated accordingly and will implement streaming reasoning in a follow-up PR. PTAL when you get a chance. |
Thanks, another round :) [P1] Continuation reasoning is silently discarded. The previous 400 was replaced with an empty match arm. Stored continuations and agentic tool rounds now succeed but omit the prior raw reasoning, which reasoning models may require between tool calls. chat_completions.rs:558 [P2] Reasoning-only completions are rejected. Response validation counts only content, refusal, or tool calls as output. A valid vLLM response containing reasoning but no final text fails before the new reasoning item can be emitted. chat_completions.rs:1267 [P2] Non-object reasoning is silently ignored. Values such as "reasoning": true bypass validation, lose their controls during translation, and can receive an ordinary successful response. This proxy-owned field should return 400 when it is neither an object nor null. reasoning.rs:92 |
|
we also need new tests in tests/integration/sdk/openai/test_openai_responses_vllm.py |
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
|
Thanks, @leseb! For P1, I am not sure where to add reasoning across calls. I looked at the OpenAI and vLLM chat completions docs and neither of those show re-adding raw reasoning as part of input messages or any other field. Did you have anything specific in mind? |
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
|
@leseb, can you please re-review when you get a chance? Thanks! |
The main concern is the silent drop. For this PR, we should either:
I'm leaning implementing the replay now. |
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
|
@leseb, I have implemented replay for reasoning. The prior turn's chain-of-thought now gets added to the assistant message that follows it, wrapped in markers (… by default). Note that these delimiters are configurable. PTAL when you get a chance, thanks! |
leseb
left a comment
There was a problem hiding this comment.
One blocker remains.
The silent drop is fixed, but reasoning is replayed as ordinary content:
{"content":"<think>...</think>answer"}For the vllm dialect, it should instead be:
{"reasoning":"...","content":"answer"}vLLM supports this field and uses it in its own Responses converter. Marker injection is model/template-dependent.
Recommendation: replace the marker logic with assistant.reasoning, update the tests, then approve. The focused 160 tests pass and the branch merges cleanly, but full CI is still pending. I posted nothing on GitHub.
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
|
Thanks, @leseb, for pointing this out! I have removed the markers and replaced with the reasoning field. PTAL when you get a chance. |
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Signed-off-by: Shabana Baig <43451943+s-akhtar-baig@users.noreply.github.com>
Summary
Adds a configurable reasoning dialect to the responses_to_chat_completions filter so that raw chain-of-thought returned by a Chat Completions backend is surfaced as a first-class Responses reasoning output item. The first dialect is vllm; the default (none) preserves existing behavior.
A reasoning summary request is currently rejected and is out of scope for #31.
Related issue
Implements part one for #31. Streaming reasoning translation is deferred to #36 and will be added as a follow-up PR once all the bug fixes land in main.
Validation
make lintChecklist
Signed-off-bytrailer.Breaking changes