mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: preserve tool_use blocks in summary for parallel tool calls (#9714)
Co-authored-by: huajiwuyan <huajiwuyan@gmail.com>
This commit is contained in:
parent
af7470908d
commit
bf3e4d8f1f
2 changed files with 148 additions and 1 deletions
|
|
@ -828,6 +828,148 @@ describe("summarizeConversation", () => {
|
|||
expect(result.messages).toHaveLength(1 + 1 + N_MESSAGES_TO_KEEP) // first + summary + last 3
|
||||
expect(result.error).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should include user tool_result message in summarize request when preserving tool_use blocks", async () => {
|
||||
const toolUseBlock = {
|
||||
type: "tool_use" as const,
|
||||
id: "toolu_history_fix",
|
||||
name: "read_file",
|
||||
input: { path: "sample.txt" },
|
||||
}
|
||||
const toolResultBlock = {
|
||||
type: "tool_result" as const,
|
||||
tool_use_id: "toolu_history_fix",
|
||||
content: "file contents",
|
||||
}
|
||||
|
||||
const messages: ApiMessage[] = [
|
||||
{ role: "user", content: "Hello", ts: 1 },
|
||||
{ role: "assistant", content: "Let me help", ts: 2 },
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "text" as const, text: "Running tool..." }, toolUseBlock],
|
||||
ts: 3,
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: [toolResultBlock, { type: "text" as const, text: "Thanks" }],
|
||||
ts: 4,
|
||||
},
|
||||
{ role: "assistant", content: "Anything else?", ts: 5 },
|
||||
{ role: "user", content: "Nope", ts: 6 },
|
||||
]
|
||||
|
||||
let capturedRequestMessages: any[] | undefined
|
||||
const customStream = (async function* () {
|
||||
yield { type: "text" as const, text: "Summary of conversation" }
|
||||
yield { type: "usage" as const, totalCost: 0.05, outputTokens: 100 }
|
||||
})()
|
||||
|
||||
mockApiHandler.createMessage = vi.fn().mockImplementation((_prompt, requestMessagesParam) => {
|
||||
capturedRequestMessages = requestMessagesParam
|
||||
return customStream
|
||||
}) as any
|
||||
|
||||
const result = await summarizeConversation(
|
||||
messages,
|
||||
mockApiHandler,
|
||||
defaultSystemPrompt,
|
||||
taskId,
|
||||
DEFAULT_PREV_CONTEXT_TOKENS,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
)
|
||||
|
||||
expect(result.error).toBeUndefined()
|
||||
expect(capturedRequestMessages).toBeDefined()
|
||||
|
||||
const requestMessages = capturedRequestMessages!
|
||||
expect(requestMessages[requestMessages.length - 1]).toEqual({
|
||||
role: "user",
|
||||
content: "Summarize the conversation so far, as described in the prompt instructions.",
|
||||
})
|
||||
|
||||
const historyMessages = requestMessages.slice(0, -1)
|
||||
expect(historyMessages.length).toBeGreaterThanOrEqual(2)
|
||||
|
||||
const assistantMessage = historyMessages[historyMessages.length - 2]
|
||||
const userMessage = historyMessages[historyMessages.length - 1]
|
||||
|
||||
expect(assistantMessage.role).toBe("assistant")
|
||||
expect(Array.isArray(assistantMessage.content)).toBe(true)
|
||||
expect(
|
||||
(assistantMessage.content as any[]).some(
|
||||
(block) => block.type === "tool_use" && block.id === toolUseBlock.id,
|
||||
),
|
||||
).toBe(true)
|
||||
|
||||
expect(userMessage.role).toBe("user")
|
||||
expect(Array.isArray(userMessage.content)).toBe(true)
|
||||
expect(
|
||||
(userMessage.content as any[]).some(
|
||||
(block) => block.type === "tool_result" && block.tool_use_id === toolUseBlock.id,
|
||||
),
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it("should append multiple tool_use blocks for parallel tool calls", async () => {
|
||||
const toolUseBlockA = {
|
||||
type: "tool_use" as const,
|
||||
id: "toolu_parallel_1",
|
||||
name: "search",
|
||||
input: { query: "foo" },
|
||||
}
|
||||
const toolUseBlockB = {
|
||||
type: "tool_use" as const,
|
||||
id: "toolu_parallel_2",
|
||||
name: "search",
|
||||
input: { query: "bar" },
|
||||
}
|
||||
|
||||
const messages: ApiMessage[] = [
|
||||
{ role: "user", content: "Start", ts: 1 },
|
||||
{ role: "assistant", content: "Working...", ts: 2 },
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "text" as const, text: "Launching parallel tools" }, toolUseBlockA, toolUseBlockB],
|
||||
ts: 3,
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "tool_result" as const, tool_use_id: "toolu_parallel_1", content: "result A" },
|
||||
{ type: "tool_result" as const, tool_use_id: "toolu_parallel_2", content: "result B" },
|
||||
{ type: "text" as const, text: "Continue" },
|
||||
],
|
||||
ts: 4,
|
||||
},
|
||||
{ role: "assistant", content: "Processing results", ts: 5 },
|
||||
{ role: "user", content: "Thanks", ts: 6 },
|
||||
]
|
||||
|
||||
const result = await summarizeConversation(
|
||||
messages,
|
||||
mockApiHandler,
|
||||
defaultSystemPrompt,
|
||||
taskId,
|
||||
DEFAULT_PREV_CONTEXT_TOKENS,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
)
|
||||
|
||||
const summaryMessage = result.messages[1]
|
||||
expect(Array.isArray(summaryMessage.content)).toBe(true)
|
||||
const summaryContent = summaryMessage.content as any[]
|
||||
expect(summaryContent[0]).toEqual({ type: "text", text: "This is a summary" })
|
||||
|
||||
const preservedToolUses = summaryContent.filter((block) => block.type === "tool_use")
|
||||
expect(preservedToolUses).toHaveLength(2)
|
||||
expect(preservedToolUses.map((block) => block.id)).toEqual(["toolu_parallel_1", "toolu_parallel_2"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("summarizeConversation with custom settings", () => {
|
||||
|
|
|
|||
|
|
@ -172,8 +172,13 @@ export async function summarizeConversation(
|
|||
? getKeepMessagesWithToolBlocks(messages, N_MESSAGES_TO_KEEP)
|
||||
: { keepMessages: messages.slice(-N_MESSAGES_TO_KEEP), toolUseBlocksToPreserve: [] }
|
||||
|
||||
const keepStartIndex = Math.max(messages.length - N_MESSAGES_TO_KEEP, 0)
|
||||
const includeFirstKeptMessageInSummary = toolUseBlocksToPreserve.length > 0
|
||||
const summarySliceEnd = includeFirstKeptMessageInSummary ? keepStartIndex + 1 : keepStartIndex
|
||||
const messagesBeforeKeep = summarySliceEnd > 0 ? messages.slice(0, summarySliceEnd) : []
|
||||
|
||||
// Get messages to summarize, including the first message and excluding the last N messages
|
||||
const messagesToSummarize = getMessagesSinceLastSummary(messages.slice(0, -N_MESSAGES_TO_KEEP))
|
||||
const messagesToSummarize = getMessagesSinceLastSummary(messagesBeforeKeep)
|
||||
|
||||
if (messagesToSummarize.length <= 1) {
|
||||
const error =
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue