Repository navigation
Request logs can miss successful ChatGPT native passthrough turns #44
Description
Summary
I am seeing a request-log gap for successful ChatGPT/native passthrough turns. Routed providers such as umans and opencode-go appear in /api/logs, but successful gpt-5.5 / chatgpt turns do not show up. A non-stream chatgpt 503 does show up, so the issue seems specific to successful native passthrough SSE finalization rather than all ChatGPT requests.
This looks like a follow-up edge case around the native passthrough SSE workaround from #31.
Observed evidence
Current runtime:
ocx status --jsonreports proxyv2.6.0, PID32544, health OK, default providerchatgpt.- Codex is configured to route through opencodex at
http://localhost:10100/v1. /api/logscurrently groups as:umans: 104 entries, all200opencode-go: 18 entries, all200chatgpt: 1 entry,503
- The only
chatgptentry is:- local time
2026-06-28 16:44:07 +09:00 - model
gpt-5.5 - status
503 - errorCode
server_is_overloaded - closeReason
non_stream - usageStatus
unreported
- local time
- During the same session, Codex session JSONL showed completed
gpt-5.5turns withmodel_provider: "opencodex"/comp_hash: "opencodex", but those successful turns were not visible in/api/logs. - The proxy stdout log repeatedly contains:
1 | (function (controller, error) {"use strict";
^
TypeError: null is not an object
Code path that looks suspicious
In src/server.ts, native passthrough SSE uses upstreamResponse.body.tee():
- branch 0: returned directly as the client-facing
Responsebody viamarkNativePassthroughSseResponse(...) - branch 1: consumed in the background by
consumeForInspection(...)
Then responseWithDeferredRequestLog(...) skips normal request-log wrapping for native passthrough SSE responses:
if (isNativePassthroughSseResponse(response)) {
return response;
}So successful native passthrough logs depend on the background inspection path calling onNativePassthroughTerminal.
The cancel path looks like it can suppress finalization:
consumeForInspection(...)setscancelled = trueand callsreader.cancel(...)when the signal aborts.- The fallback terminal reporting uses
if (!reported && !cancelled) onTerminal("incomplete"). /v1/responsespassesonNativePassthroughCancel, but if the inspection pump exits through the early aborted/cancelled path, it looks possible for neitheronNativePassthroughTerminalnoronNativePassthroughCancelto finalize the request log.
That would match the observed pattern:
- routed providers use the normal logging path and appear in
/api/logs - non-stream ChatGPT failures appear
- successful ChatGPT passthrough SSE responses can reach Codex but not finalize a request-log entry
Possible related factor
/api/logs is also memory-only (requestLog: RequestLogEntry[] = [], max 200). If the proxy crashes/restarts during the same window, successful entries from the previous process are lost. That may be a separate limitation, but the native passthrough finalization path still looks worth hardening so a successful/cancelled passthrough request always records exactly one terminal log entry when possible.
Questions
- Should native passthrough SSE finalize
/api/logson client cancel / inspection pump abort, probably as499withcloseReason: "client_cancel"? - Should
consumeForInspection(...)call a terminal/cancel callback even when the abort signal setscancelled = true? - Would you prefer a focused PR with a regression test for native passthrough SSE cancel/finalization, or is this better handled as part of a broader request-log persistence/logging change?
Activity
lidge-jun commentedon Jun 29, 2026
PR #46 (@0disoft,
fix(logs): finalize native passthrough SSE usage) addresses this. It makes the background inspection finalize/api/logs+ usage for native passthrough SSE even when no Codex pool terminal recorder is active — closing theconsumeForResponseLogMetadataelse-branch gap.One follow-up flagged on the PR: the primary symptom here is successful turns going missing because Codex disconnects the client right after consuming, which aborts the shared signal while the teed inspection branch is still draining (
consumeForInspectionthen takes thecancelledpath and skipsonTerminal). A regression test for success-then-immediate-disconnect, and a decision on a499/client_cancelcancel finalizer, would fully close #44.lidge-jun commentedon Jun 29, 2026
Merged. PR #46's fix was cherry-picked into the
feat/kiro-on-devworking branch as2481c80(author attribution to @0disoft preserved).Verification on the branch:
bun test tests/server-auth.test.ts tests/request-log.test.ts tests/passthrough-abort.test.ts→ 57 pass / 0 fail (incl. the new native-passthrough usage regression test)bun x tsc --noEmit→ cleanThis closes the secondary gap (native passthrough SSE now finalizes
/api/logs+ usage even without a Codex pool terminal recorder). The success-then-immediate-disconnect cancel-path case noted on PR #46 remains a good follow-up to fully close this issue. The GitHub PR stays open againstdevand will close when it lands there.lidge-jun commentedon Jun 29, 2026
Resolved by the native passthrough SSE finalization fix (2481c80, PR #46), now in dev and released through preview (v2.6.4-preview). Successful ChatGPT native passthrough turns are finalized into /api/logs and /api/usage with a regression test covering the path. Closing as fixed.
fix(server): finalize native-passthrough request log on client cancel (…
Merge dev into main — issue #44 request-log cancel finalization + win…
Merge dev into preview — issue #44 cancel finalization + windows-depl…
lidge-jun commentedon Jul 3, 2026
For the record — the cancel-path finalization is now fixed (merged to
main/preview, ships next release):2481c80) so successful turns stop going missing.consumeForInspectiongained anonCancelfinalizer fired on both abort branches,onDoneruns on early-abort, andreportNativeTerminalno longer downgrades a detected terminal to a cancel — so a turn logs completed/failed when it finished,499 client_cancelonly on a pure cancel. Idempotent → exactly one/api/logsentry per turn (33aafa0). Regression test:tests/consume-for-inspection-cancel.test.ts.feat(stream): eager bounded single-reader SSE relay behind runtime ga…
docs(plan): fold the five audit blockers back into the RSS unit
fix(relay): bound the SSE inspector and give the tee path a real disc…
fix(server): finalize native-passthrough request log on client cancel (…
Merge dev into preview — issue lidge-jun#44 cancel finalization + win…
Merge dev into main — issue lidge-jun#44 request-log cancel finalizat…
feat(stream): eager bounded single-reader SSE relay behind runtime ga…
docs(plan): fold the five audit blockers back into the RSS unit
fix(relay): bound the SSE inspector and give the tee path a real disc…