Conversation
|
Marking as draft — found a couple of real bugs during further live verification on the dashboard (the conversations list appears empty and the timeline detail view only shows a single turn for a multi-turn conversation). Investigating now, will mark ready again once fixed. |
|
Found and fixed two real bugs during live verification on omniroute-dev: 1. Conversations list was empty / detail view only showed 1 turn — root cause: conversation continuation never actually worked for real agentic CLI traffic. Note: this doesn't retroactively fix already-logged conversations from before the deploy — only new traffic going forward will track correctly. 2. (#9315) Provider Response panel stale for long streams — the summary was reconstructed from the (capped, truncation-dropping) raw event array instead of computed incrementally as chunks arrive. Fixed by making the per-format summary builders available as incremental reducers fed on every push(), regardless of storage truncation. Both TDD-verified (failing test → fix → passing), full Marking ready for review. |
ce87691 to
7ee2dec
Compare
…ody transcript bug CI failures on PR diegosouzapw#9439: 1. Migration version collision: upstream/release/v3.8.50 landed 134_proxy_logs_egress_ip.sql (diegosouzapw#9291) after this branch's original rebase, colliding with this branch's own 134_agentic_conversations.sql. Renamed to 135_agentic_conversations.sql (re-rebased onto the current tip first). 2. check:file-size: rebaselined the files this PR's own feature growth pushed over their frozen/cap thresholds (RequestLoggerDetail.tsx, RequestTimeline.tsx, RequestLoggerV2.tsx, chat.ts, chatCore.ts — see the new _rebaseline_2026_08_04_9439 entry for the itemized justification) plus open-sse/executors/base.ts, which was already over its own frozen baseline on release/v3.8.50 independent of this branch (confirmed via `git diff upstream/release/v3.8.50 HEAD -- open-sse/executors/base.ts` — empty). 3. A third real bug, found by re-checking the live dashboard after the previous round's fixes: a request with a long real conversation chain showed only its own response in the "Full Conversation" panel. Root cause: open-sse/handlers/chatCore/logTruncation.ts's truncateForLog() replaces any request body over ~8KB with a bare {_truncated, _originalBytes, messageCount, ...} summary, dropping messages/input entirely — the norm, not the exception, for any conversation with real substance. buildRequestTurns() legitimately found nothing to parse, so the transcript silently rendered only that row's response, and (more subtly) every subsequent row's delta-slicing bookkeeping was computed against the wrong running total (0 instead of the row's real turn count), which would have corrupted the rest of the reconstruction too for any longer chain built on top of a truncated row. Fix: buildMultiRowConversation now detects a truncated request body via its messageCount field, uses that count for delta bookkeeping instead of silently treating it as zero, and renders one explicit placeholder turn ("N messages not shown — the request body was too large to log") instead of just disappearing. Test plan: - New regression tests for the truncation case (single truncated row, and a truncated row followed by a real row to verify bookkeeping stays correct) - npm run check:migration-numbering / check:file-size — clean - npm run typecheck:core / npm run lint — clean - npm run test:unit — 27086 tests, only 4 failures remain (down from 18 — 2 were fixed by the newer upstream commits pulled in by this re-rebase), all independently pre-existing/unrelated (ServiceSupervisor timing, monaco-editor path, npm-pack) - npm run test:vitest — 291/291 passed
vulnCount 10->22 (osv-scanner, measured in PR diegosouzapw#9439's own CI run). Not a dependency change from this PR — `git diff upstream/release/v3.8.50 HEAD -- package.json package-lock.json` is empty, neither file was touched anywhere in this branch. This is the documented "CVE variance" scenario from _osv_flip_blocking_2026_06_16_v3827: newly-disclosed CVEs in already-present transitive dependencies accumulated on release/v3.8.50 (the vuln ratchet apparently doesn't run on every direct commit to the release branch, same gap already documented for check:file-size) and only surfaced here because this PR's rebase pulled in the current release tip. Re-baselined per that entry's own prescribed remedy; follow-up dependency-bump PR should re-tighten once the specific advisories are enumerated with osv-scanner installed.
…ody transcript bug CI failures on PR diegosouzapw#9439: 1. Migration version collision: upstream/release/v3.8.50 landed 134_proxy_logs_egress_ip.sql (diegosouzapw#9291) after this branch's original rebase, colliding with this branch's own 134_agentic_conversations.sql. Renamed to 135_agentic_conversations.sql (re-rebased onto the current tip first). 2. check:file-size: rebaselined the files this PR's own feature growth pushed over their frozen/cap thresholds (RequestLoggerDetail.tsx, RequestTimeline.tsx, RequestLoggerV2.tsx, chat.ts, chatCore.ts — see the new _rebaseline_2026_08_04_9439 entry for the itemized justification) plus open-sse/executors/base.ts, which was already over its own frozen baseline on release/v3.8.50 independent of this branch (confirmed via `git diff upstream/release/v3.8.50 HEAD -- open-sse/executors/base.ts` — empty). 3. A third real bug, found by re-checking the live dashboard after the previous round's fixes: a request with a long real conversation chain showed only its own response in the "Full Conversation" panel. Root cause: open-sse/handlers/chatCore/logTruncation.ts's truncateForLog() replaces any request body over ~8KB with a bare {_truncated, _originalBytes, messageCount, ...} summary, dropping messages/input entirely — the norm, not the exception, for any conversation with real substance. buildRequestTurns() legitimately found nothing to parse, so the transcript silently rendered only that row's response, and (more subtly) every subsequent row's delta-slicing bookkeeping was computed against the wrong running total (0 instead of the row's real turn count), which would have corrupted the rest of the reconstruction too for any longer chain built on top of a truncated row. Fix: buildMultiRowConversation now detects a truncated request body via its messageCount field, uses that count for delta bookkeeping instead of silently treating it as zero, and renders one explicit placeholder turn ("N messages not shown — the request body was too large to log") instead of just disappearing. Test plan: - New regression tests for the truncation case (single truncated row, and a truncated row followed by a real row to verify bookkeeping stays correct) - npm run check:migration-numbering / check:file-size — clean - npm run typecheck:core / npm run lint — clean - npm run test:unit — 27086 tests, only 4 failures remain (down from 18 — 2 were fixed by the newer upstream commits pulled in by this re-rebase), all independently pre-existing/unrelated (ServiceSupervisor timing, monaco-editor path, npm-pack) - npm run test:vitest — 291/291 passed
vulnCount 10->22 (osv-scanner, measured in PR diegosouzapw#9439's own CI run). Not a dependency change from this PR — `git diff upstream/release/v3.8.50 HEAD -- package.json package-lock.json` is empty, neither file was touched anywhere in this branch. This is the documented "CVE variance" scenario from _osv_flip_blocking_2026_06_16_v3827: newly-disclosed CVEs in already-present transitive dependencies accumulated on release/v3.8.50 (the vuln ratchet apparently doesn't run on every direct commit to the release branch, same gap already documented for check:file-size) and only surfaced here because this PR's rebase pulled in the current release tip. Re-baselined per that entry's own prescribed remedy; follow-up dependency-bump PR should re-tighten once the specific advisories are enumerated with osv-scanner installed.
3ca5f6d to
ee795f2
Compare
…egosouzapw#9439) open-sse/translator/response/openai-responses.ts, src/shared/components/RequestLoggerV2.tsx, src/sse/handlers/chat.ts, and src/shared/components/RequestTimeline.tsx crossed their frozen caps from this session's fixes (escape-state persistence, Previous/Next boundary resync, onNavigateToLog removal). See the new _rebaseline_2026_08_06_9439_no_forking_redesign_and_fixes entry for the per-file breakdown and test coverage.
|
Rebased onto the latest Rebase/merge
Bugs found and fixed along the way (not scope creep — all blocked verification or were surfaced directly by the merge):
Test/quality status (all green after the above fixes):
Everything's pushed to |
|
The base branch (`release/v3.8.50`) moved again (22 more commits) and re-introduced conflicts — resolved and pushed. New conflicts (6): file-size baseline numbers, an i18n file (took upstream's, untouched by this branch), `localDb.ts` (both sides purely additive re-exports — kept both), `SetupWizard.tsx` (upstream independently fixed the same unescaped-entity issue I'd fixed earlier — took theirs), and `catalog-order-contract.test.ts` (upstream added a slightly different fix for the same `as any` issue I'd already cleaned up — kept mine, simpler). More serious finding: this pull also revealed that upstream's own `release/v3.8.50` currently has two pairs of migration files colliding on the same version number (`135_auto_restart_adopted.sql` vs `135_migrate_model_capability_max_token.sql`, and `136_dario_fallback_backend.sql` vs `136_radar_cache_settings.sql` — confirmed via `git ls-tree` against your tip directly, unrelated to this PR). Unlike my first migration-numbering fix, this one isn't just a test-gate warning — `migrationRunner.ts` hard-throws on any duplicate version, so Re-verified: `check-migration-numbering.test.ts` (15/15), full typecheck, file-size/any-budget/docs-sync gates, and every DB-touching test this PR added or fixed (agenticConversations, conversationTracker, conversations-tree-route-seq-param, catalog-order-contract, model-capability-overrides) — all green. PR now shows `mergeable: true`. You may want to flag the Dario/radar/model-capability migration collision to whoever owns those PRs — it's a real bug on `release/v3.8.50` independent of this branch, and any other open PR based on that branch will hit the same hard failure until it's fixed at the source. |
|
Small scope-creep addition on top of this PR: Symptom: a phone browser tab got stuck in an endless refresh loop (content flickering/resetting every ~1.5s, no visible white-flash reload) hitting the dev server. A private/incognito tab on the same phone/URL did not loop, which pointed at stored browser state rather than anything server-side. Root cause: Fix: Flagging as scope creep since it's unrelated to conversation tracking — happy to split into its own PR if preferred, but it's small (one component + one test) and was blocking my own live verification of this feature. |
|
Pushed a merge + 3 more commits:
Heads up on CI: All new/changed code: typecheck clean, lint clean, relevant unit tests passing (conversationTracker: 21/21, new activeCallLogId route test: 2/2, chatcore-log-truncation + env-doc-sync: 19/19), env/docs sync check passes. |
|
One more, found via live dashboard use + a wire-level pcap cross-check (`032a3d2f7`): Bug: `open-sse/utils/stream.ts`'s `providerPayloadCollector` (the dashboard's "Provider Response" panel) was keyed on `sourceFormat` (the CLIENT's wire format) instead of `targetFormat` (the PROVIDER's — this function's own `@param` doc says so explicitly: `targetFormat - Provider format`, `sourceFormat - Client format`). Whenever a request translates between two different formats — e.g. a Responses-API client routed to a plain-OpenAI-chat-completions upstream (the common OpenClaw/opencode-zen shape) — the reducer picked for `sourceFormat` could never recognize the provider's actual raw event shape, so it stayed stuck at its empty initial state. Dashboard symptom: "Provider Response" permanently shows `output: []` while "Client Response" (built from separately-accumulated state, unaffected) correctly shows full content — reads as if the two panels simply disagree about the same request. How it was caught: while debugging an unrelated OpenClaw silent-turn issue, captured the raw Caddy↔omniroute-dev bytes with `scripts/sre/tcp-close-analyzer.py` (merged upstream in #8208) and cross-referenced against the dashboard log for the same request id — confirmed the actual wire response was complete and correct, isolating this to a pure logging/summary bug, not a wire-format bug. Fix is mode-aware: TRANSLATE mode now uses `targetFormat`; PASSTHROUGH mode keeps `sourceFormat`, since passthrough has no separate provider/client format split (nothing gets translated there, and the real passthrough caller `createPassthroughStreamWithLogger` doesn't even pass `targetFormat`). New regression test reproduces the exact live scenario (Responses-API source, OpenAI target, real `chat.completion.chunk` deltas) — confirmed it fails with the old `sourceFormat`-keyed code (reproducing the live `output: []`-style symptom) and passes with the fix. All 94 tests across the touched stream/logging test files pass; typecheck/lint clean on the actual project gates (`typecheck:core`, suppressions-aware `lint`). |
|
Thank you for this substantial contribution. After analysis, this is being marked as |
…ody transcript bug CI failures on PR diegosouzapw#9439: 1. Migration version collision: upstream/release/v3.8.50 landed 134_proxy_logs_egress_ip.sql (diegosouzapw#9291) after this branch's original rebase, colliding with this branch's own 134_agentic_conversations.sql. Renamed to 135_agentic_conversations.sql (re-rebased onto the current tip first). 2. check:file-size: rebaselined the files this PR's own feature growth pushed over their frozen/cap thresholds (RequestLoggerDetail.tsx, RequestTimeline.tsx, RequestLoggerV2.tsx, chat.ts, chatCore.ts — see the new _rebaseline_2026_08_04_9439 entry for the itemized justification) plus open-sse/executors/base.ts, which was already over its own frozen baseline on release/v3.8.50 independent of this branch (confirmed via `git diff upstream/release/v3.8.50 HEAD -- open-sse/executors/base.ts` — empty). 3. A third real bug, found by re-checking the live dashboard after the previous round's fixes: a request with a long real conversation chain showed only its own response in the "Full Conversation" panel. Root cause: open-sse/handlers/chatCore/logTruncation.ts's truncateForLog() replaces any request body over ~8KB with a bare {_truncated, _originalBytes, messageCount, ...} summary, dropping messages/input entirely — the norm, not the exception, for any conversation with real substance. buildRequestTurns() legitimately found nothing to parse, so the transcript silently rendered only that row's response, and (more subtly) every subsequent row's delta-slicing bookkeeping was computed against the wrong running total (0 instead of the row's real turn count), which would have corrupted the rest of the reconstruction too for any longer chain built on top of a truncated row. Fix: buildMultiRowConversation now detects a truncated request body via its messageCount field, uses that count for delta bookkeeping instead of silently treating it as zero, and renders one explicit placeholder turn ("N messages not shown — the request body was too large to log") instead of just disappearing. Test plan: - New regression tests for the truncation case (single truncated row, and a truncated row followed by a real row to verify bookkeeping stays correct) - npm run check:migration-numbering / check:file-size — clean - npm run typecheck:core / npm run lint — clean - npm run test:unit — 27086 tests, only 4 failures remain (down from 18 — 2 were fixed by the newer upstream commits pulled in by this re-rebase), all independently pre-existing/unrelated (ServiceSupervisor timing, monaco-editor path, npm-pack) - npm run test:vitest — 291/291 passed
8c98a59 to
ce60a70
Compare
vulnCount 10->22 (osv-scanner, measured in PR diegosouzapw#9439's own CI run). Not a dependency change from this PR — `git diff upstream/release/v3.8.50 HEAD -- package.json package-lock.json` is empty, neither file was touched anywhere in this branch. This is the documented "CVE variance" scenario from _osv_flip_blocking_2026_06_16_v3827: newly-disclosed CVEs in already-present transitive dependencies accumulated on release/v3.8.50 (the vuln ratchet apparently doesn't run on every direct commit to the release branch, same gap already documented for check:file-size) and only surfaced here because this PR's rebase pulled in the current release tip. Re-baselined per that entry's own prescribed remedy; follow-up dependency-bump PR should re-tighten once the specific advisories are enumerated with osv-scanner installed.
…egosouzapw#9439) open-sse/translator/response/openai-responses.ts, src/shared/components/RequestLoggerV2.tsx, src/sse/handlers/chat.ts, and src/shared/components/RequestTimeline.tsx crossed their frozen caps from this session's fixes (escape-state persistence, Previous/Next boundary resync, onNavigateToLog removal). See the new _rebaseline_2026_08_06_9439_no_forking_redesign_and_fixes entry for the per-file breakdown and test coverage.
…ody transcript bug CI failures on PR diegosouzapw#9439: 1. Migration version collision: upstream/release/v3.8.50 landed 134_proxy_logs_egress_ip.sql (diegosouzapw#9291) after this branch's original rebase, colliding with this branch's own 134_agentic_conversations.sql. Renamed to 135_agentic_conversations.sql (re-rebased onto the current tip first). 2. check:file-size: rebaselined the files this PR's own feature growth pushed over their frozen/cap thresholds (RequestLoggerDetail.tsx, RequestTimeline.tsx, RequestLoggerV2.tsx, chat.ts, chatCore.ts — see the new _rebaseline_2026_08_04_9439 entry for the itemized justification) plus open-sse/executors/base.ts, which was already over its own frozen baseline on release/v3.8.50 independent of this branch (confirmed via `git diff upstream/release/v3.8.50 HEAD -- open-sse/executors/base.ts` — empty). 3. A third real bug, found by re-checking the live dashboard after the previous round's fixes: a request with a long real conversation chain showed only its own response in the "Full Conversation" panel. Root cause: open-sse/handlers/chatCore/logTruncation.ts's truncateForLog() replaces any request body over ~8KB with a bare {_truncated, _originalBytes, messageCount, ...} summary, dropping messages/input entirely — the norm, not the exception, for any conversation with real substance. buildRequestTurns() legitimately found nothing to parse, so the transcript silently rendered only that row's response, and (more subtly) every subsequent row's delta-slicing bookkeeping was computed against the wrong running total (0 instead of the row's real turn count), which would have corrupted the rest of the reconstruction too for any longer chain built on top of a truncated row. Fix: buildMultiRowConversation now detects a truncated request body via its messageCount field, uses that count for delta bookkeeping instead of silently treating it as zero, and renders one explicit placeholder turn ("N messages not shown — the request body was too large to log") instead of just disappearing. Test plan: - New regression tests for the truncation case (single truncated row, and a truncated row followed by a real row to verify bookkeeping stays correct) - npm run check:migration-numbering / check:file-size — clean - npm run typecheck:core / npm run lint — clean - npm run test:unit — 27086 tests, only 4 failures remain (down from 18 — 2 were fixed by the newer upstream commits pulled in by this re-rebase), all independently pre-existing/unrelated (ServiceSupervisor timing, monaco-editor path, npm-pack) - npm run test:vitest — 291/291 passed
vulnCount 10->22 (osv-scanner, measured in PR diegosouzapw#9439's own CI run). Not a dependency change from this PR — `git diff upstream/release/v3.8.50 HEAD -- package.json package-lock.json` is empty, neither file was touched anywhere in this branch. This is the documented "CVE variance" scenario from _osv_flip_blocking_2026_06_16_v3827: newly-disclosed CVEs in already-present transitive dependencies accumulated on release/v3.8.50 (the vuln ratchet apparently doesn't run on every direct commit to the release branch, same gap already documented for check:file-size) and only surfaced here because this PR's rebase pulled in the current release tip. Re-baselined per that entry's own prescribed remedy; follow-up dependency-bump PR should re-tighten once the specific advisories are enumerated with osv-scanner installed.
ce60a70 to
60cdaac
Compare
…egosouzapw#9439) open-sse/translator/response/openai-responses.ts, src/shared/components/RequestLoggerV2.tsx, src/sse/handlers/chat.ts, and src/shared/components/RequestTimeline.tsx crossed their frozen caps from this session's fixes (escape-state persistence, Previous/Next boundary resync, onNavigateToLog removal). See the new _rebaseline_2026_08_06_9439_no_forking_redesign_and_fixes entry for the per-file breakdown and test coverage.
… tool-call gap
RequestLoggerDetail's Conversation Context section now renders only the
currently-viewed request's own buildRequestTurns/buildResponseTurns output
directly, instead of reconstructing a cross-row transcript from prior
requests sharing a session_tag. A single request's own body already is its
full context; the operator asked for this after the multi-row reconstruction
made indentation grow unboundedly (superseded by conversationTracker.ts's
no-forking redesign). Deletes multiRowConversation.ts and its test — dead
code once the panel no longer walks prior rows. Kept live-streaming updates
for an active request (extractPartialAssistantText now also accumulates
delta.reasoning_content, so the panel keeps visibly progressing during a
reasoning-only streaming phase) and added a liveRefresh toggle + scroll-to-
bottom control mirroring StreamSection's existing pattern.
Fixes a real, universal data-loss bug found while investigating why tool
calls looked different between the detail panel and the conversation tree
view: turnsFromOpenAiMessages (conversationNormalizer.ts) only handled
role-based Chat Completions messages. Real Responses API traffic (OpenClaw)
sends bare {type:"function_call"}/{type:"function_call_output"}/
{type:"reasoning"} items with NO role field at all, so they were silently
dropped — every tool call in a Responses API conversation vanished from the
Conversation Context panel. Now handled explicitly before the role-based
branches.
Also fixes a Dark Reader (browser extension) false-positive hydration
warning on OmniRouteLogo's SVG lines (suppressHydrationWarning — the
extension injects data-darkreader-inline-stroke before React hydrates), and
adds break-words to MarkdownMessage so long unspaced runs (raw JSON, ids)
wrap instead of overflowing a narrower container like the conversation
modal. ChatBubble's onClick doc comment updated to reflect it's no longer
multiRowConversation-specific.
Background list polling intentionally pauses while a request's detail modal is open, so hitting the edge of the in-memory sorted list didn't mean there was really nothing newer/older — it just meant the client hadn't fetched requests that landed in the background yet. handlePrev/handleNext now resync the list once at that boundary and let a follow-up effect decide whether to navigate or actually close, instead of assuming the boundary is real. Also removes onNavigateToLog from RequestLoggerV2/RequestTimeline's calls into RequestLoggerDetail — that prop no longer exists after the detail panel's cross-row next-turn navigation was removed in the prior commit.
Genuine pre-existing bug on upstream release/v3.8.50 (verified byte- identical to their tip, not introduced by this branch's merge): chatCore.ts calls mergeResponseToolNameMap() but never imports it from ./chatCore/passthroughToolNames.ts, throwing a ReferenceError on every request that reaches that line (surfaced by agentrouter-chatcore-protocols.test.ts's 3 streaming-protocol cases). Also renumbers this branch's own migrations from 137/138 back to a contiguous 136/137 — the earlier 135->137 renumber (done to resolve this branch's collision with upstream's independently-added 135_migrate_model_capability_max_token.sql) skipped 136 entirely, leaving an unexplained sequence gap that check-migration-numbering.test.ts's real- migrations-dir check correctly flagged.
…view Adds chevron buttons in the conversation modal to step to the adjacent conversation in the loaded list, matching the request-detail view's prev/next pattern. Also surfaces the true live reply while it's still generating: turn nodes only get written once the client resends a turn as history on its NEXT request, so the transcript had nothing new to show mid-stream even though the request was actively producing text. /api/conversations now exposes activeCallLogId — the in-flight request's own id from usageHistory's pendingById, since call_logs only gets its row on completion and the existing lastCallLogId join always lagged one request behind. The modal polls that id's partial text (same source/cadence as RequestLoggerDetail) and renders it as a provisional bubble. Co-authored-by: Markus Hartung <markus.hartung@gmail.com>
A tool_use/tool_result turn's text is the tool call's raw JSON arguments (or a stringified result) — slicing that raw JSON at a fixed character offset (TEXT_PREVIEW_LENGTH) routinely landed mid-string, storing INVALID JSON. The conversations page's toTurn() then failed to JSON.parse it and fell back to showing the raw, still-escaped text verbatim: a large edit/write/apply_patch-style tool call with a long content field rendered with literal `\n` sequences visible instead of real line breaks, looking exactly like a JSON-escaping bug rather than a big diff. Confirmed live on omniroute-dev: 3 stored `edit` tool_use previews were sitting at exactly 8000 chars with "Unterminated string in JSON" on parse. buildTextPreview now parses first and caps oversized string VALUES inside the JSON instead of slicing the raw blob, so a truncated payload is always valid, re-parseable JSON. Plain text turns are unaffected (still a simple slice — a cut-off sentence is harmless). Also fixes JsonViewer's string rendering to preserve line breaks (whitespace-pre-wrap) — a correctly-parsed multi-line tool argument was still visually squashing onto one line without it. Unrelated cleanup found while editing: conversationTracker.ts had two literal NUL bytes (pre-existing, not introduced by this change) sitting where a template-literal space belonged, making the file register as binary to grep/rg/file. Restored to plain spaces. Co-authored-by: Markus Hartung <markus.hartung@gmail.com>
… provider's providerPayloadCollector (dashboard "Provider Response" panel) was keyed on sourceFormat (the CLIENT's wire format) instead of targetFormat (the PROVIDER's — see createSSEStream's own @PARAM doc: "targetFormat - Provider format", "sourceFormat - Client format"). Whenever a request translates between two different formats — e.g. a Responses-API client routed to a plain-OpenAI-chat-completions upstream, the common OpenClaw/opencode-zen shape — the reducer picked for sourceFormat could never recognize the provider's actual raw event shape, so it stayed stuck at its empty initial state. The dashboard's "Provider Response" panel showed a permanently empty `output: []` while "Client Response" (built from separately-accumulated state, unaffected by this bug) correctly showed full content — reading as if the two panels simply disagreed about the same request. Confirmed live via a wire-level pcap capture (scripts/sre/tcp-close- analyzer.py) cross-referenced against the dashboard log (1786032832181-1c6275): the actual response was complete and correct: this was purely a logging/summary bug, never a wire-format bug. Fix is mode-aware: TRANSLATE mode uses targetFormat (the provider's true format); PASSTHROUGH mode keeps sourceFormat, since passthrough has no separate provider/client format split — nothing gets translated there, and real passthrough callers (createPassthroughStreamWithLogger) don't even pass targetFormat. New regression test reproduces the exact live scenario (Responses-API source, OpenAI target, real chat.completion.chunk deltas) and asserts the provider summary reflects them — confirmed it fails with the old `sourceFormat`-keyed code (reproducing the live `output: []`-style symptom) and passes with the fix. Co-authored-by: Markus Hartung <markus.hartung@gmail.com>
Turbopack failed with "the name HARD_COMPAT_REASONS is defined multiple times" — two top-level const declarations of the same name existed in comboStructure.ts. The unused one (with an extra "output_tokens" entry, zero references anywhere) was dead weight left over from upstream; the active one (tools/vision/structured_output, used by hasHardCapabilityFailure/describeCapabilityFilterExhaustion/ filterTargetsByRequestCompatibility) is unaffected. Confirmed pre-existing on upstream/release/v3.8.50's own tip before this branch's merge (git show 7f36b19 already has both), so this is an inherited base-red fix, not new behavior.⚠️ base-red inherited: diegosouzapw#9298
…ments Leftover from the 137/138 -> 142/143 renumber — the header comment and the cross-reference to agentic_conversations still named the old numbers.
…e reasoning preview /api/logs/[id]'s live "Generating… / Thinking…" preview (extractPartialAssistantText) parsed each stream-chunk-log array element independently. Each element is one raw network read, timestamp-prefixed for the debug display — not one complete SSE `data:` line — so a single JSON value (a `reasoning_content` delta) routinely splits across two or more elements. Parsing per-element in isolation silently failed JSON.parse on the split pieces and dropped them, leaving gaps in the reconstructed text that read as garbled/scrambled reasoning once the survivors were concatenated — reported live via a dashboard screenshot of an in-progress conversation. Fix: strip each element's timestamp prefix and concatenate the whole array into one continuous string first, then split into lines and parse — so a value split across elements rejoins correctly before JSON.parse ever sees it. Same reconstruction technique already proven correct for the final, completed response body; this brings the in-flight preview path in line. Covered by tests/unit/logs-detail-partial-reasoning-chunk-split.test.ts, including a direct demonstration that the pre-fix per-element parse fails on each half of a split value in isolation (proving genuine TDD, not a coincidental pass) while the fixed concatenate-first parse recovers the full text.
…sset (diegosouzapw#9687) Docker/standalone builds of the LLMLingua SLM compression tier failed at runtime with "Error: libonnxruntime.so.1: cannot open shared object file: No such file or directory" (open-sse/services/compression/engines/llmlingua's worker, via @huggingface/transformers -> onnxruntime-node). onnxruntime-node's dist/binding.js is a normal JS file Next.js's standalone trace bundles correctly, but binding.js dlopen()s a platform-specific native library shipped under bin/napi-v3/<platform>/<arch>/libonnxruntime.so.1 — a dynamic native load static file tracing can't see (same blind-spot class as the separate colocateLlmlinguaOptionals stub bug, just for a .so instead of a JS import, via NATIVE_ASSET_ENTRIES instead). That directory was simply never registered, unlike better-sqlite3's native binary, which already goes through the exact same mechanism correctly. Fix: add an entry for onnxruntime-node/bin, mirroring the existing better-sqlite3 entry. Confirmed against a real Docker build of the Dockerfile's own post-build verification step: this was the very next failure once the separate llmlingua-2 stub bug was fixed and the build progressed far enough to reach it. Covered by tests/unit/assemble-standalone-onnxruntime-native-asset.test.ts (fails against the pre-fix code on both assertions, passes after).
…e rebase auto-merge This branch's own earlier commit (b8601c4, "remove duplicate HARD_COMPAT_REASONS declaration") deleted one of two duplicate top-level declarations that existed on an older release/v3.8.50 tip. By the time this branch was rebased onto the current, much newer upstream/release/v3.8.50 tip, upstream had already independently deduplicated its own copy down to a single declaration — so the old delete-only diff's context lines matched the file's new (already single-declaration) shape closely enough to auto-merge without a conflict, silently deleting the only remaining declaration and breaking typecheck (Cannot find name 'HARD_COMPAT_REASONS', 3 call sites in this file). Restored the exact declaration upstream itself carries; the file is now byte-identical to upstream's own comboStructure.ts (confirmed via diff), so there is no remaining divergence to reconcile.
….8.50 npm install after rebasing picked up a small lockfile metadata drift left over from resolving the package-lock.json rebase conflict by taking upstream's version wholesale (a mechanical hasInstallScript sync commit from before the rebase was dropped as redundant, since upstream's lockfile had already moved past it).
…ffect agenticConversations.test.ts and conversationTracker.test.ts set process.env.DATA_DIR to a fresh mkdtemp dir before importing the DB-touching modules under test, but used static `import` statements. ES modules instantiate the whole dependency graph -- dependencies first, in the order encountered during linking -- before the entry module's own top-level code runs, regardless of source-line order. So src/lib/db/core.ts's `export const DATA_DIR = ...` (read once at module load) captured the real host DATA_DIR before the override line executed, and every test run silently wrote migrations and test rows into the operator's actual host database instead of an isolated temp dir. Confirmed with a minimal repro (a dependency module logging process.env.MY_VAR at its own top level, evaluated before the entry script's env-var assignment that textually precedes the import). Fix: switch the DB-touching imports in both files to dynamic `await import(...)`, which is not hoisted and executes exactly where it appears, after the DATA_DIR override. This is a systemic pattern (other test files use the same static-import-after-env-override shape, e.g. reasoning-cache.test.ts) that stays silently harmless on CI/fresh-checkout runners with no pre-existing data at the default DATA_DIR fallback -- it only became visible here because the host running this rebase had real data there. Scoped this fix to the two files this PR's own test suite touches; the wider pattern is a separate cleanup. Verified: both files' full suites (39 tests) pass, and the resolved DATA_DIR in the startup log now correctly points at the mkdtemp dir instead of the host default.
createSSEStream's providerPayloadCollector.build() falls back to the
synthesized responseBody as the "Provider Response" dashboard summary
whenever sourceFormat/targetFormat isn't OPENAI_RESPONSES (in both the
passthrough and translate branches) -- but responseBody is built purely
for the client and never carries an `object` field at all, so the
summary ended up with `object: undefined` instead of the expected
"chat.completion", even though everything else (choices, usage) was
correct.
Caught by this PR's own new regression test ("createSSEStream translate
mode: providerPayload summary reflects the PROVIDER's format, not the
client's") -- the code itself was unchanged by the rebase (applied
cleanly from the original commit), so this was a latent gap in the
original fix, not a rebase regression.
Fix: stamp `object: "chat.completion"` on a shallow copy used only for
the provider summary in both branches; responseBody itself (sent to the
client elsewhere) stays untouched.
Verified: tests/unit/stream-utils.test.ts 51/52 passing (the one
remaining failure is an unrelated, pre-existing v3.6.6-era test,
confirmed present and failing identically on a pristine
upstream/release/v3.8.50 checkout -- base-red inherited: diegosouzapw#9985).
typecheck/lint clean (pre-existing unrelated errors elsewhere in the
file, confirmed identical to upstream).
60cdaac to
60ed352
Compare
|
Rebased onto the latest
|
|
Superseded by #10047 — same feature, rebased onto the current release/v3.8.50 tip and cleaned up (23 commits → 14). The dropped commits were all fixes for bugs that were pre-existing on release/v3.8.50 itself and have since been independently resolved upstream (verified against the current tip before dropping each one); two other genuinely-standalone fixes were already split out as #10037 and #10038. See #10047's description for the full commit-by-commit breakdown. Closing this one in favor of #10047. |
… Responses API bodies Extracted from PR diegosouzapw#9439 (agentic conversation tracking). Most of the original scope this commit was cherry-picked from (CHAT_LOG_MAX_BODY_KB env var support, the estimateSizeFast() earlyExitAt parameterization) turned out to already be present on the current upstream/release/v3.8.50 tip -- confirmed via diff and by running check-env-doc-sync.test.ts / tests/unit/chatcore-log-truncation.test.ts against pristine upstream before making any changes here. Only two genuine gaps remained: 1. CHAT_LOG_MAX_BODY_KB was read by getChatLogMaxBodyBytes() but undocumented in .env.example and docs/reference/ENVIRONMENT.md -- tests/unit/check-env-doc-sync.test.ts flags any env var read in code but missing from both doc files. Documented it (both required -- the same test enforces the pairing). 2. truncateForLog()'s summary only computed messageCount from obj.messages (OpenAI-chat/Gemini field name) -- a large /v1/responses request (which uses input[], not messages[]) got summarized with no count at all, leaving the dashboard's "Full Conversation" panel nothing to base its "N messages not shown" placeholder on for any Responses-API conversation, even though the same summarization logic applies to it. Test plan: - TDD: tests/unit/chatcore-log-truncation.test.ts's new regression test ("captures a message count for Responses API bodies too") confirmed failing against the pre-fix code, passing after. - tests/unit/check-env-doc-sync.test.ts confirms CHAT_LOG_MAX_BODY_KB no longer appears in codeMissingEnv (remaining drift in that test is pre-existing/unrelated -- ANTIGRAVITY_ALLOW_SIGNATURE_BYPASS, COMMANDCODE_API_URL, OMNIROUTE_STRICT_SYSTEM_PROVIDERS, TLS_FINGERPRINT_PROVIDERS -- confirmed identical on a pristine upstream/release/v3.8.50 checkout, base-red inherited: diegosouzapw#9985). - tests/unit/chatcore-log-truncation.test.ts -- 19/19 passing. - npx tsc --noEmit / npm run lint -- clean.⚠️ base-red inherited: diegosouzapw#9985
… Responses API bodies Extracted from PR diegosouzapw#9439 (agentic conversation tracking). Most of the original scope this commit was cherry-picked from (CHAT_LOG_MAX_BODY_KB env var support, the estimateSizeFast() earlyExitAt parameterization) turned out to already be present on the current upstream/release/v3.8.50 tip -- confirmed via diff and by running check-env-doc-sync.test.ts / tests/unit/chatcore-log-truncation.test.ts against pristine upstream before making any changes here. Only two genuine gaps remained: 1. CHAT_LOG_MAX_BODY_KB was read by getChatLogMaxBodyBytes() but undocumented in .env.example and docs/reference/ENVIRONMENT.md -- tests/unit/check-env-doc-sync.test.ts flags any env var read in code but missing from both doc files. Documented it (both required -- the same test enforces the pairing). 2. truncateForLog()'s summary only computed messageCount from obj.messages (OpenAI-chat/Gemini field name) -- a large /v1/responses request (which uses input[], not messages[]) got summarized with no count at all, leaving the dashboard's "Full Conversation" panel nothing to base its "N messages not shown" placeholder on for any Responses-API conversation, even though the same summarization logic applies to it. Test plan: - TDD: tests/unit/chatcore-log-truncation.test.ts's new regression test ("captures a message count for Responses API bodies too") confirmed failing against the pre-fix code, passing after. - tests/unit/check-env-doc-sync.test.ts confirms CHAT_LOG_MAX_BODY_KB no longer appears in codeMissingEnv (remaining drift in that test is pre-existing/unrelated -- ANTIGRAVITY_ALLOW_SIGNATURE_BYPASS, COMMANDCODE_API_URL, OMNIROUTE_STRICT_SYSTEM_PROVIDERS, TLS_FINGERPRINT_PROVIDERS -- confirmed identical on a pristine upstream/release/v3.8.50 checkout, base-red inherited: diegosouzapw#9985). - tests/unit/chatcore-log-truncation.test.ts -- 19/19 passing. - npx tsc --noEmit / npm run lint -- clean.⚠️ base-red inherited: diegosouzapw#9985
… Responses API bodies Extracted from PR diegosouzapw#9439 (agentic conversation tracking). Most of the original scope this commit was cherry-picked from (CHAT_LOG_MAX_BODY_KB env var support, the estimateSizeFast() earlyExitAt parameterization) turned out to already be present on the current upstream/release/v3.8.50 tip -- confirmed via diff and by running check-env-doc-sync.test.ts / tests/unit/chatcore-log-truncation.test.ts against pristine upstream before making any changes here. Only two genuine gaps remained: 1. CHAT_LOG_MAX_BODY_KB was read by getChatLogMaxBodyBytes() but undocumented in .env.example and docs/reference/ENVIRONMENT.md -- tests/unit/check-env-doc-sync.test.ts flags any env var read in code but missing from both doc files. Documented it (both required -- the same test enforces the pairing). 2. truncateForLog()'s summary only computed messageCount from obj.messages (OpenAI-chat/Gemini field name) -- a large /v1/responses request (which uses input[], not messages[]) got summarized with no count at all, leaving the dashboard's "Full Conversation" panel nothing to base its "N messages not shown" placeholder on for any Responses-API conversation, even though the same summarization logic applies to it. Test plan: - TDD: tests/unit/chatcore-log-truncation.test.ts's new regression test ("captures a message count for Responses API bodies too") confirmed failing against the pre-fix code, passing after. - tests/unit/check-env-doc-sync.test.ts confirms CHAT_LOG_MAX_BODY_KB no longer appears in codeMissingEnv (remaining drift in that test is pre-existing/unrelated -- ANTIGRAVITY_ALLOW_SIGNATURE_BYPASS, COMMANDCODE_API_URL, OMNIROUTE_STRICT_SYSTEM_PROVIDERS, TLS_FINGERPRINT_PROVIDERS -- confirmed identical on a pristine upstream/release/v3.8.50 checkout, base-red inherited: diegosouzapw#9985). - tests/unit/chatcore-log-truncation.test.ts -- 19/19 passing. - npx tsc --noEmit / npm run lint -- clean.⚠️ base-red inherited: diegosouzapw#9985
… Responses API bodies Extracted from PR diegosouzapw#9439 (agentic conversation tracking). Most of the original scope this commit was cherry-picked from (CHAT_LOG_MAX_BODY_KB env var support, the estimateSizeFast() earlyExitAt parameterization) turned out to already be present on the current upstream/release/v3.8.50 tip -- confirmed via diff and by running check-env-doc-sync.test.ts / tests/unit/chatcore-log-truncation.test.ts against pristine upstream before making any changes here. Only two genuine gaps remained: 1. CHAT_LOG_MAX_BODY_KB was read by getChatLogMaxBodyBytes() but undocumented in .env.example and docs/reference/ENVIRONMENT.md -- tests/unit/check-env-doc-sync.test.ts flags any env var read in code but missing from both doc files. Documented it (both required -- the same test enforces the pairing). 2. truncateForLog()'s summary only computed messageCount from obj.messages (OpenAI-chat/Gemini field name) -- a large /v1/responses request (which uses input[], not messages[]) got summarized with no count at all, leaving the dashboard's "Full Conversation" panel nothing to base its "N messages not shown" placeholder on for any Responses-API conversation, even though the same summarization logic applies to it. Test plan: - TDD: tests/unit/chatcore-log-truncation.test.ts's new regression test ("captures a message count for Responses API bodies too") confirmed failing against the pre-fix code, passing after. - tests/unit/check-env-doc-sync.test.ts confirms CHAT_LOG_MAX_BODY_KB no longer appears in codeMissingEnv (remaining drift in that test is pre-existing/unrelated -- ANTIGRAVITY_ALLOW_SIGNATURE_BYPASS, COMMANDCODE_API_URL, OMNIROUTE_STRICT_SYSTEM_PROVIDERS, TLS_FINGERPRINT_PROVIDERS -- confirmed identical on a pristine upstream/release/v3.8.50 checkout, base-red inherited: diegosouzapw#9985). - tests/unit/chatcore-log-truncation.test.ts -- 19/19 passing. - npx tsc --noEmit / npm run lint -- clean.⚠️ base-red inherited: diegosouzapw#9985
… Responses API bodies (#10038) * fix(logging): document CHAT_LOG_MAX_BODY_KB, capture messageCount for Responses API bodies Extracted from PR #9439 (agentic conversation tracking). Most of the original scope this commit was cherry-picked from (CHAT_LOG_MAX_BODY_KB env var support, the estimateSizeFast() earlyExitAt parameterization) turned out to already be present on the current upstream/release/v3.8.50 tip -- confirmed via diff and by running check-env-doc-sync.test.ts / tests/unit/chatcore-log-truncation.test.ts against pristine upstream before making any changes here. Only two genuine gaps remained: 1. CHAT_LOG_MAX_BODY_KB was read by getChatLogMaxBodyBytes() but undocumented in .env.example and docs/reference/ENVIRONMENT.md -- tests/unit/check-env-doc-sync.test.ts flags any env var read in code but missing from both doc files. Documented it (both required -- the same test enforces the pairing). 2. truncateForLog()'s summary only computed messageCount from obj.messages (OpenAI-chat/Gemini field name) -- a large /v1/responses request (which uses input[], not messages[]) got summarized with no count at all, leaving the dashboard's "Full Conversation" panel nothing to base its "N messages not shown" placeholder on for any Responses-API conversation, even though the same summarization logic applies to it. Test plan: - TDD: tests/unit/chatcore-log-truncation.test.ts's new regression test ("captures a message count for Responses API bodies too") confirmed failing against the pre-fix code, passing after. - tests/unit/check-env-doc-sync.test.ts confirms CHAT_LOG_MAX_BODY_KB no longer appears in codeMissingEnv (remaining drift in that test is pre-existing/unrelated -- ANTIGRAVITY_ALLOW_SIGNATURE_BYPASS, COMMANDCODE_API_URL, OMNIROUTE_STRICT_SYSTEM_PROVIDERS, TLS_FINGERPRINT_PROVIDERS -- confirmed identical on a pristine upstream/release/v3.8.50 checkout, base-red inherited: #9985). - tests/unit/chatcore-log-truncation.test.ts -- 19/19 passing. - npx tsc --noEmit / npm run lint -- clean.⚠️ base-red inherited: #9985 * docs(logging): consolidate CHAT_LOG_MAX_BODY_KB into a single entry per file The variable was already documented (with a stale src/lib/chatLogTruncation.ts reference in .env.example); keep the new richer entries next to the CHAT_LOG_* family and drop the old duplicates. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
… Responses API bodies (diegosouzapw#10038) * fix(logging): document CHAT_LOG_MAX_BODY_KB, capture messageCount for Responses API bodies Extracted from PR diegosouzapw#9439 (agentic conversation tracking). Most of the original scope this commit was cherry-picked from (CHAT_LOG_MAX_BODY_KB env var support, the estimateSizeFast() earlyExitAt parameterization) turned out to already be present on the current upstream/release/v3.8.50 tip -- confirmed via diff and by running check-env-doc-sync.test.ts / tests/unit/chatcore-log-truncation.test.ts against pristine upstream before making any changes here. Only two genuine gaps remained: 1. CHAT_LOG_MAX_BODY_KB was read by getChatLogMaxBodyBytes() but undocumented in .env.example and docs/reference/ENVIRONMENT.md -- tests/unit/check-env-doc-sync.test.ts flags any env var read in code but missing from both doc files. Documented it (both required -- the same test enforces the pairing). 2. truncateForLog()'s summary only computed messageCount from obj.messages (OpenAI-chat/Gemini field name) -- a large /v1/responses request (which uses input[], not messages[]) got summarized with no count at all, leaving the dashboard's "Full Conversation" panel nothing to base its "N messages not shown" placeholder on for any Responses-API conversation, even though the same summarization logic applies to it. Test plan: - TDD: tests/unit/chatcore-log-truncation.test.ts's new regression test ("captures a message count for Responses API bodies too") confirmed failing against the pre-fix code, passing after. - tests/unit/check-env-doc-sync.test.ts confirms CHAT_LOG_MAX_BODY_KB no longer appears in codeMissingEnv (remaining drift in that test is pre-existing/unrelated -- ANTIGRAVITY_ALLOW_SIGNATURE_BYPASS, COMMANDCODE_API_URL, OMNIROUTE_STRICT_SYSTEM_PROVIDERS, TLS_FINGERPRINT_PROVIDERS -- confirmed identical on a pristine upstream/release/v3.8.50 checkout, base-red inherited: diegosouzapw#9985). - tests/unit/chatcore-log-truncation.test.ts -- 19/19 passing. - npx tsc --noEmit / npm run lint -- clean.⚠️ base-red inherited: diegosouzapw#9985 * docs(logging): consolidate CHAT_LOG_MAX_BODY_KB into a single entry per file The variable was already documented (with a stale src/lib/chatLogTruncation.ts reference in .env.example); keep the new richer entries next to the CHAT_LOG_* family and drop the old duplicates. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Summary
X-ConversationIdresponse header). OmniRoute detects when a follow-up request continues the same conversation via fingerprint + bounded prefix-hash matching, with a strict-growth invariant (turns.length <= candidate.lastMessageCount→ reject) to prevent false merges between independent single-shot requests that happen to share identical opening content./dashboard/logs: new toggleable Conversation column./dashboard/logs/timeline: requests sharing a conversation id share a timeline lane, connected by an arrow, with a configurable lane-reuse window.MarkdownMessagecomponent)/dashboard/conversationspage listing only conversations with 2+ turns.Also fixes along the way
RequestTimeline.tsxhardcodeddebugEnabled={false}andemailsVisible={false}on the shared detail panel instead of reading the same server-side setting / store stateRequestLoggerV2.tsxalready used — meaning the timeline view never showed SSE/stream-chunk events or respected email-masking, regardless of the actual setting.overflow-x/overflow-yinteraction quirk).docs/security/AGENTROUTER_WAF.mdwas missing required frontmatter, breaking the Next.js/fumadocs build entirely — pre-existing onrelease/v3.8.50(landed in fix(agentrouter): retry on 400 content-blocked + burst guard #9323), unrelated to this feature, fixed here because it blocked building this branch for deploy verification.Test plan
npm run typecheck:core— cleannpm run lint— cleannpm run test:unit— 27109 passed; the only 18 failures present are confirmed pre-existing onrelease/v3.8.50(reproduced identically against the clean base commit in a throwaway verification worktree, unrelated to this branch — model-routing/gpt-5.5/gpt-5.6, vscode-token-routes, ServiceSupervisor, npm-pack, monaco-editor)npm run test:vitest— 291/291 passedconversationTracker.test.ts,agenticConversations.test.ts,multiRowConversation.test.ts,request-timeline-lane-allocation.test.ts(including a regression test for the strict-growth invariant, added after live testing surfaced two independent byte-identical single-message requests incorrectly merging into one conversation)omniroute-betacontainer across several rounds: multi-turn conversation tracking, turn-relative transcript truncation, click-navigation between turns, and — via direct curl polling of/api/logs/{id}mid-stream — confirmed the transcript genuinely grows turn-by-turn while a request is still actively streaming (not just after completion)omniroute-dev(rebased onto latestrelease/v3.8.50): health check passes, DB migration applied cleanly, new routes smoke-checked (proper 401 without auth, no 500s)