Skip to content

feat: accept configuration_update input items and keep them in place - #499

Open
sohom-cs wants to merge 2 commits into
vllm-project:mainfrom
sohom-cs:feat/configuration-update-items
Open

sohom-cs wants to merge 2 commits into
vllm-project:mainfrom
sohom-cs:feat/configuration-update-items

Conversation

@sohom-cs

@sohom-cs sohom-cs commented Nov 2, 2026 •

Copy link
Copy Markdown

Summary

Part of #331 (step 1 of the split in my comment there).

Since #464, an input item with an unmodeled type fails at the request boundary, and configuration_update is not modeled. A request that changes the reasoning effort as the reasoning guide describes, with {"type": "configuration_update", "reasoning": {"effort": "high"}} before the next user message, gets a 400 today, with or without previous_response_id.

This PR:

  • adds InputItem::ConfigurationUpdate with a typed ConfigurationUpdateItem (optional id, reasoning.effort). effort must be a non-empty string. Any other field fails parsing instead of being dropped: newer OpenAI SDKs also allow a text update and "effort": null, which stay rejected for now.
  • keeps the item where the client put it: in the stored input items, in history loaded through previous_response_id or conversation, and in the input sent upstream. The request-level reasoning.effort is not rewritten, and the response's reasoning still reports it.
  • adds RequestPayload::effective_reasoning_effort(): the effort of the last update in the input, history included, or else reasoning.effort. Nothing acts on it yet; step 2 uses it.
  • covers the variant in the exhaustive matches, the InputItem OpenAPI schema (one closed object, like the code_interpreter tool), docs/api/index.md and the CHANGELOG.
  • rejects an update, in the input or in history, with a 400 before any upstream call when the request can compact: a compaction entry in context_management, a compaction_trigger, or multi_agent (each agent compacts automatically), and at /v1/responses/compact. Compaction keeps only user messages and its summary, so the update would drop out of the input after compaction and out of every later turn (from the review).

Not in this PR (steps 2 and 3): checking upstream support before inference, rejecting adjacent updates, WebSocket continuation, and keeping an update through a compaction checkpoint instead of rejecting it. Until then the gateway forwards the item as is; vLLM main does not convert this item type and answers 400 (read in responses/utils.py and harmony.py, not run).

Test Plan

  • types::io::input::configuration_update unit tests: payload and position survive parsing, serialization and model_input; eight malformed shapes are rejected; with two updates in the history, the last one is the effective effort while the upstream request keeps reasoning.effort and both items in place.
  • tests/configuration_update_test.rs (HTTP, in-memory SQLite, an upstream that records each request): a stored turn, then previous_response_id (the first turn's three input items reach the upstream again unchanged, and input_items lists the update in place); a branch from an earlier response does not inherit it; conversation history; a store: false replay; malformed updates get 400 before the upstream is called.
  • With only the production changes reverted, the four HTTP tests that send a valid update fail with 400.
  • From the review: an_update_is_rejected_where_compaction_would_drop_it sends six requests (automatic compaction with the update in the input or only in history, compaction_trigger, multi_agent, and /v1/responses/compact with either); each gets 400 and the upstream is not called. All six got 200 on fd83ed7. an_update_sent_after_compaction_reaches_the_next_turn sends an update after a compaction_trigger turn and finds it in the next turn's upstream input.
  • openapi unit tests: the fixtures and the strict history schema include the item.
  • cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test -p agentic-server-core -p agentic-server (2937 passed) and pre-commit run --all-files pass on Rust 1.98.1, the pinned toolchain.
  • Not run against a live vLLM server.

AI-assisted; reviewed and tested by me.

Since vllm-project#464 an input item with an unmodeled type fails at the request
boundary, so a request that changes the reasoning effort with a
configuration_update item before the next user message got a 400.

InputItem gains a typed ConfigurationUpdate variant. The item keeps its
position in the stored input items, in history loaded through
previous_response_id or conversation, and in the input sent upstream.
The request-level reasoning.effort is not rewritten.
RequestPayload::effective_reasoning_effort returns the effort of the
last update in the input, or else reasoning.effort.

An update must carry a non-empty reasoning.effort and no other
reasoning field. Upstream capability checks, adjacent updates and the
WebSocket and compaction cases are left for the next changes.

Part of vllm-project#331.

Signed-off-by: Sohom Chakraborty <16609933+sohom-cs@users.noreply.github.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T03:52:18.019938Z fd83ed7 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd83ed73a9

ℹ️ 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".

Comment on lines +54 to +57
Json(json!({"id": "resp_upstream", "object": "response", "created_at": 1, "model": "test-model",
"status": "completed", "usage": {"input_tokens": 3, "output_tokens": 1, "total_tokens": 4},
"output": [{"type": "message", "id": format!("msg_answer_{id}"), "role": "assistant",
"status": "completed", "content": [{"type": "output_text", "text": format!("answer {id}")}]}]}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add recorded coverage for configuration-update continuation

For a real-provider turn containing a configuration_update and a subsequent previous_response_id continuation, this stub unconditionally returns success, so the new tests cannot detect provider rejection or different update semantics. A repository-wide rg configuration_update finds no recorder scenario or cassette. The cassette rule in .agents/skills/pr-review/SKILL.md, required via AGENTS.md, requires recorded replay coverage at this material wire/continuation boundary. Extend the existing Responses recorder with a stored low-effort turn, a high-effort update before the next user message, and continuation/input-items checks, capturing the actual OpenAI and gateway outcomes and asserting them in replay.

AGENTS.md reference: AGENTS.md:L7-L11

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no recording for this yet. The OpenAI side has to be a real capture against a model that supports the item (the reasoning guide names GPT-6 and later), and a gateway capture in front of vLLM would only record vLLM rejecting it, since vLLM main has no configuration_update handling yet; a hand-written cassette wouldn't count. The PR changes only the gateway's own handling: configuration_update_test.rs asserts the exact upstream input on each continuation path, and that a compacting request with an update is rejected before any upstream call. I'll add a recorder scenario once I can run the capture.

@franciscojavierarceo franciscojavierarceo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i found one compaction continuation issue below.

| InputItem::AgentMessage(_)
| InputItem::McpListTools(_)
| InputItem::CompactionTrigger
| InputItem::ConfigurationUpdate(_)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configuration_update is accepted on a request that can also compact, but retained_user_window keeps only user messages and the summary. after compaction, the update disappears from the stored window, so a later continuation can lose the effective reasoning effort. we should reject this combination until compaction can preserve the update's position and semantics, or retain it in the compacted window with a regression covering the next turn.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduced on fd83ed7: with automatic compaction the update was gone from the compacted input, from the stored window and from the next turn, and compaction_trigger and /v1/responses/compact dropped it the same way. I went with rejecting the combination for now, in 6f667b2. When the input or history has a configuration_update, a request that can compact gets a 400 before anything reaches the upstream: a compaction entry in context_management, a compaction_trigger, or multi_agent (each agent compacts automatically). /v1/responses/compact rejects it too, as #331 describes for the reference.

an_update_is_rejected_where_compaction_would_drop_it covers six cases, including a next turn that turns on compaction with the update only in history; all six returned 200 on fd83ed7. an_update_sent_after_compaction_reaches_the_next_turn checks that an update sent after a compaction still reaches the turn after it.

Keeping the update in the compacted window needs more than retained_user_window: the window rules in types/io/input/window.rs hide everything before a checkpoint except retained user messages and open async calls, so the next turn would still lose it. I'd rather do that with the compaction_trigger step of #331.

Compaction keeps user messages and its summary only, so a
configuration_update in the compacted input disappeared from the input
after compaction, from the stored window and from later turns, and a
continuation lost the effective reasoning effort.

Until compaction keeps the item, a request that can compact rejects an
update in its input or history with a 400 before any upstream call: a
context_management compaction entry, a compaction_trigger item, or
multi_agent, which compacts each agent automatically.
/v1/responses/compact rejects it too. An update sent after a compaction
still reaches later turns.

Part of vllm-project#331.

Signed-off-by: Sohom Chakraborty <16609933+sohom-cs@users.noreply.github.com>

This branch has not been deployed

No deployments
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