Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6af78e9dd |
@@ -323,6 +323,26 @@ describe("prompt and cancel", () => {
|
|||||||
await waitFor(() => expect(sendStructuredPrompt).toHaveBeenCalledWith("s1", "next up"));
|
await waitFor(() => expect(sendStructuredPrompt).toHaveBeenCalledWith("s1", "next up"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("concatenates multiple queued messages into a single prompt", async () => {
|
||||||
|
const { socket } = mount();
|
||||||
|
snapshot(socket, [], busy);
|
||||||
|
const input = document.querySelector<HTMLTextAreaElement>(".structured-input")!;
|
||||||
|
const form = document.querySelector("form.structured-composer")!;
|
||||||
|
|
||||||
|
fireEvent.change(input, { target: { value: "first" } });
|
||||||
|
fireEvent.submit(form);
|
||||||
|
fireEvent.change(input, { target: { value: "second" } });
|
||||||
|
fireEvent.submit(form);
|
||||||
|
|
||||||
|
expect(sendStructuredPrompt).not.toHaveBeenCalled();
|
||||||
|
const queued = document.querySelectorAll(".st-row-queued");
|
||||||
|
expect(queued).toHaveLength(2);
|
||||||
|
|
||||||
|
socket.emit({ type: "reduced_state", state: idle });
|
||||||
|
await waitFor(() => expect(sendStructuredPrompt).toHaveBeenCalledWith("s1", "first\n\nsecond"));
|
||||||
|
expect(sendStructuredPrompt).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
it("hands a failed send's draft back to the operator", async () => {
|
it("hands a failed send's draft back to the operator", async () => {
|
||||||
vi.mocked(sendStructuredPrompt).mockRejectedValueOnce(new Error("boom"));
|
vi.mocked(sendStructuredPrompt).mockRejectedValueOnce(new Error("boom"));
|
||||||
const { socket } = mount();
|
const { socket } = mount();
|
||||||
|
|||||||
@@ -251,14 +251,16 @@ export const StructuredPane = forwardRef<StructuredPaneHandle, StructuredPanePro
|
|||||||
[sessionId, socketGeneration, session],
|
[sessionId, socketGeneration, session],
|
||||||
);
|
);
|
||||||
|
|
||||||
// A queued message goes out as soon as the projected turn is idle — the
|
// Queued messages are concatenated into a single prompt so the agent sees
|
||||||
// daemon answers a second prompt `409 turn_in_flight`, so the queue is
|
// one user turn instead of N back-to-back turns. The daemon rejects a
|
||||||
// client-local (docs/STRUCTURED-VIEW.md).
|
// second prompt while a turn is in flight (`409 turn_in_flight`), so the
|
||||||
|
// queue is client-local (docs/STRUCTURED-VIEW.md).
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (active || promptPending.current || queue.length === 0) return;
|
if (active || promptPending.current || queue.length === 0) return;
|
||||||
const [next, ...rest] = queue;
|
const text = queue.map((q) => q.text).join("\n\n");
|
||||||
setQueue(rest);
|
const files = queue.flatMap((q) => q.attachments);
|
||||||
dispatchPrompt(next.text, next.attachments);
|
setQueue([]);
|
||||||
|
dispatchPrompt(text, files);
|
||||||
}, [active, queue, dispatchPrompt]);
|
}, [active, queue, dispatchPrompt]);
|
||||||
|
|
||||||
const submit = (text: string, files: File[]) => {
|
const submit = (text: string, files: File[]) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user