logancyang_obsidian-copilot/src/utils.cleanMessageForCopy.test.ts
Logan Yang 3e323ba8c8
Fix insert/replace at cursor including agent reasoning blocks (#2174)
Strip <!--AGENT_REASONING:...--> markers in cleanMessageForCopy() so
that "Insert / Replace at cursor" only inserts the actual AI response,
not the internal agent reasoning metadata.

Uses greedy .* (single-line) so the regex matches to the real closing
--> even if the JSON payload contains that sequence.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 19:54:52 -08:00

130 lines
4.3 KiB
TypeScript

import { cleanMessageForCopy } from "./utils";
describe("cleanMessageForCopy", () => {
it("should remove Think blocks", () => {
const input = "Before text\n<think>This is my thought process</think>\nAfter text";
const expected = "Before text\n\nAfter text";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should remove writeToFile blocks wrapped in XML codeblocks", () => {
const input = `Some text before
\`\`\`xml
<writeToFile>
<path>test.md</path>
<content>File content here</content>
</writeToFile>
\`\`\`
Some text after`;
const expected = "Some text before\n\nSome text after";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should remove standalone writeToFile blocks", () => {
const input = `Text before
<writeToFile>
<path>test.md</path>
<content>File content</content>
</writeToFile>
Text after`;
const expected = "Text before\n\nText after";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should remove tool call markers", () => {
const input =
"Before\n<!--TOOL_CALL_START:123:localSearch:Local Search:🔍::true-->Searching...<!--TOOL_CALL_END:123:Found 5 results-->\nAfter";
const expected = "Before\n\nAfter";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should handle multiple blocks in one message", () => {
const input = `Start of message
<think>First thought</think>
Middle part
<writeToFile><path>file.md</path><content>content</content></writeToFile>
<!--TOOL_CALL_START:456:webSearch:Web Search:🌐::false-->Searching web<!--TOOL_CALL_END:456:Results-->
End of message`;
const expected = "Start of message\n\nMiddle part\n\nEnd of message";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should clean up multiple consecutive newlines", () => {
const input = `Text\n\n\n\n\nMore text`;
const expected = "Text\n\nMore text";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should preserve normal content", () => {
const input = `# Heading
This is a normal message with:
- Bullet points
- Code blocks: \`const x = 1;\`
- **Bold** and *italic* text
\`\`\`javascript
function test() {
return true;
}
\`\`\`
More content here.`;
expect(cleanMessageForCopy(input)).toBe(input);
});
it("should handle nested think blocks", () => {
const input =
"Before\n<think>Outer thought <think>Inner thought</think> back to outer</think>\nAfter";
// Since we're not handling nested blocks, the outer block will be removed but inner content remains
const expected = "Before\n back to outer</think>\nAfter";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should handle multiline content in blocks", () => {
const input = `Start
<think>
Line 1 of thought
Line 2 of thought
Line 3 of thought
</think>
End`;
const expected = "Start\n\nEnd";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should trim leading and trailing whitespace", () => {
const input = "\n\n Content with spaces \n\n";
const expected = "Content with spaces";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should handle empty message", () => {
expect(cleanMessageForCopy("")).toBe("");
});
it("should handle message with only blocks to remove", () => {
const input = "<think>Only a thought</think>";
const expected = "";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should remove agent reasoning blocks", () => {
const input = `<!--AGENT_REASONING:complete:12:["Searching notes","Read 3 notes","Analyzing content"]-->Here is my response based on the analysis.`;
const expected = "Here is my response based on the analysis.";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should remove agent reasoning blocks with surrounding content", () => {
const input = `Some intro text
<!--AGENT_REASONING:collapsed:5:["Searching notes"]-->
Here is the actual response.`;
const expected = "Some intro text\n\nHere is the actual response.";
expect(cleanMessageForCopy(input)).toBe(expected);
});
it("should handle agent reasoning blocks whose step summaries contain -->", () => {
const input = `<!--AGENT_REASONING:complete:8:["Step with --> inside"]-->Actual response.`;
const expected = "Actual response.";
expect(cleanMessageForCopy(input)).toBe(expected);
});
});