Repository navigation
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
e97105a to
3dd8fea
Compare
3dd8fea to
bd3fade
Compare
|
| response.raw_headers = [ | ||
| (name, header_value) | ||
| for name, header_value in _end_to_end_headers(value.headers) | ||
| if not may_modify or name.lower() != b"content-length" | ||
| ] |
There was a problem hiding this comment.
Stale headers on guarded streams When a guarded stream blocks content, emits an error event, or drops an unfinished tail, its bytes differ from the provider response. This code removes
Content-Length but still forwards headers such as ETag, Content-MD5, and Digest unchanged. A client verifying the body can reject it, and a cache can associate a validator with bytes it does not describe. Remove or recompute headers that depend on the original body whenever the stream may change.
Prompt To Fix With AI
This is a comment left during a code review.
Path: nemoguardrails/server/experimental/_streaming_http.py
Line: 99-103
Comment:
**Stale headers on guarded streams** When a guarded stream blocks content, emits an error event, or drops an unfinished tail, its bytes differ from the provider response. This code removes `Content-Length` but still forwards headers such as `ETag`, `Content-MD5`, and `Digest` unchanged. A client verifying the body can reject it, and a cache can associate a validator with bytes it does not describe. Remove or recompute headers that depend on the original body whenever the stream may change.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
@greptileai this is resolved in the latest commit. Do you confirm?
There was a problem hiding this comment.
Yes, this is resolved. The latest implementation defines _BODY_DEPENDENT_HEADERS with content-length, content-md5, content-digest, digest, etag, and repr-digest, and _streaming_response(..., may_modify=True) filters all of them before returning the guarded response. The uninspected relay keeps the original headers (may_modify=False), so valid transparent responses still preserve their validators. I confirm the previous stale-validator finding is addressed.
bd3fade to
5814177
Compare
5814177 to
50a025d
Compare
This comment has been minimized.
This comment has been minimized.
50a025d to
fe7408e
Compare
fe7408e to
9112df3
Compare
| if streaming_policy is not None: | ||
| validate_streaming_policy(streaming_policy) | ||
| # An encoded stream cannot be inspected; uninspected relays keep the client's preference. | ||
| request = replace(request, headers=_request_identity_encoding(request.headers)) |
There was a problem hiding this comment.
Identity encoding against client preference If a streaming client explicitly forbids an identity response, for example with
Accept-Encoding: gzip, identity;q=0, this line still asks the provider for identity. The inspected stream is then returned without a content encoding, so the client may receive a response it said it cannot accept. Reject that request or negotiate an acceptable downstream encoding.
Prompt To Fix With AI
This is a comment left during a code review.
Path: nemoguardrails/server/experimental/_streaming_http.py
Line: 176
Comment:
**Identity encoding against client preference** If a streaming client explicitly forbids an identity response, for example with `Accept-Encoding: gzip, identity;q=0`, this line still asks the provider for identity. The inspected stream is then returned without a content encoding, so the client may receive a response it said it cannot accept. Reject that request or negotiate an acceptable downstream encoding.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Make the streaming response the owner of the upstream body. It closes the body iterator and the source in a shielded cleanup, so a client disconnect or send failure before the first chunk no longer leaks the provider connection. Reject a non-user input message before dispatch instead of failing after the response starts. Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
An inspected stream may withhold events, emit a provider-native error, or drop an unfinished tail, so validators computed over the provider body no longer describe the bytes sent downstream. Remove ETag, Content-MD5, Digest, Content-Digest, and Repr-Digest alongside Content-Length whenever the stream may change. Uninspected relays keep every end-to-end header. Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Clients such as the OpenAI SDK send Accept-Encoding: gzip, and inspected streams reject a provider stream that is not identity-encoded. A compressing provider therefore turned every inspected streaming request into a proxy error. When the stream is inspected, replace Accept-Encoding with identity before dispatch, matching buffered output inspection. Uninspected relays forward the client's preference unchanged, and a still-encoded inspected stream remains rejected. Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
9112df3 to
6668113
Compare
Summary
Adds an injected streaming HTTP lifecycle bridge around the provider-neutral runner, including response validation and reliable source closure.
What Changed
Review Notes
Review pre-header validation, framing, transparent relay, and closure. Dispatch remains injected; concrete outbound HTTP and application client lifecycle remain separate work.
AI Assistance
Checklist
Stack Position
Part 3 of 4.
Stack Context
Adds OpenAI Chat streaming above #2414 in four parts: provider-neutral execution, typed OpenAI stream declarations and handwritten hooks, injected HTTP lifecycle handling, and integration with the buffered request pipeline.
The open chain is #2411 → #2413 → #2414 → #2434 → #2435 → #2436 → #2437. #2412 is closed; its provider provenance and boundary documentation are included in #2413.
Python declarations own field and event policy. Hooks are handwritten and created for each stream by the integration. The shared exporter currently emits buffered policy; streaming contract export remains separate work. Concrete outbound HTTP, deployment configuration, and replacement execution land separately.
Review each PR against its listed base branch.
pouyanpi/transparent-proxy-streaming-kernel-1pouyanpi/openai-chat-buffered-integration-4pouyanpi/openai-chat-streaming-contract-2pouyanpi/transparent-proxy-streaming-kernel-1pouyanpi/transparent-proxy-streaming-http-3pouyanpi/openai-chat-streaming-contract-2pouyanpi/openai-chat-streaming-integration-4pouyanpi/transparent-proxy-streaming-http-3Summary by CodeRabbit