Skip to content

fix(dashboard): forward dead-key composition input to chat PTY - #76257

Closed
dplush wants to merge 10 commits into
NousResearch:mainfrom
dplush:fix/dashboard-ime-dead-key
Closed

fix(dashboard): forward dead-key composition input to chat PTY#76257
dplush wants to merge 10 commits into
NousResearch:mainfrom
dplush:fix/dashboard-ime-dead-key

Conversation

@dplush

@dplush dplush commented Aug 1, 2026

Copy link
Copy Markdown

Summary

Fixes #76233. The dashboard chat now uses committed compositionend text as a narrowly delayed fallback when xterm does not emit onData for dead-key/IME input. Normal xterm input remains authoritative; the fallback is cancelled when xterm delivers input, cleaned up on unmount, and SGR mouse reports do not cancel it.

Reproducer-first

On current main, the focused regression suite initially failed because the composition forwarder did not exist. The first commit adds that red regression; subsequent commits add the minimal forwarding and lifecycle handling.

Verification

  • npm test --workspace web -- --run src/lib/pty-composition.test.ts — 6 passed
  • npm run typecheck --workspace web — passed
  • npm run lint --workspace web -- src/lib/pty-composition.ts src/lib/pty-composition.test.ts src/pages/ChatPage.tsx — passed (existing repository warnings only)
  • git diff --check origin/main — passed
  • /opt/data/home/.local/bin/reviewer-claude-review diff origin/main --narrow — pass-with-followups; no blockers

Scope

Only dashboard PTY composition input and focused regression coverage. No API, persistence, auth, or model behavior changes.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for adding a focused fallback for the verified dashboard composition gap.

Problems

  • web/src/lib/pty-composition.ts:35 clears pending for every non-ESC xterm payload. The predicate does not compare incoming data with the pending committed text. Therefore onCompositionEnd("ä") followed by unrelated noteTerminalData("x") inside the 16 ms window drops ä rather than sending the fallback.
  • web/src/lib/pty-composition.test.ts covers a matching-ish "äx" input but not the unrelated-input loss case.

Suggested changes

  • Correlate cancellation with the pending composition (including any deliberate chunk handling), rather than cancelling on arbitrary terminal data.
  • Add a regression for a pending composition followed by unrelated xterm input before the timer fires.

This is an automated hermes-sweeper review.

Comment thread web/src/lib/pty-composition.ts Outdated
},
noteTerminalData(data: string) {
// A non-protocol xterm input in the short grace window is its own
// composition delivery (possibly chunked or normalization-different).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This clears a pending "ä" for any non-ESC terminal payload, including an unrelated next keystroke such as "x" during the 16 ms grace interval; then the fallback never sends "ä". Please correlate cancellation with the pending composition and add that regression case.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Aug 1, 2026
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/dashboard Web dashboard / control panel UI (dashboard/, landing) labels Aug 1, 2026
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

Two PRs address #76233 by adding a compositionend fallback for dead-key/IME text that xterm.js may not deliver through onData. #76257 uses a tested pending-commit helper with value-correlated cancellation, while #76337 suppresses its fallback after any printable payload observed during composition.

Related pull requests

Duplicates

#76257 and #76337 overlap at the issue and fallback level, but their mechanisms are not identical: #76257 uses correlated pending text, whereas #76337 counts arbitrary printable data during composition.

Suggested consolidation

Keep #76257 open with a salvage path centered on its extracted, value-correlated forwarder and regression coverage; validate the remaining ChatPage integration behavior against #76233. Choose that correlated composition contract as requested in the contributor reviews, and close #76337 as duplicate of #76257 because its alternative counter-based implementation retains the documented unrelated-input loss and adds no focused tests.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I76233(["issue #76233 (open)"])
    P76257["PR #76257 (open)"]
    P76257 -->|best fix| I76233
    class I76233 open
    class P76257 open
    class P76257 best
    class P76257 target
    click I76233 "https://github.com/NousResearch/hermes-agent/issues/76233"
    click P76257 "https://github.com/NousResearch/hermes-agent/pull/76257"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 2 pull requests and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 14 kB of PR diffs, 4 kB of issue/PR text, 3 kB of discussion (5 comments), 3 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

@dplush
dplush marked this pull request as ready for review August 8, 2026 01:56
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for this fix! It was salvaged into #86761 (cherry-picked onto current main with your authorship preserved in the commit history) and is now merged. Closing since the work has landed.

@teknium1 teknium1 closed this Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/dashboard Web dashboard / control panel UI (dashboard/, landing) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web Dashboard chat: German umlauts / dead-key input not delivered in xterm.js terminal

4 participants