mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
refactor(task): switch to <feedback> wrapper to prevent focus drift after context-management event (condense/truncate) (#9237)
* refactor(task): wrap initial user message in <feedback> instead of <task> to prevent focus drift after context-management Rationale: After a successful context-management event, framing the next user block as feedback reduces model focus drift. Mentions parsing already supports <feedback>, and tool flows (attemptCompletion, responses) are aligned. No change to loop/persistence. * refactor(mentions): drop <task> parsing; standardize on <feedback>; update tests
This commit is contained in:
parent
ad1e9a82f9
commit
aaab2bf4d4
4 changed files with 22 additions and 25 deletions
|
|
@ -31,7 +31,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Read file with limit</task>",
|
||||
text: "<feedback>Read file with limit</feedback>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Read file with limit</task>",
|
||||
"<feedback>Read file with limit</feedback>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
@ -61,7 +61,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Read file without limit</task>",
|
||||
text: "<feedback>Read file without limit</feedback>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Read file without limit</task>",
|
||||
"<feedback>Read file without limit</feedback>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
@ -90,7 +90,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Read unlimited lines</task>",
|
||||
text: "<feedback>Read unlimited lines</feedback>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Read unlimited lines</task>",
|
||||
"<feedback>Read unlimited lines</feedback>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
@ -118,11 +118,11 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
describe("content processing", () => {
|
||||
it("should process text blocks with <task> tags", async () => {
|
||||
it("should process text blocks with <feedback> tags", async () => {
|
||||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Do something</task>",
|
||||
text: "<feedback>Do something</feedback>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ describe("processUserContentMentions", () => {
|
|||
expect(parseMentions).toHaveBeenCalled()
|
||||
expect(result[0]).toEqual({
|
||||
type: "text",
|
||||
text: "parsed: <task>Do something</task>",
|
||||
text: "parsed: <feedback>Do something</feedback>",
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ describe("processUserContentMentions", () => {
|
|||
content: [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Array task</task>",
|
||||
text: "<feedback>Array task</feedback>",
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
|
|
@ -237,7 +237,7 @@ describe("processUserContentMentions", () => {
|
|||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "parsed: <task>Array task</task>",
|
||||
text: "parsed: <feedback>Array task</feedback>",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
|
|
@ -251,7 +251,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>First task</task>",
|
||||
text: "<feedback>First task</feedback>",
|
||||
},
|
||||
{
|
||||
type: "image" as const,
|
||||
|
|
@ -280,7 +280,7 @@ describe("processUserContentMentions", () => {
|
|||
expect(result).toHaveLength(3)
|
||||
expect(result[0]).toEqual({
|
||||
type: "text",
|
||||
text: "parsed: <task>First task</task>",
|
||||
text: "parsed: <feedback>First task</feedback>",
|
||||
})
|
||||
expect(result[1]).toEqual(userContent[1]) // Image block unchanged
|
||||
expect(result[2]).toEqual({
|
||||
|
|
@ -296,7 +296,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Test default</task>",
|
||||
text: "<feedback>Test default</feedback>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -308,7 +308,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Test default</task>",
|
||||
"<feedback>Test default</feedback>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
@ -324,7 +324,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Test explicit false</task>",
|
||||
text: "<feedback>Test explicit false</feedback>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Test explicit false</task>",
|
||||
"<feedback>Test explicit false</feedback>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export async function processUserContentMentions({
|
|||
// Process userContent array, which contains various block types:
|
||||
// TextBlockParam, ImageBlockParam, ToolUseBlockParam, and ToolResultBlockParam.
|
||||
// We need to apply parseMentions() to:
|
||||
// 1. All TextBlockParam's text (first user message with task)
|
||||
// 1. All TextBlockParam's text (first user message with feedback)
|
||||
// 2. ToolResultBlockParam's content/context text arrays if it contains
|
||||
// "<feedback>" (see formatToolDeniedFeedback, attemptCompletion,
|
||||
// executeCommand, and consecutiveMistakeCount >= 3) or "<answer>"
|
||||
|
|
@ -40,10 +40,7 @@ export async function processUserContentMentions({
|
|||
return Promise.all(
|
||||
userContent.map(async (block) => {
|
||||
const shouldProcessMentions = (text: string) =>
|
||||
text.includes("<task>") ||
|
||||
text.includes("<feedback>") ||
|
||||
text.includes("<answer>") ||
|
||||
text.includes("<user_message>")
|
||||
text.includes("<feedback>") || text.includes("<answer>") || text.includes("<user_message>")
|
||||
|
||||
if (block.type === "text") {
|
||||
if (shouldProcessMentions(block.text)) {
|
||||
|
|
|
|||
|
|
@ -1284,7 +1284,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
await this.initiateTaskLoop([
|
||||
{
|
||||
type: "text",
|
||||
text: `<task>\n${task}\n</task>`,
|
||||
text: `<feedback>\n${task}\n</feedback>`,
|
||||
},
|
||||
...imageBlocks,
|
||||
])
|
||||
|
|
|
|||
|
|
@ -895,7 +895,7 @@ describe("Cline", () => {
|
|||
} as const,
|
||||
{
|
||||
type: "text",
|
||||
text: "<task>Text with 'some/path' (see below for file content) in task tags</task>",
|
||||
text: "<feedback>Text with 'some/path' (see below for file content) in task tags</feedback>",
|
||||
} as const,
|
||||
{
|
||||
type: "tool_result",
|
||||
|
|
@ -934,7 +934,7 @@ describe("Cline", () => {
|
|||
// Text within task tags should be processed
|
||||
expect((processedContent[1] as Anthropic.TextBlockParam).text).toContain("processed:")
|
||||
expect((processedContent[1] as Anthropic.TextBlockParam).text).toContain(
|
||||
"<task>Text with 'some/path' (see below for file content) in task tags</task>",
|
||||
"<feedback>Text with 'some/path' (see below for file content) in task tags</feedback>",
|
||||
)
|
||||
|
||||
// Feedback tag content should be processed
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue