Skip to content

refactor(ai-gateway): fold request logging into rewriteModelResponse - #4755

Merged
chrarnoldus merged 6 commits into
mainfrom
single-pass-request-logging-rewrite
Jul 27, 2026
Merged

refactor(ai-gateway): fold request logging into rewriteModelResponse#4755
chrarnoldus merged 6 commits into
mainfrom
single-pass-request-logging-rewrite

Conversation

@chrarnoldus

@chrarnoldus chrarnoldus commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What

Combines request logging and response rewriting so the upstream event stream is only processed once, and removes handleRequestLogging as a separate step.

Previously, when both request logging and response rewriting were active, the stream was consumed twice: once by handleRequestLogging (reading a cloned response via .text()) and once by rewriteModelResponse (parsing and rewriting SSE events).

Now:

  • handleRequestLogging.ts is deleted. Its logic (opt-in check, api_request_log insert from after()) lives in rewriteModelResponse.ts, which creates a RequestLogCapture from the passed RequestLoggingParams and records the raw upstream body while rewriting: the raw text for JSON responses, the raw decoded chunks for SSE streams.
  • When request logging is enabled, the rewrite pipeline runs for everyone with logging enabled (even when the rewrite would otherwise be skipped), so the body is captured in the same single pass. The organizationId !== KILO_ORGANIZATION_ID check in the skip condition is removed as redundant: the Kilo organization always has logging enabled and therefore always gets a capture.
  • The capture is settled on every path: stream completion, stream read errors, client disconnect (cancel()), JSON read errors, and before readResponseText rethrows unrecognized errors — so the after() callback awaiting it can never hang and the request is always logged (with response_body_read_error when the body is unavailable, preserving previous semantics).
  • Error responses replaced early by makeErrorReadable are logged via logUnrewrittenResponse, which reads the body once on that path.

processUsage is unchanged.

Tests

Added coverage in rewriteModelResponse.test.ts for body capture on JSON and SSE paths, empty bodies, stream read errors, JSON read errors, stream cancellation, and forced processing when request logging is enabled. route.test.ts now asserts the Vercel request ID is passed through to rewriteModelResponse's logging params.

Combine handleRequestLogging and rewriteModelResponse so the event stream
is only processed once. handleRequestLogging now returns a capture handle
instead of reading a cloned response; rewriteModelResponse accepts the
capture and records the upstream body while rewriting it. When request
logging is enabled the rewrite pipeline now runs for everyone so the body
is captured in the same pass. processUsage is unchanged.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
@chrarnoldus chrarnoldus self-assigned this Jul 24, 2026
@kilo-code-bot

kilo-code-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit resolves the previously flagged capture-hang risk by settling capture.setReadError in readResponseText before rethrowing unexpected errors and in the unrecognized-kind fallthrough; no new issues found in the changed lines.

Files Reviewed (1 file)
  • apps/web/src/lib/rewriteModelResponse.ts - previous WARNING resolved, no new issues
Previous Review Summaries (4 snapshots, latest commit cf5cd24)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit cf5cd24)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The incremental change removes the try/catch that used to settle the request-log capture on unexpected rewriteModelResponse_* rejections, which can leave the after() log-insert task waiting on an unresolved promise indefinitely and silently drop that request's log row.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/rewriteModelResponse.ts 699 Removed try/catch no longer settles the log capture when rewriteModelResponse_* rejects with an unexpected error, leaving the after() insert task hanging and the log row unwritten
Files Reviewed (3 files)
  • apps/web/src/app/api/openrouter/[...path]/route.ts - comment-only changes
  • apps/web/src/lib/rewriteModelResponse.test.ts - type rename/cleanup, no issues
  • apps/web/src/lib/rewriteModelResponse.ts - 1 issue

Fix these issues in Kilo Cloud

Previous review (commit fd68f42)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change moves request-log capture creation from the deleted handleRequestLogging.ts into rewriteModelResponse.ts (adding logUnrewrittenResponse for the early-error path) and updates callers/tests accordingly; the refactor preserves prior logging-gate and single-pass-read semantics with no new issues found.

Files Reviewed (4 files)
  • apps/web/src/app/api/openrouter/[...path]/route.ts
  • apps/web/src/app/api/openrouter/[...path]/route.test.ts
  • apps/web/src/lib/rewriteModelResponse.ts
  • apps/web/src/lib/rewriteModelResponse.test.ts

Previous review (commit dfd96c5)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change since the last review is a pure formatting update (Prettier line-wrapping of test.each calls) in rewriteModelResponse.test.ts, with no logic or assertion changes; combined with the previously reviewed request-logging/response-rewrite refactor, no issues were found.

Files Reviewed (4 files)
  • apps/web/src/app/api/openrouter/[...path]/route.ts
  • apps/web/src/lib/ai-gateway/handleRequestLogging.ts
  • apps/web/src/lib/rewriteModelResponse.ts
  • apps/web/src/lib/rewriteModelResponse.test.ts (formatting-only change since last review)

Previous review (commit ca00505)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Reviewed the single-pass request-logging/response-rewrite refactor across all four changed files; the RequestLogCapture handle is consistently set (body or read error) on every code path (JSON success/error, SSE normal completion, SSE stream error, SSE cancellation, empty body, and the early error-response path), with no signs of unresolved promises, double body reads, or logic errors introduced by this change.

Files Reviewed (4 files)
  • apps/web/src/app/api/openrouter/[...path]/route.ts
  • apps/web/src/lib/ai-gateway/handleRequestLogging.ts
  • apps/web/src/lib/rewriteModelResponse.ts
  • apps/web/src/lib/rewriteModelResponse.test.ts

Reviewed by claude-sonnet-5 · Input: 22 · Output: 3.9K · Cached: 447.6K

Review guidance: REVIEW.md from base branch main

chrarnoldus and others added 3 commits July 24, 2026 15:19
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
handleRequestLogging is folded into rewriteModelResponse: the wrapper
creates the request log capture itself from the logging params, so the
route makes a single call. Paths where the upstream response is replaced
by a readable error use logUnrewrittenResponse. The KILO_ORGANIZATION_ID
check in the skip condition is removed since the Kilo organization always
has request logging enabled and therefore always gets a capture.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
…d wrapper try/catch

- Rename RequestLogging to RequestLoggingParams.
- Remove comments that just restate the code.
- Remove the try/catch around the rewrite dispatch: it only guarded
  against unexpected throws from the JSON body read, which cannot
  happen in practice.
- Fix jest.mock not being hoisted in rewriteModelResponse.test.ts:
  use the global jest instead of the @jest/globals import, matching
  the other test files.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Comment thread apps/web/src/lib/rewriteModelResponse.ts
readResponseText rethrows errors that are not recognized abort/timeout
errors. Settle the capture before rethrowing so the after() callback
awaiting it does not hang and the request is still logged without a
response body. Addresses Kilobot review.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
@chrarnoldus chrarnoldus changed the title refactor(ai-gateway): capture request log body during response rewrite refactor(ai-gateway): fold request logging into rewriteModelResponse Jul 27, 2026
@chrarnoldus
chrarnoldus enabled auto-merge (squash) July 27, 2026 11:28
@chrarnoldus
chrarnoldus merged commit 21729bf into main Jul 27, 2026
14 checks passed
@chrarnoldus
chrarnoldus deleted the single-pass-request-logging-rewrite branch July 27, 2026 11:30
chrarnoldus added a commit that referenced this pull request Jul 27, 2026
Resolve conflicts with the squash-merged #4755 by keeping the branch
content, which already contains those changes plus this feature.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.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.

2 participants