Commit graph

3 commits

Author SHA1 Message Date
nesquena-hermes
e2ade27bfe fix(anchor): preserve settled mixed content order (#4958)
When a settled assistant turn carries _anchor_activity_scene and has mixed
content[] (text interleaved with tool_use), promote that ordering into anchor
scene rows (prose / tool / thinking rows in sequence) instead of only the raw
content[] fallback, and mirror the same scene model in the backend hydration
path so a cold reload reconstructs an identical transcript.

Also fixes: post-tool_use text/thinking in a NON-FINAL assistant message was
silently dropped — only the turn-final assistant's post-last-tool text is the
"final answer" tail; earlier assistant messages keep post-tool content as
activity rows. Tail thinking is excluded from the final-answer text but still
emitted as a thinking row (verified on both JS and Python paths).

Tool-row de-duplication is conservative — ID-equal always merges; name/
invocation matches are cardinality-gated and same-message; body-prefix is only
a secondary confirmation inside the id-flexible branch (also requires matching
started_at + compatible name + invocation). It biases toward an extra visible
tool card over ever silently merging two distinct calls.

Gate: Codex SAFE (tail-thinking edge verified already-handled both sides),
Opus SHIP (dedup fails toward duplicate-not-loss; non-final preservation, XSS,
non-mixed regression all clean), full suite 10778 passed (only the 4 known
pre-existing flakes). One non-blocking follow-up noted: bring the prose/thinking
peer-dedup into JS↔Python parity (cosmetic cold-reload extra-narration row).

Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
2026-06-27 22:54:29 +00:00
nesquena-hermes
89d7fae347 fix(#4622): restore full body for CAPPED-PREVIEW settled snippets, not just empty
Codex gate caught that the enrich only restored when the settled snippet was
fully EMPTY — but the backend persists a 4000-char capped preview
(_TOOL_RESULT_SNIPPET_MAX), so long terminal/tool output settles to a truncated
4000-char prefix, not empty (the actual #4622 symptom). Now also restore when
the settled snippet is a bounded preview of the live one (live longer + settled
is a prefix + settled length >= the 4000 cap), without clobbering a genuinely
short non-preview value. Adds capped-preview restore + short-prefix-not-clobbered
tests (proven non-vacuous).
2026-06-25 06:51:33 +00:00
nesquena-hermes
ef3092434f fix(#4622): restore tool-card result body on the settled rebuild path
In the Transparent Stream / Worklog view, terminal tool cards lost their stdout
and patch/edit cards lost their diff AFTER a turn settled (live cards were fine).

Root cause (proven via a node harness driving the real settled chain
_anchorSceneRowsByMessageIndex -> _anchorSceneToolRowFromCall ->
_anchorSceneToolCallFromRow): the settled rebuild builds each tool row from the
persisted messages[].tool_calls (state.db/sidecar), which can carry only a short
preview — or, on a cold/paginated load, nothing — for the result body. The full
output lives on the live S.toolCalls entry at settle time, but the dedup loop in
_anchorSceneRowsByMessageIndex SKIPPED the matching live entry (continue) instead
of restoring the missing body onto the surviving settled row. So buildToolCard
got tc.snippet='' -> empty output region, and the patch/edit diff (detected from
the snippet) never rendered. This also blanks the transparent 'Output' tab and
the 'Full' (detailed-input) tab.

Fix: new _enrichSettledToolRowBodyFromLive() restores snippet/result/output,
command, and args onto a settled row from the matched live call, ONLY when the
settled value is empty (never clobbers a genuinely persisted body). Wired into
the dedup loop: on a tid match that would have been skipped, enrich the existing
pooled row instead of dropping the live data.

The prior #4625 guard only exercised the LIVE buildToolCard path, which is why it
stayed green while the settled path regressed. New
tests/test_issue4622_settled_toolcard_body.py drives the full SETTLED chain and
asserts: terminal stdout restored + full output in data-full + transparent Output
tab non-empty; patch diff body restored + renders as a diff + Full-tab args kept;
genuine persisted body not clobbered; args restored when dropped; no-live-match
leaves the row untouched; no duplicate row after enrich. Verified to FAIL on clean
master (assertions) and pass with the fix. Also registered the new helper in the
and now references the new symbol).

Reusable proof harness saved to ~/WebUI/qa/harnesses/.

Closes #4622.
2026-06-25 06:40:27 +00:00