diff --git a/packages/app/src/components/prompt-input/submit.test.ts b/packages/app/src/components/prompt-input/submit.test.ts index b1b289a27658..daffc139aca9 100644 --- a/packages/app/src/components/prompt-input/submit.test.ts +++ b/packages/app/src/components/prompt-input/submit.test.ts @@ -1,7 +1,8 @@ import { beforeAll, beforeEach, describe, expect, mock, test } from "bun:test" -import type { Prompt } from "@/context/prompt" +import type { ContextItem, Prompt } from "@/context/prompt" let createPromptSubmit: typeof import("./submit").createPromptSubmit +type FollowupDraft = import("./submit").FollowupDraft const createdClients: string[] = [] const createdSessions: string[] = [] @@ -20,10 +21,13 @@ const storedSessions: Record> = {} const promoted: Array<{ directory: string; sessionID: string }> = [] const sentShell: string[] = [] const syncedDirectories: string[] = [] +const removedContextKeys: string[] = [] let params: { id?: string } = {} let selected = "/repo/worktree-a" let variant: string | undefined +let promptContextItems: Array = [] +let promptResetCount = 0 const promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }] @@ -106,12 +110,17 @@ beforeAll(async () => { mock.module("@/context/prompt", () => ({ usePrompt: () => ({ current: () => promptValue, - reset: () => undefined, + reset: () => { + promptResetCount += 1 + }, set: () => undefined, context: { add: () => undefined, - remove: () => undefined, - items: () => [], + remove: (key: string) => { + removedContextKeys.push(key) + promptContextItems = promptContextItems.filter((item) => item.key !== key) + }, + items: () => promptContextItems, }, }), })) @@ -211,8 +220,11 @@ beforeEach(() => { params = {} sentShell.length = 0 syncedDirectories.length = 0 + removedContextKeys.length = 0 selected = "/repo/worktree-a" variant = undefined + promptContextItems = [] + promptResetCount = 0 for (const key of Object.keys(storedSessions)) delete storedSessions[key] }) @@ -343,3 +355,81 @@ describe("prompt submit worktree selection", () => { expect(optimisticSeeded).toEqual([true]) }) }) + +describe("queued followups", () => { + test("queues followup drafts instead of sending immediately", async () => { + params = { id: "session-1" } + variant = "high" + promptContextItems = [ + { + key: "context-1", + type: "file", + path: "src/index.ts", + selection: undefined, + comment: "Check this", + commentID: "comment-1", + commentOrigin: "file", + preview: "const value = 1", + }, + ] + + const queued: FollowupDraft[] = [] + const modes: Array<"normal" | "shell"> = [] + const popovers: Array<"at" | "slash" | null> = [] + let submitCalls = 0 + + const submit = createPromptSubmit({ + info: () => ({ id: "session-1" }), + imageAttachments: () => [], + commentCount: () => 1, + autoAccept: () => false, + mode: () => "normal", + working: () => true, + editor: () => undefined, + queueScroll: () => undefined, + promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0), + addToHistory: () => undefined, + resetHistoryNavigation: () => undefined, + setMode: (mode) => modes.push(mode), + setPopover: (popover) => popovers.push(popover), + shouldQueue: () => true, + onQueue: (draft) => queued.push(draft), + onSubmit: () => { + submitCalls += 1 + }, + }) + + const event = { preventDefault: () => undefined } as unknown as Event + + await submit.handleSubmit(event) + + expect(queued).toHaveLength(1) + expect(queued[0]).toMatchObject({ + sessionID: "session-1", + sessionDirectory: "/repo/main", + prompt: promptValue, + context: [ + { + key: "context-1", + type: "file", + path: "src/index.ts", + comment: "Check this", + commentID: "comment-1", + commentOrigin: "file", + preview: "const value = 1", + }, + ], + agent: "agent", + model: { providerID: "provider", modelID: "model" }, + variant: "high", + }) + expect(promptResetCount).toBe(1) + expect(promptContextItems).toEqual([]) + expect(removedContextKeys).toEqual(["context-1"]) + expect(modes).toEqual(["normal"]) + expect(popovers).toEqual([null]) + expect(submitCalls).toBe(0) + expect(optimistic).toEqual([]) + expect(createdSessions).toEqual([]) + }) +}) diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index b94f42897afa..aa3af6b1c187 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -258,6 +258,11 @@ export const SettingsGeneral: Component = () => { { value: "dark", label: language.t("theme.scheme.dark") }, ]) + const followupOptions = createMemo((): { value: "queue" | "steer"; label: string }[] => [ + { value: "queue", label: language.t("settings.general.row.followup.option.queue") }, + { value: "steer", label: language.t("settings.general.row.followup.option.steer") }, + ]) + const languageOptions = createMemo(() => language.locales.map((locale) => ({ value: locale, @@ -388,6 +393,24 @@ export const SettingsGeneral: Component = () => { + +