diff --git a/packages/app/src/app/agent/new.tsx b/packages/app/src/app/agent/new.tsx index 95402712d..5fb67b83f 100644 --- a/packages/app/src/app/agent/new.tsx +++ b/packages/app/src/app/agent/new.tsx @@ -122,6 +122,7 @@ export default function DraftAgentScreen() { >(null); const [errorMessage, setErrorMessage] = useState(""); const [isLoading, setIsLoading] = useState(false); + const [promptText, setPromptText] = useState(""); const [baseBranch, setBaseBranch] = useState(""); // Isolation mode: "none" | "branch" | "worktree" const [isolationMode, setIsolationMode] = useState<"none" | "branch" | "worktree">("none"); @@ -487,27 +488,27 @@ export default function DraftAgentScreen() { const trimmedPrompt = text.trim(); if (!trimmedPath) { setErrorMessage("Working directory is required"); - return; + throw new Error("Working directory is required"); } if (!trimmedPrompt) { setErrorMessage("Initial prompt is required"); - return; + throw new Error("Initial prompt is required"); } if (!selectedServerId) { setErrorMessage("No host selected"); - return; + throw new Error("No host selected"); } if (gitBlockingError) { setErrorMessage(gitBlockingError); - return; + throw new Error(gitBlockingError); } if (isLoading) { - return; + throw new Error("Already loading"); } const createAgent = sessionMethods?.createAgent; if (!createAgent) { setErrorMessage("Host is not connected"); - return; + throw new Error("Host is not connected"); } const modeId = modeOptions.length > 0 && selectedMode !== "" ? selectedMode : undefined; @@ -608,6 +609,7 @@ export default function DraftAgentScreen() { } pendingRequestIdRef.current = null; setIsLoading(false); + setPromptText(""); router.push({ pathname: "/agent/[serverId]/[agentId]", params: { @@ -905,6 +907,8 @@ export default function DraftAgentScreen() { serverId={selectedServerId ?? ""} onSubmitMessage={handleCreateFromInput} isSubmitLoading={isLoading} + value={promptText} + onChangeText={setPromptText} /> diff --git a/packages/app/src/components/agent-input-area.tsx b/packages/app/src/components/agent-input-area.tsx index 8f6490d6a..14db31a34 100644 --- a/packages/app/src/components/agent-input-area.tsx +++ b/packages/app/src/components/agent-input-area.tsx @@ -52,6 +52,8 @@ interface AgentInputAreaProps { }) => Promise; /** Externally controlled loading state. When true, disables the submit button. */ isSubmitLoading?: boolean; + value?: string; + onChangeText?: (text: string) => void; } const MIN_INPUT_HEIGHT = 50; @@ -96,6 +98,8 @@ export function AgentInputArea({ serverId, onSubmitMessage, isSubmitLoading = false, + value, + onChangeText, }: AgentInputAreaProps) { const { theme } = useUnistyles(); const insets = useSafeAreaInsets(); @@ -146,7 +150,9 @@ export function AgentInputArea({ const wsOrInert = ws ?? inertWebSocket; const { startRealtime, stopRealtime, isRealtimeMode } = useRealtime(); - const [userInput, setUserInput] = useState(""); + const [internalInput, setInternalInput] = useState(""); + const userInput = value ?? internalInput; + const setUserInput = onChangeText ?? setInternalInput; const [inputHeight, setInputHeight] = useState(MIN_INPUT_HEIGHT); const [isProcessing, setIsProcessing] = useState(false); const [selectedImages, setSelectedImages] = useState>([]); @@ -367,8 +373,11 @@ export function AgentInputArea({ const message = userInput.trim(); const imageAttachments = selectedImages.length > 0 ? selectedImages : undefined; - - setUserInput(""); + + const isControlled = value !== undefined; + if (!isControlled) { + setUserInput(""); + } setSelectedImages([]); setInputHeight(MIN_INPUT_HEIGHT); setIsProcessing(true); @@ -377,6 +386,11 @@ export function AgentInputArea({ await submitMessage(message, imageAttachments); } catch (error) { console.error("[AgentInput] Failed to send message:", error); + // Restore input on error so user doesn't lose their message + setUserInput(message); + if (imageAttachments) { + setSelectedImages(imageAttachments); + } } finally { setIsProcessing(false); } diff --git a/packages/server/src/server/session.ts b/packages/server/src/server/session.ts index f73c39ecf..ae286b502 100644 --- a/packages/server/src/server/session.ts +++ b/packages/server/src/server/session.ts @@ -1503,10 +1503,6 @@ export class Session { }; } - if (!normalized.createWorktree) { - await this.ensureCleanWorkingTree(cwd); - } - if (normalized.createWorktree) { const targetBranch = normalized.createNewBranch ? normalized.newBranchName @@ -1751,6 +1747,7 @@ export class Session { return; } + await this.ensureCleanWorkingTree(cwd); await execAsync(`git checkout ${branch}`, { cwd }); } @@ -1773,6 +1770,7 @@ export class Session { throw new Error(`Branch already exists: ${newBranchName}`); } + await this.ensureCleanWorkingTree(cwd); await execAsync(`git checkout -b ${newBranchName} ${baseBranch}`, { cwd, });