mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-11 22:51:26 +00:00
feat: inject queued messages into next API call for mid-task guidance
This commit is contained in:
parent
193053110b
commit
69db1b2f26
2 changed files with 138 additions and 0 deletions
|
|
@ -2639,6 +2639,31 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
// Add environment details as its own text block, separate from tool
|
||||
// results.
|
||||
let finalUserContent = [...contentWithoutEnvDetails, { type: "text" as const, text: environmentDetails }]
|
||||
|
||||
// Inject any queued user messages into this API call.
|
||||
// This allows users to provide mid-task guidance that the agent
|
||||
// picks up immediately on the next API request, rather than
|
||||
// waiting for the current turn to fully complete.
|
||||
if (!this.messageQueueService.isEmpty()) {
|
||||
const queuedTexts: string[] = []
|
||||
|
||||
while (!this.messageQueueService.isEmpty()) {
|
||||
const msg = this.messageQueueService.dequeueMessage()
|
||||
|
||||
if (msg?.text) {
|
||||
queuedTexts.push(msg.text)
|
||||
}
|
||||
}
|
||||
|
||||
if (queuedTexts.length > 0) {
|
||||
const injection =
|
||||
"\n[USER_MID_TASK_MESSAGE]\nThe user has sent the following message(s) while you were working. " +
|
||||
"Please acknowledge and incorporate this feedback into your current task:\n" +
|
||||
queuedTexts.join("\n") +
|
||||
"\n[/USER_MID_TASK_MESSAGE]"
|
||||
finalUserContent.push({ type: "text" as const, text: injection })
|
||||
}
|
||||
}
|
||||
// Only add user message to conversation history if:
|
||||
// 1. This is the first attempt (retryAttempt === 0), AND
|
||||
// 2. The original userContent was not empty (empty signals delegation resume where
|
||||
|
|
|
|||
113
src/core/task/__tests__/mid-task-message-injection.spec.ts
Normal file
113
src/core/task/__tests__/mid-task-message-injection.spec.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import { MessageQueueService } from "../../message-queue/MessageQueueService"
|
||||
|
||||
/**
|
||||
* Tests for the mid-task message injection feature.
|
||||
*
|
||||
* When a user queues messages while the agent is working,
|
||||
* they should be drained and injected into the next API call's
|
||||
* user content as [USER_MID_TASK_MESSAGE] blocks.
|
||||
*
|
||||
* This test validates the drain-and-inject logic in isolation,
|
||||
* using the same MessageQueueService that Task.ts uses.
|
||||
*/
|
||||
describe("Mid-task message injection", () => {
|
||||
let queue: MessageQueueService
|
||||
|
||||
beforeEach(() => {
|
||||
queue = new MessageQueueService()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
queue.dispose()
|
||||
})
|
||||
|
||||
/**
|
||||
* Simulates the drain-and-inject logic from Task.ts L2647-2666.
|
||||
* Returns the injection text block if any messages were queued,
|
||||
* or undefined if the queue was empty.
|
||||
*/
|
||||
function drainAndBuildInjection(mqs: MessageQueueService): string | undefined {
|
||||
if (mqs.isEmpty()) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const queuedTexts: string[] = []
|
||||
|
||||
while (!mqs.isEmpty()) {
|
||||
const msg = mqs.dequeueMessage()
|
||||
|
||||
if (msg?.text) {
|
||||
queuedTexts.push(msg.text)
|
||||
}
|
||||
}
|
||||
|
||||
if (queuedTexts.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return (
|
||||
"\n[USER_MID_TASK_MESSAGE]\nThe user has sent the following message(s) while you were working. " +
|
||||
"Please acknowledge and incorporate this feedback into your current task:\n" +
|
||||
queuedTexts.join("\n") +
|
||||
"\n[/USER_MID_TASK_MESSAGE]"
|
||||
)
|
||||
}
|
||||
|
||||
it("returns undefined when queue is empty", () => {
|
||||
const result = drainAndBuildInjection(queue)
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it("injects a single queued message with correct tags", () => {
|
||||
queue.addMessage("use TypeScript instead of JavaScript")
|
||||
const result = drainAndBuildInjection(queue)
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result).toContain("[USER_MID_TASK_MESSAGE]")
|
||||
expect(result).toContain("use TypeScript instead of JavaScript")
|
||||
expect(result).toContain("[/USER_MID_TASK_MESSAGE]")
|
||||
})
|
||||
|
||||
it("injects multiple queued messages in order", () => {
|
||||
queue.addMessage("first advice")
|
||||
queue.addMessage("second advice")
|
||||
queue.addMessage("third advice")
|
||||
const result = drainAndBuildInjection(queue)
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result).toContain("first advice")
|
||||
expect(result).toContain("second advice")
|
||||
expect(result).toContain("third advice")
|
||||
|
||||
// Verify order: first should appear before second
|
||||
const firstIndex = result!.indexOf("first advice")
|
||||
const secondIndex = result!.indexOf("second advice")
|
||||
const thirdIndex = result!.indexOf("third advice")
|
||||
expect(firstIndex).toBeLessThan(secondIndex)
|
||||
expect(secondIndex).toBeLessThan(thirdIndex)
|
||||
})
|
||||
|
||||
it("drains the queue completely after injection", () => {
|
||||
queue.addMessage("some advice")
|
||||
queue.addMessage("more advice")
|
||||
|
||||
drainAndBuildInjection(queue)
|
||||
|
||||
expect(queue.isEmpty()).toBe(true)
|
||||
// Second drain should return undefined
|
||||
expect(drainAndBuildInjection(queue)).toBeUndefined()
|
||||
})
|
||||
|
||||
it("does not interfere with messages queued after drain", () => {
|
||||
queue.addMessage("before drain")
|
||||
drainAndBuildInjection(queue)
|
||||
|
||||
// Simulate new message arriving after drain (during API call)
|
||||
queue.addMessage("after drain")
|
||||
expect(queue.isEmpty()).toBe(false)
|
||||
|
||||
const result = drainAndBuildInjection(queue)
|
||||
expect(result).toContain("after drain")
|
||||
expect(result).not.toContain("before drain")
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Reference in a new issue