Skip to content

feat(responses): process every body-bearing Responses operation - #1374

Open
cdoern wants to merge 2 commits into
praxis-proxy:mainfrom
cdoern:feat/responses-request-body-bearing-operations
Open

cdoern wants to merge 2 commits into
praxis-proxy:mainfrom
cdoern:feat/responses-request-body-bearing-operations

Conversation

@cdoern

@cdoern cdoern commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Progresses #741.

Problem

openai_responses_request recognized only createResponse, so it released POST /v1/responses/compact and POST /v1/responses/input_tokens untouched. The validation stage it replaces handled both. That is why the migrated compact chain returned 404 for an unknown previous_response_id where it previously returned 400, and why compact.yaml was reverted from the previous PR.

Change

Two commits, deliberately separate because they are different kinds of change.

Parity — process every body-bearing operation. The registry already records which operations declare a request body, so that declaration selects what is worth parsing instead of naming one operation. Bodyless operations — fetch, delete, cancel, list input items, and the WebSocket handshake — are still released untouched, and that set can no longer drift from the registry the way a hand-written path list would.

Behavior change — an absent optional body is valid. The specification marks the compact and input-token-count bodies optional, so a request without one is complete. Both the old classifier and the first commit here classified the missing body as non_json and ran it through on_invalid, which returns 400 under reject for a well-formed request. That is a fix, not a port: this diverges from the filters being replaced rather than reproducing them.

An absent body is still invalid where the specification requires one, and a body that was supplied but does not parse is still invalid either way — optional means it may be omitted, not that a broken one is acceptable.

Verification

examples::compact passes 17/17; that suite is what exposed the gap.

Each commit is checked by reverting it in isolation and confirming exactly one test fails:

  • create-only gate restored → other_body_bearing_responses_operations_are_processed
  • optional-body guard removed → an_absent_optional_body_is_not_an_invalid_body

Unit tests 4517 pass, 0 fail. make lint passes, including the lean build and the generated-doc sync checks.

Scope

This does not close #741. Twenty-eight example configs still run openai_responses_format and openai_responses_validate, and neither filter can be deleted until they are migrated. None of those configs route compact or input-token-count, so migrating them does not depend on this change and can proceed in parallel.

Roughly seventeen are the same shape as the ten already migrated. The remainder need design work rather than a config swap: the Chat Completions translation chains rewrite the path away from /v1/responses, so head-based matching does not see the operation on re-entry.

Checklist

  • Unit tests
  • Integration tests
  • Example config in examples/configs/
  • Functional integration test for the example config
  • Generated filter documentation regenerated

The create request processor recognized only `createResponse`, so it
released `POST /v1/responses/compact` and `POST /v1/responses/input_tokens`
untouched. The validation stage it replaces handled both, which is why a
migrated compact chain returned 404 for an unknown `previous_response_id`
where it previously returned 400.

Select operations by the request-body shape the registry already records
rather than by naming one operation. Bodyless operations — fetch, delete,
cancel, list input items, and the `WebSocket` handshake — are still
released untouched, and that list cannot drift from the registry the way a
hand-written path list would.

Migrates the compact example, whose 404 exposed the gap.

Tests cover both directions: the four bodyless operations publish nothing
and initialize no state, and compact and input-token-count are classified
and given state as the validator gave them. Restoring the create-only gate
fails `other_body_bearing_responses_operations_are_processed`.

Signed-off-by: Charlie Doern <cdoern@redhat.com>
The specification marks the compact and input-token-count request bodies
optional, so a request without one is complete. Both the previous
classifier and this processor classified the missing body as `non_json`
and ran it through `on_invalid`, which returns a 400 under `reject` for a
request that is actually well formed.

Carry the declared body shape out of the registry match instead of a bare
"has a body" flag, and release an operation whose optional body is absent
before any parsing or `on_invalid` handling.

An absent body is still invalid where the specification requires one, and
a body that was supplied but does not parse is still invalid either way —
optional means it may be omitted, not that a broken one is acceptable.

This diverges from the behavior of the filters being replaced rather than
reproducing it. Removing the guard fails
`an_absent_optional_body_is_not_an_invalid_body`.

Signed-off-by: Charlie Doern <cdoern@redhat.com>
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.

refactor(responses): consolidate create request processing

1 participant