Skip to content

fix(logs,web-search): bound response inspection and withheld search events (#4775, #4743) - #4801

Merged
lidge-jun merged 12 commits into
devfrom
codex/r2570-response-lifecycle-carry
Sep 16, 2026
Merged

lidge-jun merged 12 commits into
devfrom
codex/r2570-response-lifecycle-carry

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Summary

Carries #4775 and #4743 onto the current dev head with the fixes their review found. Both bound a buffer that grows without limit today; neither may drop user output to do it.

Bounded response inspection (#4775)

The change holds: createBoundedResponseLogBody and teeWithBoundedInspection each finalize exactly once across EOF, read error and cancellation, and neither awaits a tee sibling's cancel promise. The carry fixes a mechanical defect in the authoring: three structure paragraphs were written with a literal two-character backslash-n instead of a newline, so each rendered glued to the following heading. Docs text only.

Two behaviour notes recorded rather than blocked on. The non-stream JSON and error path now forwards chunk by chunk instead of buffering and emitting once, so a mid-body upstream failure can arrive after partial bytes: same failure class, different shape, and it is the point of the change. And the tee's pacing bound is one-sided, bounding inspection running ahead of the client but not the reverse; inspection is the fast side in practice.

Withheld search events (#4743)

The cleanup is right: failLegFrames closes every search cell the leg opened as failed before exactly one response.failed and one [DONE], read failure and overflow share that single path, and lazy release cannot double-emit.

The carry changes two things. The event bound was 1,000, which counts every held function_call_arguments delta, so a sizeable client-executed apply_patch streamed as fine-grained deltas could plausibly cross it and the leg would then fail and discard a legitimate tool call. Bounding memory must not cost a valid call, so the count is re-derived from the 8 MiB code-unit budget that is the actual memory guard, with the derivation stated in the comment instead of another unexplained constant. And overflow reported itself through the upstream-read-failure message, blaming the provider for a proxy-side admission bound; it now reads as what it is.

One pre-existing residual is explicitly not addressed here: decide() returns end when no search ran, before inspecting the terminal, so a leg with a client-executed call and a failed terminal still releases the held call. That predates this change and the phase doc defers it.

Verification

  • Static and source-oracle review of both carries against current dev, including single-finalization across EOF, read error and cancellation, and the four flushHeldCalls call sites.
  • Exact-head hosted CI on this branch is the gate.
  • No local suite, focused test, typecheck, build, install, or service command was run.

Checklist

  • Targets dev.
  • Preserves the original author with Co-authored-by trailers.
  • No default is altered and no authorization surface is widened.
  • Exact-head hosted CI is green.
  • Maintainer review is complete.

Summary by CodeRabbit

  • New Features

    • Added bounded response inspection for streaming and non-streaming responses.
    • JSON inspection retains up to 32 MiB; non-JSON diagnostics retain up to 8 KiB.
    • Added pacing and post-disconnect limits for SSE inspection.
    • Added safeguards for client cancellations, read failures, oversized payloads, and incomplete data.
    • Added limits for buffered web-search tool events.
  • Documentation

    • Added a Response Inspection guide and documented the bounded inspection contract across product documentation.

luvs01 and others added 12 commits September 16, 2026 11:04
…lure

Carry the held-event limits and lazy flush from luvs01#481 onto current upstream dev. Close the source review finding by routing read/limit failures through shared pre-execution leg cleanup. Add stream lifecycle regressions and document the UTF-16 accounting boundary.

Source commit: 1efcfad
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Adapt luvs01#177 and #106 onto current dev. Preserve terminal ownership with bounded tee read-ahead, stream non-SSE bodies, and cover cancellation races.
Preserve the exact conflict-free GitHub merge tree for PR #4775. Upstream advanced 48 commits after the pinned implementation baseline; no response-inspection patch content or validation claims are rewritten.
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
The bounded-response-inspection change wrote a literal two-character
backslash-n instead of a newline at three paragraph boundaries, so
structure/runtime.md, structure/transports/byte-accounting.md and
structure/transports/responses.md each render a stray "\\n" glued to the
start of the following heading or paragraph.

Restore the intended blank-line separation. Documentation text only; no
runtime, test or contract change.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
… proxy bound

A flat cap of 1,000 withheld client-tool events discarded legitimate work.
Every held event counts, including each response.function_call_arguments.delta
for a withheld call, so a sizeable client-executed tool call streamed as
fine-grained deltas -- an ordinary apply_patch, not an exotic case -- crossed
the cap, failed its leg and dropped the tool call. Bounding a leak by trading
it for a different user-visible failure is what this release is not allowed
to do.

Derive the cap from the budget that actually guards memory instead. A
fine-grained argument delta serializes to roughly 128 code units, so the
existing 8 MiB MAX_HELD_CALL_CHARS budget is exhausted at 65,536 such events;
the count is set there and now only bounds the per-event object overhead the
character budget cannot see. The derivation is stated at the constant so the
next reader does not inherit another unexplained number.

Also report overflow as the bridge's own admission bound. It was thrown as a
plain Error into the upstream-read catch and surfaced to the client as
"web-search bridge upstream read failed", blaming the provider for a refusal
this proxy made. A distinct HeldCallBudgetExceededError keeps the two apart.

Tests follow the exported constant rather than a hardcoded boundary, so the
acceptance and refusal cases stay pinned to the real limit, and a regression
asserts the overflow message is not attributed to the upstream.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f31a5be5-5c09-431d-ab53-fe9f645f456d

📥 Commits

Reviewing files that changed from the base of the PR and between ada3a9b and 14b4d30.

📒 Files selected for processing (29)
  • docs-site/astro.config.mjs
  • docs-site/src/content/docs/guides/response-inspection.md
  • scripts/test-layout/layout.json
  • src/server/inspection-tee.ts
  • src/server/relay.ts
  • src/server/response-log-body.ts
  • src/server/responses/passthrough-delivery.ts
  • src/web-search/passthrough-bridge.ts
  • structure/adapters/registry.md
  • structure/catalog.md
  • structure/clients/claude-desktop.md
  • structure/data-planes/images.md
  • structure/data-planes/inbound-compat.md
  • structure/gui-and-management-api.md
  • structure/ops/docs-and-release.md
  • structure/ops/service-and-sidecars.md
  • structure/overview.md
  • structure/providers/xai-grok.md
  • structure/runtime.md
  • structure/subagents.md
  • structure/transports/byte-accounting.md
  • structure/transports/inventory.md
  • structure/transports/responses.md
  • structure/transports/streaming-health.md
  • tests/fixtures/test-layout-expected.json
  • tests/responses/passthrough-abort.test.ts
  • tests/server/response-log-inspection.test.ts
  • tests/usage/request-log-nonstream.test.ts
  • tests/web-search/web-search-progress-stream.test.ts

📝 Walkthrough

Walkthrough

The pull request adds bounded response-log inspection, paced SSE inspection, and bounded web-search event buffering. It preserves streamed response bytes, records bounded terminal states, adds lifecycle tests, and documents the inspection contract.

Changes

Bounded streaming contracts

Layer / File(s) Summary
Bounded response-log body handling
src/server/response-log-body.ts, src/server/relay.ts, tests/usage/request-log-nonstream.test.ts, tests/server/response-log-inspection.test.ts
Response bodies retain bounded byte prefixes and forward original chunks unchanged. Finalization records EOF, read-error, or cancellation states. Non-stream request logging preserves response metadata and records 499 or 502 where applicable.
Paced SSE inspection delivery
src/server/inspection-tee.ts, src/server/responses/passthrough-delivery.ts, tests/server/response-log-inspection.test.ts, tests/responses/passthrough-abort.test.ts
SSE inspection uses a bounded tee paced against client consumption. Client departure and branch errors release pacing. Tests cover limits, cancellation, drain behavior, source errors, and terminal handling.
Web-search held-event bounds
src/web-search/passthrough-bridge.ts, tests/web-search/web-search-progress-stream.test.ts, structure/runtime.md
Held client-tool events use 8 MiB and derived event-count limits. Overflow and read failures share cleanup that drops held events, closes search cells, and emits bridge failure output.
Inspection contract documentation and wiring
docs-site/..., structure/..., scripts/test-layout/layout.json, tests/fixtures/test-layout-expected.json
The response-inspection guide, transport contract, repository documentation, sidebar, and test-layout mappings describe the new bounds and lifecycle behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PassthroughDelivery
  participant InspectionTee
  participant ResponseLogInspector
  Client->>PassthroughDelivery: request streamed response
  PassthroughDelivery->>InspectionTee: tee passthrough SSE body
  InspectionTee-->>Client: forward client branch
  InspectionTee-->>ResponseLogInspector: paced inspection branch
  Client->>PassthroughDelivery: consume or disconnect
  PassthroughDelivery->>InspectionTee: release pacing on client departure
  ResponseLogInspector-->>PassthroughDelivery: inspect terminal and usage state
Loading
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/r2570-response-lifecycle-carry

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 16, 2026
@lidge-jun
lidge-jun marked this pull request as ready for review September 16, 2026 10:54
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 16, 2026 10:54
@lidge-jun
lidge-jun merged commit c272309 into dev Sep 16, 2026
31 of 32 checks passed
@lidge-jun
lidge-jun deleted the codex/r2570-response-lifecycle-carry branch September 16, 2026 10:54
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 16, 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-09-16T10:58:02.825882Z 14b4d30 Draft marked ready
ℹ️ 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants