mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-10 22:41:14 +00:00
refactor: unify user content tags to <user_message> (#10723)
Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
parent
ea62173792
commit
0f08867656
10 changed files with 44 additions and 78 deletions
|
|
@ -34,7 +34,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Read file with limit</task>",
|
||||
text: "<user_message>Read file with limit</user_message>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Read file with limit</task>",
|
||||
"<user_message>Read file with limit</user_message>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
@ -64,7 +64,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Read file without limit</task>",
|
||||
text: "<user_message>Read file without limit</user_message>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Read file without limit</task>",
|
||||
"<user_message>Read file without limit</user_message>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
@ -93,7 +93,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Read unlimited lines</task>",
|
||||
text: "<user_message>Read unlimited lines</user_message>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Read unlimited lines</task>",
|
||||
"<user_message>Read unlimited lines</user_message>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
@ -121,11 +121,11 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
describe("content processing", () => {
|
||||
it("should process text blocks with <task> tags", async () => {
|
||||
it("should process text blocks with <user_message> tags", async () => {
|
||||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Do something</task>",
|
||||
text: "<user_message>Do something</user_message>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -139,35 +139,12 @@ describe("processUserContentMentions", () => {
|
|||
expect(parseMentions).toHaveBeenCalled()
|
||||
expect(result.content[0]).toEqual({
|
||||
type: "text",
|
||||
text: "parsed: <task>Do something</task>",
|
||||
text: "parsed: <user_message>Do something</user_message>",
|
||||
})
|
||||
expect(result.mode).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should process text blocks with <feedback> tags", async () => {
|
||||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<feedback>Fix this issue</feedback>",
|
||||
},
|
||||
]
|
||||
|
||||
const result = await processUserContentMentions({
|
||||
userContent,
|
||||
cwd: "/test",
|
||||
urlContentFetcher: mockUrlContentFetcher,
|
||||
fileContextTracker: mockFileContextTracker,
|
||||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalled()
|
||||
expect(result.content[0]).toEqual({
|
||||
type: "text",
|
||||
text: "parsed: <feedback>Fix this issue</feedback>",
|
||||
})
|
||||
expect(result.mode).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should not process text blocks without task or feedback tags", async () => {
|
||||
it("should not process text blocks without user_message tags", async () => {
|
||||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
|
|
@ -192,7 +169,7 @@ describe("processUserContentMentions", () => {
|
|||
{
|
||||
type: "tool_result" as const,
|
||||
tool_use_id: "123",
|
||||
content: "<feedback>Tool feedback</feedback>",
|
||||
content: "<user_message>Tool feedback</user_message>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -207,7 +184,7 @@ describe("processUserContentMentions", () => {
|
|||
expect(result.content[0]).toEqual({
|
||||
type: "tool_result",
|
||||
tool_use_id: "123",
|
||||
content: "parsed: <feedback>Tool feedback</feedback>",
|
||||
content: "parsed: <user_message>Tool feedback</user_message>",
|
||||
})
|
||||
expect(result.mode).toBeUndefined()
|
||||
})
|
||||
|
|
@ -220,7 +197,7 @@ describe("processUserContentMentions", () => {
|
|||
content: [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Array task</task>",
|
||||
text: "<user_message>Array task</user_message>",
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
|
|
@ -244,7 +221,7 @@ describe("processUserContentMentions", () => {
|
|||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "parsed: <task>Array task</task>",
|
||||
text: "parsed: <user_message>Array task</user_message>",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
|
|
@ -259,7 +236,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>First task</task>",
|
||||
text: "<user_message>First task</user_message>",
|
||||
},
|
||||
{
|
||||
type: "image" as const,
|
||||
|
|
@ -272,7 +249,7 @@ describe("processUserContentMentions", () => {
|
|||
{
|
||||
type: "tool_result" as const,
|
||||
tool_use_id: "456",
|
||||
content: "<feedback>Feedback</feedback>",
|
||||
content: "<user_message>Feedback</user_message>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -288,13 +265,13 @@ describe("processUserContentMentions", () => {
|
|||
expect(result.content).toHaveLength(3)
|
||||
expect(result.content[0]).toEqual({
|
||||
type: "text",
|
||||
text: "parsed: <task>First task</task>",
|
||||
text: "parsed: <user_message>First task</user_message>",
|
||||
})
|
||||
expect(result.content[1]).toEqual(userContent[1]) // Image block unchanged
|
||||
expect(result.content[2]).toEqual({
|
||||
type: "tool_result",
|
||||
tool_use_id: "456",
|
||||
content: "parsed: <feedback>Feedback</feedback>",
|
||||
content: "parsed: <user_message>Feedback</user_message>",
|
||||
})
|
||||
expect(result.mode).toBeUndefined()
|
||||
})
|
||||
|
|
@ -305,7 +282,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Test default</task>",
|
||||
text: "<user_message>Test default</user_message>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -317,7 +294,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Test default</task>",
|
||||
"<user_message>Test default</user_message>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
@ -333,7 +310,7 @@ describe("processUserContentMentions", () => {
|
|||
const userContent = [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "<task>Test explicit false</task>",
|
||||
text: "<user_message>Test explicit false</user_message>",
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -346,7 +323,7 @@ describe("processUserContentMentions", () => {
|
|||
})
|
||||
|
||||
expect(parseMentions).toHaveBeenCalledWith(
|
||||
"<task>Test explicit false</task>",
|
||||
"<user_message>Test explicit false</user_message>",
|
||||
"/test",
|
||||
mockUrlContentFetcher,
|
||||
mockFileContextTracker,
|
||||
|
|
|
|||
|
|
@ -38,20 +38,13 @@ 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)
|
||||
// 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).
|
||||
// "<user_message>" - we place all user generated content in this tag
|
||||
// so it can effectively be used as a marker for when we should parse mentions.
|
||||
const content = await Promise.all(
|
||||
userContent.map(async (block) => {
|
||||
const shouldProcessMentions = (text: string) =>
|
||||
text.includes("<task>") ||
|
||||
text.includes("<feedback>") ||
|
||||
text.includes("<answer>") ||
|
||||
text.includes("<user_message>")
|
||||
const shouldProcessMentions = (text: string) => text.includes("<user_message>")
|
||||
|
||||
if (block.type === "text") {
|
||||
if (shouldProcessMentions(block.text)) {
|
||||
|
|
|
|||
|
|
@ -20,22 +20,20 @@ export const formatResponse = {
|
|||
if (isNativeProtocol(protocol ?? TOOL_PROTOCOL.XML)) {
|
||||
return JSON.stringify({
|
||||
status: "denied",
|
||||
message: "The user denied this operation and provided the following feedback",
|
||||
feedback: feedback,
|
||||
})
|
||||
}
|
||||
return `The user denied this operation and provided the following feedback:\n<feedback>\n${feedback}\n</feedback>`
|
||||
return `The user denied this operation and responded with the message:\n<user_message>\n${feedback}\n</user_message>`
|
||||
},
|
||||
|
||||
toolApprovedWithFeedback: (feedback?: string, protocol?: ToolProtocol) => {
|
||||
if (isNativeProtocol(protocol ?? TOOL_PROTOCOL.XML)) {
|
||||
return JSON.stringify({
|
||||
status: "approved",
|
||||
message: "The user approved this operation and provided the following context",
|
||||
feedback: feedback,
|
||||
})
|
||||
}
|
||||
return `The user approved this operation and provided the following context:\n<feedback>\n${feedback}\n</feedback>`
|
||||
return `The user approved this operation and responded with the message:\n<user_message>\n${feedback}\n</user_message>`
|
||||
},
|
||||
|
||||
toolError: (error?: string, protocol?: ToolProtocol) => {
|
||||
|
|
@ -81,11 +79,10 @@ Otherwise, if you have not completed the task and do not need additional informa
|
|||
if (isNativeProtocol(protocol ?? TOOL_PROTOCOL.XML)) {
|
||||
return JSON.stringify({
|
||||
status: "guidance",
|
||||
message: "You seem to be having trouble proceeding",
|
||||
feedback: feedback,
|
||||
})
|
||||
}
|
||||
return `You seem to be having trouble proceeding. The user has provided the following feedback to help guide you:\n<feedback>\n${feedback}\n</feedback>`
|
||||
return `You seem to be having trouble proceeding. The user has provided the following feedback to help guide you:\n<user_message>\n${feedback}\n</user_message>`
|
||||
},
|
||||
|
||||
missingToolParameterError: (paramName: string, protocol?: ToolProtocol) => {
|
||||
|
|
|
|||
|
|
@ -1918,7 +1918,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
await this.initiateTaskLoop([
|
||||
{
|
||||
type: "text",
|
||||
text: `<task>\n${task}\n</task>`,
|
||||
text: `<user_message>\n${task}\n</user_message>`,
|
||||
},
|
||||
...imageBlocks,
|
||||
]).catch((error) => {
|
||||
|
|
@ -2197,7 +2197,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
if (responseText) {
|
||||
newUserContent.push({
|
||||
type: "text",
|
||||
text: `\n\nNew instructions for task continuation:\n<user_message>\n${responseText}\n</user_message>`,
|
||||
text: `<user_message>\n${responseText}\n</user_message>`,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -883,7 +883,7 @@ describe("Cline", () => {
|
|||
})
|
||||
|
||||
describe("processUserContentMentions", () => {
|
||||
it("should process mentions in task and feedback tags", async () => {
|
||||
it("should process mentions in user_message tags", async () => {
|
||||
const [cline, task] = Task.create({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
|
|
@ -897,7 +897,7 @@ describe("Cline", () => {
|
|||
} as const,
|
||||
{
|
||||
type: "text",
|
||||
text: "<task>Text with 'some/path' (see below for file content) in task tags</task>",
|
||||
text: "<user_message>Text with 'some/path' (see below for file content) in user_message tags</user_message>",
|
||||
} as const,
|
||||
{
|
||||
type: "tool_result",
|
||||
|
|
@ -905,7 +905,7 @@ describe("Cline", () => {
|
|||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "<feedback>Check 'some/path' (see below for file content)</feedback>",
|
||||
text: "<user_message>Check 'some/path' (see below for file content)</user_message>",
|
||||
},
|
||||
],
|
||||
} as Anthropic.ToolResultBlockParam,
|
||||
|
|
@ -933,18 +933,18 @@ describe("Cline", () => {
|
|||
"Regular text with 'some/path' (see below for file content)",
|
||||
)
|
||||
|
||||
// Text within task tags should be processed
|
||||
// Text within user_message 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>",
|
||||
"<user_message>Text with 'some/path' (see below for file content) in user_message tags</user_message>",
|
||||
)
|
||||
|
||||
// Feedback tag content should be processed
|
||||
// user_message tag content should be processed
|
||||
const toolResult1 = processedContent[2] as Anthropic.ToolResultBlockParam
|
||||
const content1 = Array.isArray(toolResult1.content) ? toolResult1.content[0] : toolResult1.content
|
||||
expect((content1 as Anthropic.TextBlockParam).text).toContain("processed:")
|
||||
expect((content1 as Anthropic.TextBlockParam).text).toContain(
|
||||
"<feedback>Check 'some/path' (see below for file content)</feedback>",
|
||||
"<user_message>Check 'some/path' (see below for file content)</user_message>",
|
||||
)
|
||||
|
||||
// Regular tool result should not be processed
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ describe("Task Tool History Handling", () => {
|
|||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
text: "Another message with <task> tags",
|
||||
text: "Another message with <user_message> tags",
|
||||
},
|
||||
{
|
||||
type: "tool_result" as const,
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ export class AskFollowupQuestionTool extends BaseTool<"ask_followup_question"> {
|
|||
task.consecutiveMistakeCount = 0
|
||||
const { text, images } = await task.ask("followup", JSON.stringify(follow_up_json), false)
|
||||
await task.say("user_feedback", text ?? "", images)
|
||||
pushToolResult(formatResponse.toolResult(`<answer>\n${text}\n</answer>`, images))
|
||||
pushToolResult(formatResponse.toolResult(`<user_message>\n${text}\n</user_message>`, images))
|
||||
} catch (error) {
|
||||
await handleError("asking question", error as Error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ export class AttemptCompletionTool extends BaseTool<"attempt_completion"> {
|
|||
// User provided feedback - push tool result to continue the conversation
|
||||
await task.say("user_feedback", text ?? "", images)
|
||||
|
||||
const feedbackText = `The user has provided feedback on the results. Consider their input to continue the task, and then attempt completion again.\n<feedback>\n${text}\n</feedback>`
|
||||
const feedbackText = `<user_message>\n${text}\n</user_message>`
|
||||
pushToolResult(formatResponse.toolResult(feedbackText, images))
|
||||
} catch (error) {
|
||||
await handleError("inspecting site", error as Error)
|
||||
|
|
|
|||
|
|
@ -340,8 +340,7 @@ export async function executeCommandInTerminal(
|
|||
[
|
||||
`Command is still running in terminal from '${terminal.getCurrentWorkingDirectory().toPosix()}'.`,
|
||||
result.length > 0 ? `Here's the output so far:\n${result}\n` : "\n",
|
||||
`The user provided the following feedback:`,
|
||||
`<feedback>\n${text}\n</feedback>`,
|
||||
`<user_message>\n${text}\n</user_message>`,
|
||||
].join("\n"),
|
||||
images,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -95,11 +95,11 @@ vi.mock("../../prompts/responses", () => ({
|
|||
toolDenied: vi.fn(() => "The user denied this operation."),
|
||||
toolDeniedWithFeedback: vi.fn(
|
||||
(feedback?: string) =>
|
||||
`The user denied this operation and provided the following feedback:\n<feedback>\n${feedback}\n</feedback>`,
|
||||
`The user denied this operation and responded with the message:\n<user_message>\n${feedback}\n</user_message>`,
|
||||
),
|
||||
toolApprovedWithFeedback: vi.fn(
|
||||
(feedback?: string) =>
|
||||
`The user approved this operation and provided the following context:\n<feedback>\n${feedback}\n</feedback>`,
|
||||
`The user approved this operation and responded with the message:\n<user_message>\n${feedback}\n</user_message>`,
|
||||
),
|
||||
rooIgnoreError: vi.fn(
|
||||
(path: string) =>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue