fix(gateway): include session label in deriveSessionTitle fallback chain#98841
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 3, 2026, 4:40 AM ET / 08:40 UTC. Summary PR surface: Source +6, Tests +30. Total +36 across 4 files. Reproducibility: yes. at source level: current main ignores entry.label in deriveSessionTitle while TUI and ACP paths request or consume derivedTitle before later fallbacks. I did not run a live Control UI/TUI refresh reproduction in this read-only review. Review metrics: none identified. Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the focused shared-helper precedence fix with the /name suggestion preservation, then keep broader auto-title and origin-label refactors in separate review paths. Do we have a high-confidence way to reproduce the issue? Yes, at source level: current main ignores entry.label in deriveSessionTitle while TUI and ACP paths request or consume derivedTitle before later fallbacks. I did not run a live Control UI/TUI refresh reproduction in this read-only review. Is this the best way to solve the issue? Yes: fixing the shared gateway title helper is narrower than patching each UI client, and the added /name change handles the only local caller that intentionally wants a suggestion excluding the current label. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 1fef99962edf. Label changesLabel justifications:
Evidence reviewedPR surface: Source +6, Tests +30. Total +36 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
@clawsweeper re-review Proof updated — real runtime evidence added beyond unit tests: 1. Direct runtime proof ( 2. Full pipeline proof ( Label-only sessions now get 3. Supplementary unit tests: 6 new cases + 10 existing, all 3 CI shards pass. Not tested: Live Control UI/TUI browser session rename and refresh (needs running gateway + browser — maintainer can use |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Proof updated with real gateway session store evidence (redacted production Summary: All 11 real production sessions with |
When a session is renamed with /name, the user-provided label is persisted in sessions.json but was ignored by deriveSessionTitle. This caused the TUI session picker and other derived-title consumers to show auto-generated or UUID-based names instead of the user's label. Add entry.label to the deriveSessionTitle fallback chain after displayName and subject, before the auto-derived firstUserMessage and sessionId fallbacks. This aligns with the existing ACP translator precedence (derivedTitle ?? displayName ?? label ?? key). Related to openclaw#98742 Co-Authored-By: Claude Opus 4.8 <[email protected]>
a789783 to
bac3b5d
Compare
|
Land-ready verification for exact head
No screenshot attached: this fixes session metadata returned over Gateway RPC; the before/after proof is the exact RPC result. Thanks @SunnyShu0925 for the fix. |
|
Merged via squash.
|
…ain (openclaw#98841) * fix(gateway): include session label in deriveSessionTitle fallback chain When a session is renamed with /name, the user-provided label is persisted in sessions.json but was ignored by deriveSessionTitle. This caused the TUI session picker and other derived-title consumers to show auto-generated or UUID-based names instead of the user's label. Add entry.label to the deriveSessionTitle fallback chain after displayName and subject, before the auto-derived firstUserMessage and sessionId fallbacks. This aligns with the existing ACP translator precedence (derivedTitle ?? displayName ?? label ?? key). Related to openclaw#98742 Co-Authored-By: Claude Opus 4.8 <[email protected]> * test(gateway): tighten session label precedence coverage * fix(gateway): prioritize explicit session labels * fix(commands): preserve named-session suggestions --------- Co-authored-by: Claude Opus 4.8 <[email protected]> Co-authored-by: Peter Steinberger <[email protected]>
What Problem This Solves
Sessions renamed with
/namein Control UI/TUI can appear unnamed (UUID-only) even though the user-provided label is still persisted insessions.json. The root cause isderiveSessionTitleignoringentry.labelwhile multiple consumers resolve titles from derived titles before display names.deriveSessionTitleskipsentry.label, so TUI picker (derivedTitle ?? displayName) and other derived-title consumers fall through to auto-generated text or sessionId UUIDs, hiding the user-set labelentry.labelinto thederiveSessionTitlefallback chain after displayName/subject and before auto-derived firstUserMessage/sessionIdsrc/gateway/session-utils.ts(4 lines — label check),src/gateway/session-utils.test.ts(46 lines — 6 new regression tests)buildGatewaySessionRowdisplayName projection (already uses label),resolveSessionDisplayName(already prefers label), ACP translator (already had label in precedence), TUI picker, Control UI list/session-control pathsChange Type
Scope
Linked Issue/PR
Motivation
The issue reporter observed that
/name <label>persistedlabeltosessions.jsoncorrectly, but after reloads or session-family rotations the Control UI rendered a UUID instead. Source inspection confirms the gap:deriveSessionTitle(line 237 insession-utils.ts) checksdisplayName→subject→firstUserMessage→sessionIdbut never readsentry.label. The TUI session picker requestsincludeDerivedTitlesand rendersderivedTitle ?? displayName, so a label-only session shows its raw key instead.This is consistent with the existing ACP translator convention at
src/acp/translator.ts:1425:The fix aligns
deriveSessionTitlewith that contract.Evidence
Behavior addressed:
deriveSessionTitlenow includes user-provided/namelabel in fallback chain, so TUI picker, Control UI header, and any derived-title path display the label instead of UUID when displayName/subject are absentReal environment tested: Linux x64, Node 24.17.0, branch
fix/session-label-title-98742Exact steps or command run after this patch:
$ pnpm vitest run src/gateway/session-utils.test.ts -t "deriveSessionTitle" --reporter=verboseBefore fix, the first two cases would have returned:
label-only →
"a1b2c3d4 (2026-07-02)"(UUID, user label ignored)label + firstUserMessage →
"Hello, what can you do for me today?"(auto-derived, user label ignored)Real gateway session store proof — loaded from production
sessions.json(19 entries, 11 with/namelabels, redacted):Result: All 11 real production sessions with
/namelabels but nodisplayName/subjectnow correctly resolvederivedTitlefromlabel. Before this fix, they would have shown UUID prefixes. Subject and displayName still take precedence as expected.Supplementary unit test evidence (3 CI shards × 15 tests all passed):
Precedence matrix (inputs →
deriveSessionTitleoutput):listSessionsFromStorewithincludeDerivedTitles=true(matches TUI picker code path):Observed result after fix:
deriveSessionTitlereturns user label when only label is set (no displayName/subject)listSessionsFromStorewithincludeDerivedTitles=truecorrectly populatesderivedTitlefromlabelfor label-only sessions — the exact TUI picker code pathbuildGatewaySessionRowalready usedentry.labelfordisplayNameprojection; nowderivedTitleis also label-aware, closing the gapWhat was not tested:
Root Cause
deriveSessionTitle(introduced January 2026 by CJ Winslow in session picker work) was designed with adisplayName → subject → firstUserMessage → sessionIdfallback chain. When/namesupport was later added by Azade/Thomas Krohnfuß, thelabelfield was populated insessions.jsonand consumed bybuildGatewaySessionRowandresolveSessionDisplayName, butderiveSessionTitlewas never updated to include it.The TUI picker requests
includeDerivedTitlesand rendersderivedTitle ?? displayName, so a session with only a label (no displayName/subject) renders as its raw session key UUID.Regression Test Plan
6 new test cases in
session-utils.test.tsderiveSessionTitlesuite:User-visible / Behavior Changes
TUI session picker and any derived-title consumer (Control UI header after session-family rotation, ACP bridge) now show the user's
/namelabel instead of a UUID when displayName and subject are not set.Security Impact
Compatibility / Migration
Best-fix Verdict
deriveSessionTitleis the single shared boundary; fixing here covers all pathsAI Assistance
Risks and Mitigations
displayNameprojection might now also show it viaderivedTitle; this is strictly additive — label visibility can only increase, never decreasenormalizeOptionalStringgate as every other level; whitespace-only and empty labels fall through identically to empty displayName/subject behaviorFixes #98742