Skip to content

TUI: restore hook-visible /new resets#49945

Open
caopulan wants to merge 2 commits intoopenclaw:mainfrom
caopulan:caopulan/tui-new-hooks
Open

TUI: restore hook-visible /new resets#49945
caopulan wants to merge 2 commits intoopenclaw:mainfrom
caopulan:caopulan/tui-new-hooks

Conversation

@caopulan
Copy link
Copy Markdown

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: #49918 reported that TUI /new stopped emitting hook-visible command:new behavior after the per-client session isolation change.
  • Why it matters: hook-driven flows like command-logger and session-memory silently stop running for TUI /new, even though users still expect a normal fresh-session reset.
  • What changed: /new now resets the newly allocated per-client tui-<uuid> session through sessions.reset(reason="new") before switching the TUI to that unique key, and the command-handler test now locks that route in.
  • What did NOT change (scope boundary): /reset behavior stays in-place on the current session, and TUI session isolation still uses unique per-client keys.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

TUI /new once again emits the same hook-visible reset path as other reset flows, while still creating an isolated tui-<uuid> session for the current TUI client.

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node 22 + pnpm + Vitest
  • Model/provider: N/A
  • Integration/channel (if any): TUI command handling + gateway session reset hooks
  • Relevant config (redacted): test harness defaults

Steps

  1. Register a hook that listens for command:new.
  2. Open openclaw tui and run /new.
  3. Observe whether the fresh-session path goes through sessions.reset(reason="new") or only switches local session state.

Expected

  • /new keeps the isolated tui-<uuid> behavior and still emits the standard hook-visible command:new reset path.

Actual

  • Before this patch, /new only called local setSession(uniqueKey) and skipped the gateway reset path entirely.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Verification commands run locally:

  • pnpm test -- src/tui/tui-command-handlers.test.ts
  • pnpm test -- src/gateway/server.sessions.gateway-server-sessions-a.test.ts -t 'sessions.reset emits internal command hook with reason'
  • pnpm exec oxfmt --check src/tui/tui-command-handlers.ts src/tui/tui-command-handlers.test.ts
  • pnpm exec oxlint src/tui/tui-command-handlers.ts src/tui/tui-command-handlers.test.ts

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: /new now routes through gateway reset with reason new, /reset still resets the shared current session, and existing gateway coverage still confirms that sessions.reset(reason="new") emits the internal command hook.
  • Edge cases checked: canonical agent:main:tui-<uuid> session key generation for /new and preserved /reset behavior.
  • What you did not verify: a live interactive TUI session with a real installed hook script.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert commit 37d84d03f8
  • Files/config to restore: src/tui/tui-command-handlers.ts, src/tui/tui-command-handlers.test.ts, CHANGELOG.md
  • Known bad symptoms reviewers should watch for: /new no longer emitting hook-visible resets, or TUI /new falling back to the shared main session instead of a unique tui-<uuid> key

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: /new could accidentally stop isolating the TUI client if the canonical unique key routing regresses.
    • Mitigation: the command-handler test asserts both the unique tui-<uuid> session handoff and the gateway reset call shape.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 18, 2026

Greptile Summary

This PR restores hook-visible command:new behavior for TUI /new by calling client.resetSession(nextSessionKey, "new") on the newly generated tui-<uuid> session key before handing the client off to that session via setSession. The per-client isolation introduced in #39217 is preserved — /new still generates a unique tui-<uuid> key — and /reset is unchanged.

Key changes:

  • src/tui/tui-command-handlers.ts: Builds the full canonical key (agent:<agentId>:tui-<uuid>) and calls client.resetSession with it before calling setSession, ensuring gateway hooks observe the reset. Display message now uses formatSessionKey on the full key for cleaner output.
  • src/tui/tui-command-handlers.test.ts: Tightens the mock type (ResetSessionMock), updates the combined /new+/reset test to assert both the gateway reset call shape and the setSession call shape, and renames the test to better describe the new invariant.
  • CHANGELOG.md: Entry added under the bug-fix section with issue reference.

Confidence Score: 5/5

  • Safe to merge — minimal, well-tested bug fix with no behavioral regressions.
  • The change is small and tightly scoped: one new await call inserted before an existing await, with matching test assertions that lock in both the gateway-reset key shape and the session-switch key. The double-normalization of state.currentAgentId via normalizeAgentId is safe because the function is idempotent. The partial-failure path (reset succeeds, setSession fails) leaves the user with a clear error and a retry option, identical in UX to the previous single-failure path. Existing sanitization and isolation tests continue to pass with the new ordering.
  • No files require special attention.

Last reviewed commit: "TUI: restore /new ho..."

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37d84d03f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/tui/tui-command-handlers.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b62dde6f7a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 278 to +281
target.canonicalKey ?? params.key,
{
sessionEntry: entry,
previousSessionEntry: entry,
sessionEntry: hookSourceEntry,
previousSessionEntry: hookSourceEntry,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid logging /new hooks under the fresh tui-* key

In the TUI /new flow, hookSourceKey now makes previousSessionEntry point at the session being left, but the emitted hook still uses sessionKey=target.canonicalKey. Bundled hooks such as src/hooks/bundled/command-logger/handler.ts:52-59 and src/hooks/bundled/session-memory/handler.ts:221-235 treat event.sessionKey as the conversation being archived, so installs with those hooks enabled will now record the old transcript under the brand-new tui-* key instead of the session that actually ended.

Useful? React with 👍 / 👎.

// to other connected TUI clients sharing the original session key.
const uniqueKey = `tui-${randomUUID()}`;
const nextSessionKey = `agent:${normalizeAgentId(state.currentAgentId)}:${uniqueKey}`;
await client.resetSession(nextSessionKey, "new", state.currentSessionKey);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip creating a persisted session row before the user sends anything

Calling sessions.reset on a brand-new tui-* key means /new now writes a fresh SessionEntry immediately, even though no message was ever sent on that session. performGatewaySessionReset always persists a new entry for the requested key, and src/gateway/session-utils.ts:868-976 lists every store row, so repeatedly pressing /new will leave behind blank tui-* sessions that clutter the session picker/history. Before this change, /new only switched the local key and did not persist an empty session.

Useful? React with 👍 / 👎.

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 28, 2026

Codex review: needs changes before merge.

Summary
The PR adds hookSourceKey plumbing to sessions.reset, calls it from TUI /new before switching to a unique tui-* key, and updates TUI/reset-hook tests plus the changelog.

Reproducibility: yes. by source inspection. Current main's TUI /new only switches local session state, while docs and reset-hook tests establish command:new as the hook-visible reset path.

Next step before merge
The remaining blockers are narrow code-level defects in the reset target/lifecycle path that an automated repair can attempt without product judgment.

Security
Cleared: The diff changes admin-scoped Gateway/TUI session reset plumbing and tests without adding dependencies, workflows, secret handling, or new external execution paths.

Review findings

  • [P2] Emit /new hooks for the session being left — src/tui/tui-command-handlers.ts:467
  • [P3] Avoid persisting blank TUI sessions on /new — src/tui/tui-command-handlers.ts:467
Review details

Best possible solution:

Preserve isolated TUI tui-* sessions, emit command:new and reset lifecycle hooks for the session being left, and avoid persisting the new TUI session row until it has real content.

Do we have a high-confidence way to reproduce the issue?

Yes, by source inspection. Current main's TUI /new only switches local session state, while docs and reset-hook tests establish command:new as the hook-visible reset path.

Is this the best way to solve the issue?

No. Calling sessions.reset on the future tui-* key restores one internal command event but leaves hook attribution, lifecycle context, and persistence tied to the wrong session; the narrower fix should target the session being left before switching keys.

Full review comments:

  • [P2] Emit /new hooks for the session being left — src/tui/tui-command-handlers.ts:467
    Calling resetSession(nextSessionKey, "new", state.currentSessionKey) still makes sessions.reset emit command:new, before_reset, session_end, and session_start around the fresh agent:main:tui-* target. Even with hookSourceKey filling previousSessionEntry, bundled hooks see event.sessionKey and lifecycle context for the new empty session instead of the conversation that ended. Fire the hook/lifecycle path against state.currentSessionKey, then switch to the isolated key.
    Confidence: 0.9
  • [P3] Avoid persisting blank TUI sessions on /new — src/tui/tui-command-handlers.ts:467
    sessions.reset always writes a new store entry and transcript header for its target. Since this call targets a freshly generated tui-* key before any message is sent, every /new can leave an empty persisted session in history; keep the unique key lazy or use a hook-only path that does not create the row.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.89

Acceptance criteria:

  • pnpm test -- src/tui/tui-command-handlers.test.ts src/gateway/server.sessions.reset-hooks.test.ts src/hooks/bundled/session-memory/handler.test.ts
  • pnpm exec oxfmt --check --threads=1 src/tui/tui-command-handlers.ts src/tui/tui-command-handlers.test.ts src/gateway/session-reset-service.ts src/gateway/server.sessions.reset-hooks.test.ts src/hooks/bundled/session-memory/handler.test.ts
  • pnpm exec oxlint src/tui/tui-command-handlers.ts src/tui/tui-command-handlers.test.ts src/gateway/session-reset-service.ts src/gateway/server.sessions.reset-hooks.test.ts src/hooks/bundled/session-memory/handler.test.ts
  • pnpm check:changed

What I checked:

Likely related people:

  • widingmarcus-cyber: Contributor PR fix(tui): isolate /new sessions to prevent cross-client broadcast #39238 introduced the isolated TUI /new behavior that this fix must preserve while restoring hooks. (role: introduced behavior; confidence: medium; commits: 46008178d1ba; files: src/tui/tui-command-handlers.ts, src/tui/tui-command-handlers.test.ts)
  • Peter Steinberger: The TUI isolation behavior appears in commit 46008178, and nearby reset/session-memory test history includes several maintainer follow-ups by this author. (role: merger and maintainer; confidence: medium; commits: 46008178d1ba, 445c7a65e6d1, 1e2b367e1ea0; files: src/tui/tui-command-handlers.ts, src/tui/tui-command-handlers.test.ts, src/hooks/bundled/session-memory/handler.test.ts)
  • Vignesh Natarajan: Commit b08146f introduced the original TUI/Gateway internal hook behavior for /new and /reset, which is the contract this PR is restoring. (role: introduced hook path; confidence: medium; commits: b08146fad6e4; files: src/tui/tui-command-handlers.ts, src/gateway/session-reset-service.ts)
  • Tak Hoffman: Recent reset-hook context commits are directly adjacent to previousSessionEntry and target-entry attribution behavior. (role: recent reset-hook maintainer; confidence: medium; commits: 9403008c6c68, 94340b959830; files: src/gateway/session-reset-service.ts, src/gateway/server.sessions.reset-hooks.test.ts)

Remaining risk / open question:

  • Validation commands were not run locally because pnpm is unavailable in this read-only checkout.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 103cdd9d96f8.

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.

[Bug]: TUI /new stopped emitting hook-visible new-session behavior after 46008178d

1 participant