Skip to content

fix: preserve assistant message phase through history (Phrase 1 of #335) - #383

Closed
Zheng-Lu wants to merge 1 commit into
vllm-project:mainfrom
Zheng-Lu:fix/335-assistant-message-phase
Closed

Zheng-Lu wants to merge 1 commit into
vllm-project:mainfrom
Zheng-Lu:fix/335-assistant-message-phase

Conversation

@Zheng-Lu

@Zheng-Lu Zheng-Lu commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Related to #335 (split from #350)

Summary

OpenAI marks assistant messages with phase (commentary or final_answer). The gateway's message types had no such field, so the value was dropped from the public response, from stored history, and from the input replayed on the next turn.

  • Add an optional, closed MessagePhase to input and output messages. It passes through completion, output-to-input conversion, storage and rehydration unchanged. The gateway never infers a phase: absent or null stays absent, and vLLM's "phase": null output is unchanged.
  • Reject phase on non-assistant input messages with a 400 before any inference.
  • Move InputMessage and OutputMessage into types/io/message.rs to stay within the file-size policy. Existing import paths still work. Rust struct literals must now set phase; the constructors default it to None.

Test Plan

  • cargo test -p agentic-server-core -p agentic-server: 1,728 passed, 0 failed, 17 ignored. cargo clippy --workspace --all-targets -- -D warnings, cargo fmt --check and pre-commit (including Rust file sizes) pass.
  • message_phase_test.rs replays the recorder-generated custom-tool-openai-reference-gpt-5.6 cassettes (JSON and SSE):
    • phase: final_answer reaches the public output.
    • A previous_response_id continuation replays it upstream.
    • Negative control: on main both values are missing, in both modes.
  • The same file covers the closed enum, absent and null legacy values, storage round trips, the upstream wire projection, and rejection for user, system and developer. openapi.rs checks the schema accepts absent, null and both values, and rejects unknown ones.
  • No cassette was added or edited.

OpenAI marks assistant messages as commentary or final_answer. The message
types had no phase field, so the value was dropped from public output, stored
history and replayed input. Model it as an optional closed enum, keep it through
conversion and storage, and reject it on non-assistant input.

Signed-off-by: Zheng Lu <Lz429671594@gmail.com>
@Zheng-Lu Zheng-Lu changed the title fix: preserve assistant message phase through history fix: preserve assistant message phase through history (Phrase 1 of #335) Sep 25, 2026
@maralbahari

Copy link
Copy Markdown
Collaborator

@Zheng-Lu thanks for the split. there seems to be overlap for the changes with #372 it adds support for phase and final_answer

@Zheng-Lu Zheng-Lu closed this Sep 29, 2026
@Zheng-Lu

Copy link
Copy Markdown
Contributor Author

@Zheng-Lu thanks for the split. there seems to be overlap for the changes with #372 it adds support for phase and final_answer

Thanks, you're right. I'll close #383.

The only behavior #383 adds is rejecting phase on non-assistant input messages with a 400; main currently forwards it upstream. If you'd like that check, I can open a small follow-up with the recorded-cassette regression test; otherwise nothing is lost.

@Zheng-Lu
Zheng-Lu deleted the fix/335-assistant-message-phase branch October 9, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants