hermes - 💡(How to fix) Fix [Bug]: sanitize_title removes the ESC anchor before the sequence is stripped — escape body survives in session titles

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Session titles generated from a first message that contains terminal escape sequences (ANSI CSI / OSC) keep the body of the sequence as visible garbage — e.g. a pasted \x1b[31mRed\x1b[0m is stored as the title [31mRed[0m, and \x1b]11;rgb:2828/2c2c/3434\x07 as ]11;rgb:2828/2c2c/3434.

Root Cause

SessionDB.sanitize_title() removes control bytes with:

cleaned = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', title)

0x1b (ESC, within \x0e-\x1f) and 0x07 (BEL, within \x00-\x08) are deleted, but the printable sequence body ([31m, ]11;…) is ordinary ASCII and survives. The repo already ships tools/ansi_strip.py::strip_ansi (full ECMA-48, fast-path no-op on clean text) — used by terminal_tool / code_execution_tool / process_registry — which removes whole sequences, but it must run before the control-char strip, while the ESC anchor is still present.

Fix Action

Fix

from tools.ansi_strip import strip_ansi
...
cleaned = strip_ansi(title)                                  # ESC anchor still present
cleaned = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', cleaned)

Complementary, not redundant: strip_ansi removes escape-anchored sequences + C1 controls; the existing regex still removes lone C0 controls it doesn't touch. All-escape input collapses to '' → existing return None. The fast-path makes it a no-op for clean CJK/emoji/RTL titles.

Code Example

cleaned = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', title)

---

from tools.ansi_strip import strip_ansi
...
cleaned = strip_ansi(title)                                  # ESC anchor still present
cleaned = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', cleaned)
RAW_BUFFERClick to expand / collapse

Summary

Session titles generated from a first message that contains terminal escape sequences (ANSI CSI / OSC) keep the body of the sequence as visible garbage — e.g. a pasted \x1b[31mRed\x1b[0m is stored as the title [31mRed[0m, and \x1b]11;rgb:2828/2c2c/3434\x07 as ]11;rgb:2828/2c2c/3434.

Repro

  1. Start a new session via a chat gateway (observed via Telegram).
  2. Make the first message contain escapes, e.g. \x1b[31mRed\x1b[0m or \x1b]11;rgb:2828/2c2c/3434\x07.
  3. Auto-title generation runs on the first exchange.
  4. The stored/displayed title contains the residue above.

Root cause

SessionDB.sanitize_title() removes control bytes with:

cleaned = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', title)

0x1b (ESC, within \x0e-\x1f) and 0x07 (BEL, within \x00-\x08) are deleted, but the printable sequence body ([31m, ]11;…) is ordinary ASCII and survives. The repo already ships tools/ansi_strip.py::strip_ansi (full ECMA-48, fast-path no-op on clean text) — used by terminal_tool / code_execution_tool / process_registry — which removes whole sequences, but it must run before the control-char strip, while the ESC anchor is still present.

Fix

from tools.ansi_strip import strip_ansi
...
cleaned = strip_ansi(title)                                  # ESC anchor still present
cleaned = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', cleaned)

Complementary, not redundant: strip_ansi removes escape-anchored sequences + C1 controls; the existing regex still removes lone C0 controls it doesn't touch. All-escape input collapses to '' → existing return None. The fast-path makes it a no-op for clean CJK/emoji/RTL titles.

Scope

Session titles are not FTS5-indexed (only message content is, and that is stored raw by design), so this is a title display/storage fix only.

I have a fix + regression tests ready and will open a PR.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING