Chat-first new drive setup - #1263
Conversation
New Drive now asks what the workspace is for and reuses RealAIChat plus a bundled skill to research hints (like a company website) and build a small starter template. The name + Create path still creates an empty drive so existing e2e helpers keep working. Co-authored-by: joepmeindertsma <joepmeindertsma@gmail.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.
Bugbot Autofix prepared fixes for all 3 issues found in the latest run.
- ✅ Fixed: File-only messages no longer send
- Moved empty text check after onBeforeSubmit and added attachedFiles.length check to allow file-only messages.
- ✅ Fixed: Setup race creates two drives
- Added busy state management in handleBeforeChatSubmit to prevent concurrent drive creation attempts.
- ✅ Fixed: Failed create clears the prompt
- Made AIChatInput await onSubmit promise and only clear the input on success, preserving prompt on error.
Or push these changes by commenting:
@cursor push e691c651f4
Preview (e691c651f4)
diff --git a/browser/data-browser/src/chunks/AI/RealAIChat.tsx b/browser/data-browser/src/chunks/AI/RealAIChat.tsx
--- a/browser/data-browser/src/chunks/AI/RealAIChat.tsx
+++ b/browser/data-browser/src/chunks/AI/RealAIChat.tsx
@@ -540,10 +540,6 @@
return;
}
- if (text.trim() === '') {
- return;
- }
-
if (onBeforeSubmit) {
try {
await onBeforeSubmit(text);
@@ -558,6 +554,10 @@
}
}
+ if (text.trim() === '' && attachedFiles.length === 0) {
+ return;
+ }
+
const context = [...externalContextItems, ...userSelectedContextItems];
const message: AtomicUIMessage = {
id: store.newLocalId(),
diff --git a/browser/data-browser/src/chunks/RTE/AIChatInput/AsyncAIChatInput.tsx b/browser/data-browser/src/chunks/RTE/AIChatInput/AsyncAIChatInput.tsx
--- a/browser/data-browser/src/chunks/RTE/AIChatInput/AsyncAIChatInput.tsx
+++ b/browser/data-browser/src/chunks/RTE/AIChatInput/AsyncAIChatInput.tsx
@@ -97,7 +97,7 @@
large?: boolean;
onMentionUpdate: (mentions: MentionItem[]) => void;
onChange: (markdown: string) => void;
- onSubmit: () => void;
+ onSubmit: () => void | Promise<void>;
onCompact?: () => void;
onEditModel?: () => void;
onEditAgent?: () => void;
@@ -167,9 +167,15 @@
}
// The content has to be read from a ref because this callback is not updated often leading to stale content.
- onSubmitRef.current();
- setMarkdown('');
- this.editor.commands.clearContent();
+ Promise.resolve(onSubmitRef.current()).then(
+ () => {
+ setMarkdown('');
+ this.editor.commands.clearContent();
+ },
+ () => {
+ // Keep the input on error
+ },
+ );
return true;
},
@@ -301,9 +307,15 @@
disabled || disableSubmit || (markdown.length === 0 && !hasFiles)
}
onClick={() => {
- onSubmit();
- setMarkdown('');
- editor?.commands.clearContent();
+ Promise.resolve(onSubmit()).then(
+ () => {
+ setMarkdown('');
+ editor?.commands.clearContent();
+ },
+ () => {
+ // Keep the input on error
+ },
+ );
}}
title='Send'
variant={IconButtonVariant.Fill}
diff --git a/browser/data-browser/src/components/Drives/NewDriveSetup.tsx b/browser/data-browser/src/components/Drives/NewDriveSetup.tsx
--- a/browser/data-browser/src/components/Drives/NewDriveSetup.tsx
+++ b/browser/data-browser/src/components/Drives/NewDriveSetup.tsx
@@ -127,6 +127,12 @@
return;
}
+ if (busy) {
+ throw new Error('Drive is already being created, please wait.');
+ }
+
+ setBusy(true);
+
try {
await createDrive(driveNameFromPrompt(text));
} catch (err) {
@@ -134,6 +140,8 @@
err instanceof Error ? err : new Error('Could not create the drive.');
store.notifyError(asError);
throw asError;
+ } finally {
+ setBusy(false);
}
};You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit e30b1ce. Configure here.
|
|
||
| if (text.trim() === '') { | ||
| return; | ||
| } |
There was a problem hiding this comment.
File-only messages no longer send
Medium Severity
The new empty-text return in handleSubmit bails out before attachments are added, so a send with files and no caption is dropped. The input already allows that case when hasFiles is set, which previously produced an image-only message.
Reviewed by Cursor Bugbot for commit e30b1ce. Configure here.
| store.notifyError(asError); | ||
| throw asError; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Setup race creates two drives
Medium Severity
The first chat send creates a drive only after await store.createDrive, and createdDrive / busy are not shared with that path. While that request is in flight, starter prompts and the Name/Create form stay active, so a second submit can create another drive.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit e30b1ce. Configure here.
| setRequestError(message); | ||
|
|
||
| return; | ||
| } |
There was a problem hiding this comment.
Failed create clears the prompt
Medium Severity
onBeforeSubmit is documented to keep the typed message when it throws, but the input clears before that promise settles. A failed drive create therefore wipes the prompt and surfaces it as a provider error whose Try again calls regenerate even though no message was sent.
Reviewed by Cursor Bugbot for commit e30b1ce. Configure here.



New Drive now starts as a conversation: the assistant asks what the drive is for, can take hints like a company website, and builds a small starter workspace from existing table templates.
What changed
drive-setupskill (read_skill/ attached as chat context) that interviews the user, researches a URL or company name via web search, renames the drive, and creates a few matching tables/folders/docs — not every template.NewDriveSetupreusesRealAIChat(lazy-loaded) in the New Drive dialog and/app/new-drivepage, with starter prompts and the skill pre-attached.store.setDrive+ a React flush), then the agent writes into that drive.newDrive()in e2e is unchanged.Tests
driveNameFromPrompt(URL host, first line, truncation, empty fallback).Checklist