unwrap pasted text only where it is an attachment

`messageToPlainText` shares one `collect` between `msg.content` and attachment
content, so b5dc502 ran `unwrapPastedTextContent` over message bodies too. A
message that legitimately opens with `<pasted_text name=...>`, a code sample
about this feature being the obvious case, had its first and last lines stripped
out of fine-tuning exports.

`collect` now takes the source, and only attachment blocks are unwrapped, which
is what `messageToText` and `messageToMarkdown` already did.
This commit is contained in:
Maheswar Kumar 2026-08-13 20:04:00 +12:00
parent b5dc502523
commit 4011c4ad96

View file

@ -619,10 +619,15 @@ function messageToPlainText(msg: {
attachments?: unknown;
}): string {
const parts: string[] = [];
const collect = (blocks: unknown) => {
// Only attachment text is unwrapped: a message body is verbatim, and may
// legitimately quote the wrapper syntax in a code sample.
const collect = (blocks: unknown, fromAttachment = false) => {
const normalize = fromAttachment
? unwrapPastedTextContent
: (text: string) => text;
// Legacy and imported histories can store content as a plain string.
if (typeof blocks === "string") {
if (blocks.trim()) parts.push(blocks);
if (blocks.trim()) parts.push(normalize(blocks));
return;
}
if (!Array.isArray(blocks)) return;
@ -632,15 +637,14 @@ function messageToPlainText(msg: {
}
const block = b as Record<string, unknown>;
if (block.type === "text" && typeof block.text === "string" && block.text) {
// No-op for message content, which never carries the paste wrapper.
parts.push(unwrapPastedTextContent(block.text));
parts.push(normalize(block.text));
}
}
};
collect(msg.content);
if (Array.isArray(msg.attachments)) {
for (const attachment of msg.attachments as Array<{ content?: unknown }>) {
collect(attachment?.content);
collect(attachment?.content, true);
}
}
return parts.join("\n\n").trim();