fix(coding-agent): preserve backslash escapes in user messages
closes #6105
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed `--session` and `SessionManager.open()` to reject non-empty invalid session files without overwriting them ([#6002](https://github.com/earendil-works/pi/issues/6002)).
|
||||
- Fixed user-message transcript rendering to keep visible backslashes in Markdown escape sequences such as `\"` ([#6105](https://github.com/earendil-works/pi/issues/6105)).
|
||||
- Fixed assistant messages stopped by output length to show a visible incomplete-response error ([#4290](https://github.com/earendil-works/pi/issues/4290)).
|
||||
- Fixed `--no-session --session-id` so ephemeral CLI runs can use deterministic session IDs for provider cache affinity ([#6070](https://github.com/earendil-works/pi/issues/6070)).
|
||||
- Fixed disk BMP image files to be detected, converted to PNG, and attached through `read` and CLI `@file` inputs ([#6047](https://github.com/earendil-works/pi/issues/6047)).
|
||||
|
||||
@@ -23,7 +23,7 @@ export class UserMessageComponent extends Container {
|
||||
{
|
||||
color: (content: string) => theme.fg("userMessageText", content),
|
||||
},
|
||||
{ preserveOrderedListMarkers: true },
|
||||
{ preserveOrderedListMarkers: true, preserveBackslashEscapes: true },
|
||||
),
|
||||
);
|
||||
this.addChild(this.contentBox);
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added an opt-in Markdown renderer option to preserve source backslash escapes for transcript rendering ([#6105](https://github.com/earendil-works/pi/issues/6105)).
|
||||
|
||||
## [0.80.2] - 2026-06-23
|
||||
|
||||
## [0.80.1] - 2026-06-23
|
||||
|
||||
@@ -98,6 +98,8 @@ export interface MarkdownTheme {
|
||||
export interface MarkdownOptions {
|
||||
/** Preserve source list markers instead of normalizing them. */
|
||||
preserveOrderedListMarkers?: boolean;
|
||||
/** Preserve source backslash escapes instead of normalizing escaped punctuation. */
|
||||
preserveBackslashEscapes?: boolean;
|
||||
}
|
||||
|
||||
interface InlineStyleContext {
|
||||
@@ -498,6 +500,10 @@ export class Markdown implements Component {
|
||||
|
||||
for (const token of tokens) {
|
||||
switch (token.type) {
|
||||
case "escape":
|
||||
result += applyTextWithNewlines(this.options.preserveBackslashEscapes ? token.raw : token.text);
|
||||
break;
|
||||
|
||||
case "text":
|
||||
// Text tokens in list items can have nested tokens for inline formatting
|
||||
if (token.tokens && token.tokens.length > 0) {
|
||||
|
||||
@@ -654,6 +654,26 @@ describe("Markdown component", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Backslash escapes", () => {
|
||||
it("should normalize escaped punctuation by default", () => {
|
||||
const markdown = new Markdown(String.raw`"\"`, 0, 0, defaultMarkdownTheme);
|
||||
|
||||
const lines = markdown.render(80).map((line) => stripAnsi(line).trimEnd());
|
||||
|
||||
assert.deepStrictEqual(lines, [`""`]);
|
||||
});
|
||||
|
||||
it("should preserve source backslash escapes when configured", () => {
|
||||
const markdown = new Markdown(String.raw`"\"`, 0, 0, defaultMarkdownTheme, undefined, {
|
||||
preserveBackslashEscapes: true,
|
||||
});
|
||||
|
||||
const lines = markdown.render(80).map((line) => stripAnsi(line).trimEnd());
|
||||
|
||||
assert.deepStrictEqual(lines, [String.raw`"\"`]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Pre-styled text (thinking traces)", () => {
|
||||
it("should preserve gray italic styling after inline code", () => {
|
||||
// This replicates how thinking content is rendered in assistant-message.ts
|
||||
|
||||
Reference in New Issue
Block a user