fix(coding-agent): preserve backslash escapes in user messages

closes #6105
This commit is contained in:
Armin Ronacher
2026-06-27 19:23:52 +02:00
parent 622eca7608
commit f2e9d75388
5 changed files with 32 additions and 1 deletions
+4
View File
@@ -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
+6
View File
@@ -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) {
+20
View File
@@ -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