diff --git a/src/modules/workbench-shell/model/composer-commands.test.ts b/src/modules/workbench-shell/model/composer-commands.test.ts index 5b9a14fe..5ce79982 100644 --- a/src/modules/workbench-shell/model/composer-commands.test.ts +++ b/src/modules/workbench-shell/model/composer-commands.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from "vitest"; import type { PromptInputMessage } from "@/components/ai-elements/prompt-input"; -import type { RunMode } from "@/shared/types/api"; import { buildCommandEffectivePrompt, buildComposerCommandRegistry, @@ -10,8 +9,6 @@ import { parseSlashCommandInput, } from "@/modules/workbench-shell/model/composer-commands"; -const RUN_MODE: RunMode = "default"; - function createMessage(text: string): PromptInputMessage { return { text, @@ -22,7 +19,7 @@ function createMessage(text: string): PromptInputMessage { describe("buildComposerSubmission", () => { it("preserves plain multi-line Markdown exactly", () => { const text = " 1. First\n2. Second\n\n- Bullet\n```ts\nconst value = 1;\n```\n "; - const submission = buildComposerSubmission(createMessage(text), [], RUN_MODE); + const submission = buildComposerSubmission(createMessage(text), []); expect(submission).not.toBeNull(); expect(submission?.kind).toBe("plain"); @@ -31,7 +28,7 @@ describe("buildComposerSubmission", () => { }); it("rejects whitespace-only messages without attachments", () => { - const submission = buildComposerSubmission(createMessage(" \n\t "), [], RUN_MODE); + const submission = buildComposerSubmission(createMessage(" \n\t "), []); expect(submission).toBeNull(); }); @@ -39,7 +36,7 @@ describe("buildComposerSubmission", () => { it("parses slash commands from trimmed text while preserving the original display text", () => { const registry = buildComposerCommandRegistry([]); const text = " /init \n"; - const submission = buildComposerSubmission(createMessage(text), registry, RUN_MODE); + const submission = buildComposerSubmission(createMessage(text), registry); expect(submission).not.toBeNull(); expect(submission?.kind).toBe("command"); @@ -51,7 +48,7 @@ describe("buildComposerSubmission", () => { it("preserves multi-line /goal objectives as command arguments", () => { const registry = buildComposerCommandRegistry([]); const text = "/goal First goal line\nSecond goal line\n- checklist item"; - const submission = buildComposerSubmission(createMessage(text), registry, RUN_MODE); + const submission = buildComposerSubmission(createMessage(text), registry); expect(submission).not.toBeNull(); expect(submission?.kind).toBe("command"); diff --git a/src/modules/workbench-shell/model/composer-commands.ts b/src/modules/workbench-shell/model/composer-commands.ts index 0c1c7cd8..5e5a26f1 100644 --- a/src/modules/workbench-shell/model/composer-commands.ts +++ b/src/modules/workbench-shell/model/composer-commands.ts @@ -1,6 +1,6 @@ import type { PromptInputMessage } from "@/components/ai-elements/prompt-input"; import type { CommandEntry } from "@/modules/settings-center/model/types"; -import type { MessageAttachmentDto, RunMode } from "@/shared/types/api"; +import type { MessageAttachmentDto } from "@/shared/types/api"; export type ComposerReferencedFile = { name: string; @@ -139,7 +139,6 @@ export type ComposerSubmission = { attachments: MessageAttachmentDto[]; command?: ComposerCommandInvocation; metadata?: Record | null; - runMode?: RunMode; }; const BUILTIN_COMMANDS: ReadonlyArray = [ @@ -551,7 +550,6 @@ export function buildCommandEffectivePrompt( export function buildComposerSubmission( message: PromptInputMessage, registry: ReadonlyArray, - runMode?: RunMode, ): ComposerSubmission | null { const rawText = message.text ?? ""; const trimmedText = rawText.trim(); @@ -574,7 +572,6 @@ export function buildComposerSubmission( rawMessage: message, attachments, metadata: null, - runMode, }; } @@ -605,6 +602,5 @@ export function buildComposerSubmission( command: invocation, }, }, - runMode, }; } diff --git a/src/modules/workbench-shell/model/composer-store.test.ts b/src/modules/workbench-shell/model/composer-store.test.ts index d0b0ca5a..c0b805a4 100644 --- a/src/modules/workbench-shell/model/composer-store.test.ts +++ b/src/modules/workbench-shell/model/composer-store.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach } from "vitest"; import { composerStore, setNewThreadValue, - setNewThreadRunMode, setNewThreadReferencedFiles, setNewThreadAttachmentData, setDraft, @@ -25,13 +24,6 @@ describe("composerStore", () => { expect(composerStore.getState().newThreadValue).toBe("hello world"); }); - it("should set new thread run mode", () => { - setNewThreadRunMode("plan"); - expect(composerStore.getState().newThreadRunMode).toBe("plan"); - setNewThreadRunMode("default"); - expect(composerStore.getState().newThreadRunMode).toBe("default"); - }); - it("should clear new thread composer", () => { setNewThreadValue("some value"); setNewThreadReferencedFiles([{ name: "test.ts", path: "/test.ts", parentPath: "/" }]); diff --git a/src/modules/workbench-shell/model/composer-store.ts b/src/modules/workbench-shell/model/composer-store.ts index fea3cbed..c48adcd8 100644 --- a/src/modules/workbench-shell/model/composer-store.ts +++ b/src/modules/workbench-shell/model/composer-store.ts @@ -1,5 +1,4 @@ import { createStore, useStore as useStoreBase, shallowEqual } from "@/shared/lib/create-store"; -import type { RunMode } from "@/shared/types/api"; import type { ComposerReferencedFile } from "@/modules/workbench-shell/model/composer-commands"; // --------------------------------------------------------------------------- @@ -28,8 +27,6 @@ export interface ComposerStoreState { [key: string]: unknown; /** Input value for new-thread mode. */ newThreadValue: string; - /** Run mode for new threads (default / plan). */ - newThreadRunMode: RunMode; /** @file references for new-thread composer. */ newThreadReferencedFiles: ComposerReferencedFile[]; /** Serialized attachment data for new-thread composer. */ @@ -46,7 +43,6 @@ export interface ComposerStoreState { export const composerStore = createStore({ newThreadValue: "", - newThreadRunMode: "default", newThreadReferencedFiles: [], newThreadAttachmentData: [], drafts: {}, @@ -67,10 +63,6 @@ export function setNewThreadValue(value: string): void { composerStore.setState({ newThreadValue: value }); } -export function setNewThreadRunMode(mode: RunMode): void { - composerStore.setState({ newThreadRunMode: mode }); -} - export function setNewThreadReferencedFiles(files: ReadonlyArray): void { composerStore.setState({ newThreadReferencedFiles: files as ComposerReferencedFile[] }); } diff --git a/src/modules/workbench-shell/model/thread-store.test.ts b/src/modules/workbench-shell/model/thread-store.test.ts index 7980ec71..24e8f3c3 100644 --- a/src/modules/workbench-shell/model/thread-store.test.ts +++ b/src/modules/workbench-shell/model/thread-store.test.ts @@ -42,7 +42,6 @@ function makePendingRun(overrides?: Partial): PendingThreadRun effectivePrompt: "test prompt", attachments: [], metadata: null, - runMode: "default", threadId: "thread-1", ...overrides, }; diff --git a/src/modules/workbench-shell/model/workbench-actions.test.ts b/src/modules/workbench-shell/model/workbench-actions.test.ts index 5950c7a9..009ce0e8 100644 --- a/src/modules/workbench-shell/model/workbench-actions.test.ts +++ b/src/modules/workbench-shell/model/workbench-actions.test.ts @@ -387,7 +387,7 @@ describe("deleteThread", () => { threadStore.setState({ activeThreadId: null, workspaces: [makeWorkspace("ws-1", [thread])], - pendingRuns: { "thread-1": { id: "run-1", prompt: "test", runMode: "auto" } as any }, + pendingRuns: { "thread-1": { id: "run-1", prompt: "test" } as any }, }); await deleteThread("thread-1", { skipIpc: true }); @@ -461,7 +461,7 @@ describe("removeWorkspace", () => { threadStore.setState({ activeThreadId: null, workspaces: [ws1], - pendingRuns: { "thread-1": { id: "run-1", prompt: "test", runMode: "auto" } as any }, + pendingRuns: { "thread-1": { id: "run-1", prompt: "test" } as any }, }); await removeWorkspace(ws1 as any); @@ -583,7 +583,6 @@ describe("submitNewThread", () => { ): NewThreadSubmission { return { value: "test prompt", - runMode: "default", effectivePrompt: "test prompt", ...overrides, }; @@ -594,7 +593,6 @@ describe("submitNewThread", () => { workspaces: [], isNewThreadMode: true, }); - composerStore.setState({ newThreadRunMode: "default" }); settingsStore.setState({ activeAgentProfileId: "default-profile" }); await submitNewThread(makeSubmission({ value: "hello" })); @@ -626,7 +624,6 @@ describe("submitNewThread", () => { workspaces: [workspace], isNewThreadMode: true, }); - composerStore.setState({ newThreadRunMode: "default" }); settingsStore.setState({ activeAgentProfileId: "default-profile" }); await submitNewThread(makeSubmission({ value: "hello" })); @@ -659,7 +656,6 @@ describe("submitNewThread", () => { isNewThreadMode: true, }); projectStore.setState({ selectedProject: project, recentProjects: [project] }); - composerStore.setState({ newThreadRunMode: "default" }); settingsStore.setState({ activeAgentProfileId: "default-profile" }); await submitNewThread(makeSubmission({ @@ -703,7 +699,6 @@ describe("submitNewThread", () => { workspaces: [workspace], isNewThreadMode: true, }); - composerStore.setState({ newThreadRunMode: "default" }); settingsStore.setState({ activeAgentProfileId: "default-profile" }); await submitNewThread(makeSubmission({ value: "new thread" })); diff --git a/src/modules/workbench-shell/model/workbench-actions.ts b/src/modules/workbench-shell/model/workbench-actions.ts index da71fc2c..02f3803e 100644 --- a/src/modules/workbench-shell/model/workbench-actions.ts +++ b/src/modules/workbench-shell/model/workbench-actions.ts @@ -51,7 +51,7 @@ import { findWorkspaceByPath, } from "@/modules/workbench-shell/model/workspace-path-bindings"; import type { ProjectOption, WorkspaceItem } from "@/modules/workbench-shell/model/types"; -import type { MessageAttachmentDto, RunMode, ThreadSummaryDto, WorkspaceDto } from "@/shared/types/api"; +import type { MessageAttachmentDto, ThreadSummaryDto, WorkspaceDto } from "@/shared/types/api"; import type { LanguagePreference } from "@/app/providers/language-provider"; import type { ComposerCommandInvocation } from "@/modules/workbench-shell/model/composer-commands"; @@ -61,7 +61,6 @@ import type { ComposerCommandInvocation } from "@/modules/workbench-shell/model/ export interface NewThreadSubmission { value: string; - runMode: RunMode; displayText?: string; effectivePrompt: string; attachments?: MessageAttachmentDto[]; @@ -574,7 +573,6 @@ export async function submitNewThread(submission: NewThreadSubmission): Promise< // Re-read workspaces after async IPC to avoid stale state const { workspaces } = threadStore.getState(); - const { newThreadRunMode } = composerStore.getState(); // Find or match the workspace in the sidebar const existingWorkspace = @@ -674,7 +672,6 @@ export async function submitNewThread(submission: NewThreadSubmission): Promise< attachments: (submission.attachments ?? []) as unknown as PendingThreadRun["attachments"], metadata: submission.metadata ?? null, command: submission.command, - runMode: submission.runMode ?? newThreadRunMode, threadId, }; return { @@ -717,7 +714,6 @@ export async function submitNewThread(submission: NewThreadSubmission): Promise< // Reset composer composerStore.setState({ newThreadValue: "", - newThreadRunMode: "default", newThreadReferencedFiles: [], newThreadAttachmentData: [], error: null, diff --git a/src/modules/workbench-shell/ui/dashboard-workbench-logic.ts b/src/modules/workbench-shell/ui/dashboard-workbench-logic.ts index 55658cbe..9dfc20f1 100644 --- a/src/modules/workbench-shell/ui/dashboard-workbench-logic.ts +++ b/src/modules/workbench-shell/ui/dashboard-workbench-logic.ts @@ -1,5 +1,5 @@ import type { LanguagePreference } from "@/app/providers/language-provider"; -import type { MessageAttachmentDto, RunMode, WorkspaceDto } from "@/shared/types/api"; +import type { MessageAttachmentDto, WorkspaceDto } from "@/shared/types/api"; import { buildProjectOptionFromPath } from "@/modules/workbench-shell/model/helpers"; import type { ProjectOption, @@ -188,6 +188,5 @@ export type PendingThreadRun = { attachments: MessageAttachmentDto[]; metadata: Record | null; command?: import("@/modules/workbench-shell/model/composer-commands").ComposerCommandInvocation; - runMode: RunMode; threadId: string; }; diff --git a/src/modules/workbench-shell/ui/dashboard-workbench.tsx b/src/modules/workbench-shell/ui/dashboard-workbench.tsx index b8129cac..f2dd227c 100644 --- a/src/modules/workbench-shell/ui/dashboard-workbench.tsx +++ b/src/modules/workbench-shell/ui/dashboard-workbench.tsx @@ -262,7 +262,6 @@ const drawerWidth = useStore(uiLayoutStore, (s) => s.drawerWidth); const composerValue = useStore(composerStore, (s) => s.newThreadValue); const composerError = useStore(composerStore, (s) => s.error); - const newThreadRunMode = useStore(composerStore, (s) => s.newThreadRunMode); const newThreadReferencedFiles = useStore(composerStore, (s) => s.newThreadReferencedFiles); const newThreadAttachmentData = useStore(composerStore, (s) => s.newThreadAttachmentData); @@ -714,7 +713,6 @@ const drawerWidth = useStore(uiLayoutStore, (s) => s.drawerWidth); void submitNewThread({ value: trimmedValue, - runMode: newThreadRunMode, displayText: submission.displayText, effectivePrompt, attachments: submission.attachments, diff --git a/src/modules/workbench-shell/ui/runtime-thread-surface-state.ts b/src/modules/workbench-shell/ui/runtime-thread-surface-state.ts index 1b862dbe..dab0e8be 100644 --- a/src/modules/workbench-shell/ui/runtime-thread-surface-state.ts +++ b/src/modules/workbench-shell/ui/runtime-thread-surface-state.ts @@ -7,7 +7,6 @@ import type { MessageAttachmentDto, MessageDto, MessagePartDto, - RunMode, RunSummaryDto, ThreadSnapshotDto, ToolCallDto, @@ -279,7 +278,6 @@ export type InitialPromptRequest = { effectivePrompt: string; attachments: MessageAttachmentDto[]; metadata: Record | null; - runMode?: RunMode; }; export type ThinkingPlaceholder = { @@ -392,22 +390,6 @@ export function mapRecordedUserMessage(event: RecordedUserMessageEvent): Surface -export function deriveSelectedRunMode(snapshot: ThreadSnapshotDto, currentMode: RunMode) { - if ( - snapshot.thread.status === "waiting_approval" - && !snapshot.activeRun - && snapshot.latestRun?.runMode === "plan" - ) { - return "plan"; - } - - if (snapshot.activeRun?.runMode === "default" || snapshot.activeRun?.runMode === "plan") { - return snapshot.activeRun.runMode; - } - - return currentMode; -} - export function formatApprovalPromptState(state: string, approvedAction: PlanApprovalAction | null, t: (key: TranslationKey) => string) { switch (state) { case "approved": diff --git a/src/modules/workbench-shell/ui/runtime-thread-surface.tsx b/src/modules/workbench-shell/ui/runtime-thread-surface.tsx index 6fbfb3e3..ef06efe8 100644 --- a/src/modules/workbench-shell/ui/runtime-thread-surface.tsx +++ b/src/modules/workbench-shell/ui/runtime-thread-surface.tsx @@ -38,7 +38,6 @@ import { } from "@/services/thread-stream"; import type { MessageAttachmentDto, - RunMode, RuntimeQueueMessageKind, RuntimeQueueMessageDto, RuntimeQueueSnapshotDto, @@ -118,7 +117,6 @@ import { TaskHistoryTimeline } from "@/modules/workbench-shell/ui/task-stage-his import { appendOrReplaceMessage, compareTimelineEntries, - deriveSelectedRunMode, formatApprovalPromptState, formatToolStatusLabel, getApprovalReason, @@ -356,7 +354,6 @@ export function RuntimeThreadSurface({ threadStore, (s) => (threadId ? s.threadStatuses[threadId]?.runId ?? null : null), ); - const [selectedRunMode, setSelectedRunMode] = useState("default"); const [snapshotReady, setSnapshotReady] = useState(false); const [snapshotThreadId, setSnapshotThreadId] = useState(null); @@ -376,7 +373,6 @@ export function RuntimeThreadSurface({ useEffect(() => { if (prevThreadIdRef.current !== threadId) { prevThreadIdRef.current = threadId; - setSelectedRunMode("default"); setRuntimeQueueSubmitMode(defaultAppendMessageKind); setRequestRetryEntries([]); setRequestRetryOpen({}); @@ -694,7 +690,6 @@ export function RuntimeThreadSurface({ } eventBufferRef.current = []; } - setSelectedRunMode((current) => deriveSelectedRunMode(snapshot, current)); if (!shouldPreserveContextUsage) { threadStore.setState({ runtimeContextUsage: nextContextUsage }); } @@ -836,7 +831,6 @@ export function RuntimeThreadSurface({ errorMessage: null, retryCount: 0, }); - setSelectedRunMode((current) => deriveSelectedRunMode(snapshot, current)); const latestVisibleRun = getLatestVisibleRun(snapshot); if (latestVisibleRun?.id === runId) { @@ -1017,9 +1011,6 @@ export function RuntimeThreadSurface({ if (event.type === "run_started") { setApprovingPlanMessageId(null); - if (event.runMode === "default" || event.runMode === "plan") { - setSelectedRunMode(event.runMode); - } } if (event.type === "stream_resync_required") { @@ -1505,7 +1496,6 @@ export function RuntimeThreadSurface({ const submitPrompt = useCallback(async ( submissionOrPrompt: ComposerSubmission | string, - runModeOverride?: RunMode, ): Promise => { if (!threadId) { setComposerError("This thread is still preparing. Try again in a moment."); @@ -1520,7 +1510,6 @@ export function RuntimeThreadSurface({ rawMessage: { text: submissionOrPrompt, files: [] }, attachments: [], metadata: null, - runMode: runModeOverride, } : submissionOrPrompt; const prompt = submission.effectivePrompt ?? ""; @@ -1726,7 +1715,7 @@ export function RuntimeThreadSurface({ promptMetadata: submission.metadata ?? null, attachments: submission.attachments, }, - runModeOverride ?? submission.runMode ?? selectedRunMode, + "default", modelPlan, ); } catch (error) { @@ -1736,7 +1725,7 @@ export function RuntimeThreadSurface({ submittingRef.current = false; } return true; - }, [activeAgentProfileId, activeProfile, agentProfiles, appendOptimisticUserMessage, loadSnapshot, providers, runState, runtimeQueueSubmitMode, selectedRunMode, t, threadId]); + }, [activeAgentProfileId, activeProfile, agentProfiles, appendOptimisticUserMessage, loadSnapshot, providers, runState, runtimeQueueSubmitMode, t, threadId]); const cancelRuntimeQueueMessage = useCallback(async (messageId: string) => { if (!threadId || !streamRef.current) { @@ -1884,9 +1873,6 @@ export function RuntimeThreadSurface({ // Mark as handled at the store level — survives component unmount/remount. markPendingRunHandled(initialPromptRequestId!); - if (initialPromptRequest.runMode) { - setSelectedRunMode(initialPromptRequest.runMode); - } const pendingRunSubmission: ComposerSubmission = { kind: initialPromptRequest.command ? "command" : "plain", displayText: initialPromptRequest.displayText, @@ -1895,9 +1881,8 @@ export function RuntimeThreadSurface({ attachments: initialPromptRequest.attachments, command: initialPromptRequest.command, metadata: initialPromptRequest.metadata, - runMode: initialPromptRequest.runMode, }; - void submitPrompt(pendingRunSubmission, initialPromptRequest.runMode) + void submitPrompt(pendingRunSubmission) .finally(() => { threadStore.setState((prev) => { const next = Object.fromEntries( diff --git a/src/modules/workbench-shell/ui/workbench-prompt-composer.tsx b/src/modules/workbench-shell/ui/workbench-prompt-composer.tsx index 6acd577a..25df8b42 100644 --- a/src/modules/workbench-shell/ui/workbench-prompt-composer.tsx +++ b/src/modules/workbench-shell/ui/workbench-prompt-composer.tsx @@ -72,7 +72,7 @@ import type { updateAgentProfile as updateAgentProfileAction } from "@/modules/s import { sortAgentProfilesByName } from "@/modules/settings-center/model/profile-utils"; import { profileSubagentAccessGet } from "@/services/bridge/subagent-commands"; import type { SkillRecord } from "@/shared/types/extensions"; -import type { RunMode, RuntimeQueueMessageKind } from "@/shared/types/api"; +import type { RuntimeQueueMessageKind } from "@/shared/types/api"; import { indexFilterFiles, type FileFilterMatch } from "@/services/bridge"; import type { SerializableAttachment } from "@/modules/workbench-shell/model/composer-store"; import { useT } from "@/i18n"; @@ -182,7 +182,6 @@ function isSlashCommandActive(value: string) { function buildSubmissionFromPromptInput( message: PromptInputMessage, registry: ReadonlyArray, - runMode: RunMode, referencedFiles: ReadonlyArray, ): ComposerSubmission { const rawText = message.text ?? ""; @@ -215,7 +214,6 @@ function buildSubmissionFromPromptInput( }, } : null, - runMode, }; } @@ -227,7 +225,6 @@ function buildSubmissionFromPromptInput( effectivePrompt, rawMessage: message, attachments, - runMode, command: { source: parsedCommand.command.source, name: parsedCommand.command.name, @@ -2143,7 +2140,7 @@ export function WorkbenchPromptComposer({ // must be called inside a PromptInput descendant. const handlePromptSubmit = async (message: PromptInputMessage) => { - const submission = buildSubmissionFromPromptInput(message, commandRegistry, "default", referencedFiles); + const submission = buildSubmissionFromPromptInput(message, commandRegistry, referencedFiles); await onSubmit(submission); // Only clear referenced files and sources after a successful submit. // If onSubmit throws (e.g. thread has an active run), the composer