Skip to content

Commit 48edfe6

Browse files
committed
Only load context and parse @-mentions in user input
1 parent f12c342 commit 48edfe6

File tree

3 files changed

+99
-9
lines changed

3 files changed

+99
-9
lines changed

.changeset/odd-news-yell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
Only parse @-mentions in user input (not in files)

src/core/Cline.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,22 +2360,30 @@ export class Cline {
23602360
// 2. ToolResultBlockParam's content/context text arrays if it contains "<feedback>" (see formatToolDeniedFeedback, attemptCompletion, executeCommand, and consecutiveMistakeCount >= 3) or "<answer>" (see askFollowupQuestion), we place all user generated content in these tags so they can effectively be used as markers for when we should parse mentions)
23612361
Promise.all(
23622362
userContent.map(async (block) => {
2363+
const shouldProcessMentions = (text: string) =>
2364+
text.includes("<task>") || text.includes("<feedback>");
2365+
23632366
if (block.type === "text") {
2364-
return {
2365-
...block,
2366-
text: await parseMentions(block.text, cwd, this.urlContentFetcher),
2367-
}
2368-
} else if (block.type === "tool_result") {
2369-
const isUserMessage = (text: string) => text.includes("<feedback>") || text.includes("<answer>")
2370-
if (typeof block.content === "string" && isUserMessage(block.content)) {
2367+
if (shouldProcessMentions(block.text)) {
23712368
return {
23722369
...block,
2373-
content: await parseMentions(block.content, cwd, this.urlContentFetcher),
2370+
text: await parseMentions(block.text, cwd, this.urlContentFetcher),
2371+
}
2372+
}
2373+
return block;
2374+
} else if (block.type === "tool_result") {
2375+
if (typeof block.content === "string") {
2376+
if (shouldProcessMentions(block.content)) {
2377+
return {
2378+
...block,
2379+
content: await parseMentions(block.content, cwd, this.urlContentFetcher),
2380+
}
23742381
}
2382+
return block;
23752383
} else if (Array.isArray(block.content)) {
23762384
const parsedContent = await Promise.all(
23772385
block.content.map(async (contentBlock) => {
2378-
if (contentBlock.type === "text" && isUserMessage(contentBlock.text)) {
2386+
if (contentBlock.type === "text" && shouldProcessMentions(contentBlock.text)) {
23792387
return {
23802388
...contentBlock,
23812389
text: await parseMentions(contentBlock.text, cwd, this.urlContentFetcher),
@@ -2389,6 +2397,7 @@ export class Cline {
23892397
content: parsedContent,
23902398
}
23912399
}
2400+
return block;
23922401
}
23932402
return block
23942403
}),

src/core/__tests__/Cline.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,82 @@ describe('Cline', () => {
626626
text: '[Referenced image in conversation]'
627627
});
628628
});
629+
630+
describe('loadContext', () => {
631+
it('should process mentions in task and feedback tags', async () => {
632+
const cline = new Cline(
633+
mockProvider,
634+
mockApiConfig,
635+
undefined,
636+
false,
637+
undefined,
638+
'test task'
639+
);
640+
641+
// Mock parseMentions to track calls
642+
const mockParseMentions = jest.fn().mockImplementation(text => `processed: ${text}`);
643+
jest.spyOn(require('../../core/mentions'), 'parseMentions').mockImplementation(mockParseMentions);
644+
645+
const userContent = [
646+
{
647+
type: 'text',
648+
text: 'Regular text with @/some/path'
649+
} as const,
650+
{
651+
type: 'text',
652+
text: '<task>Text with @/some/path in task tags</task>'
653+
} as const,
654+
{
655+
type: 'tool_result',
656+
tool_use_id: 'test-id',
657+
content: [{
658+
type: 'text',
659+
text: '<feedback>Check @/some/path</feedback>'
660+
}]
661+
} as Anthropic.ToolResultBlockParam,
662+
{
663+
type: 'tool_result',
664+
tool_use_id: 'test-id-2',
665+
content: [{
666+
type: 'text',
667+
text: 'Regular tool result with @/path'
668+
}]
669+
} as Anthropic.ToolResultBlockParam
670+
];
671+
672+
// Process the content
673+
const [processedContent] = await cline['loadContext'](userContent);
674+
675+
// Regular text should not be processed
676+
expect((processedContent[0] as Anthropic.TextBlockParam).text)
677+
.toBe('Regular text with @/some/path');
678+
679+
// Text within task tags should be processed
680+
expect((processedContent[1] as Anthropic.TextBlockParam).text)
681+
.toContain('processed:');
682+
expect(mockParseMentions).toHaveBeenCalledWith(
683+
'<task>Text with @/some/path in task tags</task>',
684+
expect.any(String),
685+
expect.any(Object)
686+
);
687+
688+
// Feedback tag content should be processed
689+
const toolResult1 = processedContent[2] as Anthropic.ToolResultBlockParam;
690+
const content1 = Array.isArray(toolResult1.content) ? toolResult1.content[0] : toolResult1.content;
691+
expect((content1 as Anthropic.TextBlockParam).text).toContain('processed:');
692+
expect(mockParseMentions).toHaveBeenCalledWith(
693+
'<feedback>Check @/some/path</feedback>',
694+
expect.any(String),
695+
expect.any(Object)
696+
);
697+
698+
// Regular tool result should not be processed
699+
const toolResult2 = processedContent[3] as Anthropic.ToolResultBlockParam;
700+
const content2 = Array.isArray(toolResult2.content) ? toolResult2.content[0] : toolResult2.content;
701+
expect((content2 as Anthropic.TextBlockParam).text)
702+
.toBe('Regular tool result with @/path');
703+
});
704+
});
629705
});
630706
});
631707
});

0 commit comments

Comments
 (0)