Add active-turn steering (#3394)

* feat(agents): add active-turn steering

Let users choose whether an immediate prompt interrupts or joins the active turn. The daemon owns exact-turn admission, provider delivery, safe fallback, and canonical timeline identity while queueing remains client-side.

* fix(agents): stabilize steering history and replay QA

* fix(agents): preserve steering timeline order

* fix(agents): reconcile resumed provider history

* fix(agents): serialize steering with cancellation

* test(agents): prove Claude multi-tool steering

* test(agents): force explicit history hydration

* fix(agents): flush output before steer admission
This commit is contained in:
Mohamed Boudra
2026-08-16 13:58:40 +02:00
committed by GitHub
parent 16120ebff1
commit 42245d139a
69 changed files with 5203 additions and 269 deletions
+33
View File
@@ -184,6 +184,39 @@ describe("submitAgentInput", () => {
expect(clearDraft).not.toHaveBeenCalled();
});
it("restores a steered active-turn draft after an ambiguous immediate-send error", async () => {
const error = new Error("connection lost after delivery");
const setUserInput = vi.fn();
const setAttachments = vi.fn();
const setSendError = vi.fn();
const setIsProcessing = vi.fn();
await expect(
submitAgentInput({
message: " steer this turn ",
attachments: [{ id: "img-1" }],
forceSend: true,
isAgentRunning: true,
canSubmit: true,
queueMessage: vi.fn(),
submitMessage: async () => {
throw error;
},
clearDraft: vi.fn(),
setUserInput,
setAttachments,
setSendError,
setIsProcessing,
}),
).resolves.toBe("failed");
expect(setUserInput).toHaveBeenNthCalledWith(1, "");
expect(setUserInput).toHaveBeenNthCalledWith(2, "steer this turn");
expect(setAttachments).toHaveBeenNthCalledWith(1, []);
expect(setAttachments).toHaveBeenNthCalledWith(2, [{ id: "img-1" }]);
expect(setSendError).toHaveBeenLastCalledWith("connection lost after delivery");
});
it("submits when empty submit is explicitly allowed", async () => {
const queueMessage = vi.fn();
const submitMessage = vi.fn(async () => {});