Skip to content

Conversation

@ibetitsmike
Copy link
Contributor

Previously, workspace creation blocked for up to 10s while waiting for the AI to generate a workspace name. This caused a poor UX where users had to wait before seeing any result.

Changes

  • Use generatePlaceholderName() to create workspace immediately with a temporary name derived from the user's message (e.g., 'add-user-auth')
  • Generate AI name asynchronously in the background via generateAndApplyAIName()
  • If AI generation succeeds and differs from placeholder, rename workspace using existing rename() method
  • If AI generation or rename fails, gracefully keep the placeholder name

UX Improvement

Before After
User waits 5-10s for AI name generation Workspace appears instantly
Loading spinner while blocked AI name applied seamlessly when ready
Network/API errors block creation Errors handled gracefully, placeholder name retained

The existing generatePlaceholderName() function was already implemented but unused - this change puts it to work.

Generated with mux

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ammario
Copy link
Member

ammario commented Dec 3, 2025

Can we reliably rename a workspace with an active stream? Just making sure it won't interfere with running bash operations, file edits, etc.

@ibetitsmike
Copy link
Contributor Author

@ammario the idea was to wait until stream ends

const handler = (event: StreamEndEvent | StreamAbortEvent) => {
        if (event.workspaceId === workspaceId) {
          this.aiService.off("stream-end", handler);
          this.aiService.off("stream-abort", handler);
          log.debug("Stream completed, proceeding with rename", { workspaceId });
          resolve();
        }
      };

@ibetitsmike ibetitsmike added this pull request to the merge queue Dec 3, 2025
@ibetitsmike ibetitsmike removed this pull request from the merge queue due to a manual request Dec 3, 2025
@ibetitsmike ibetitsmike force-pushed the async-workspace-name-generation branch 4 times, most recently from 66f70e3 to edc1191 Compare December 3, 2025 22:32
Previously, workspace creation blocked for up to 10s while waiting for
the AI to generate a workspace name. This caused a poor UX where users
had to wait before seeing any result.

Changes:
- Use generatePlaceholderName() to create workspace immediately with
  a temporary name derived from the user's message (e.g., 'add-user-auth')
- Generate AI name asynchronously in the background
- If AI generation succeeds and differs from placeholder, rename workspace
- If AI generation or rename fails, gracefully keep the placeholder name

The workspace now appears instantly while the AI-generated name is applied
as soon as it's available. Users see their workspace right away instead of
waiting for the AI provider to respond.

_Generated with `mux`_
Address review feedback: the rename() method rejects while a stream is
active, so the async name generation needs to wait for the stream to
complete before attempting the rename.

Added waitForStreamComplete() helper that:
- Returns immediately if no stream is active
- Subscribes to stream-end and stream-abort events
- Resolves when the workspace's stream completes

This ensures the AI-generated name is applied after the first message
stream finishes, rather than being silently rejected.
The workspace now appears immediately with 'creating' status:

1. Generate placeholder name and ID (instant)
2. Emit preliminary metadata with status='creating' (instant)
3. Return to frontend immediately

All blocking operations run in completeWorkspaceCreation():
- listLocalBranches (git operation)
- detectDefaultTrunkBranch (git operation)
- runtime.createWorkspace (creates worktree)
- Config save

On completion, final metadata is emitted (without 'creating' status).
On failure, null metadata is emitted to remove the workspace.

Also added collision retry for AI-generated name renames.
Two fixes:

1. WorktreeRuntime.renameWorkspace now renames the git branch via
   `git branch -m` after moving the worktree directory. Previously
   only the directory was moved, leaving the branch with the old name.

2. ReviewPanel shows a loading state when workspace status is 'creating'.
   This prevents errors when the panel tries to run git commands on a
   workspace that doesn't exist on disk yet.

Props added: AIView.status, RightSidebar.isCreating, ReviewPanel.isCreating
Branch rename can fail if the branch name doesn't match the old
directory name (e.g., in test scenarios). The directory move is
the critical operation; branch rename is nice-to-have.

In mux's real usage, branch name and workspace name are always kept
in sync, so the branch rename will succeed in production.
When creating a workspace with async background operations, the
frontend can try to access the workspace before React processes
the state update. This causes a race condition where WorkspaceStore
throws 'must call addWorkspace() first'.

Fix by calling workspaceStore.addWorkspace() synchronously BEFORE
setting the selected workspace. This ensures the store knows about
the workspace immediately, regardless of when React batches the
state updates.
…eation

Two fixes for workspace rename not updating UI:

1. App.tsx: Use currentMetadata?.namedWorkspacePath instead of the stale
   selectedWorkspace.namedWorkspacePath. The live metadata updates when
   the workspace is renamed, while selectedWorkspace is set once at creation.

2. ReviewPanel.tsx: Add isCreating checks to useEffects that load data.
   Previously the early return only affected the render output, but the
   data loading useEffects still ran and tried to call executeBash on a
   workspace that wasn't in config yet.
When workspace creation background operations fail (e.g., API key not
configured), errors were silently logged to console with no user feedback.
The user would just see their message with no response.

Changes:
- Add formatSendMessageError helper to convert SendMessageError to
  user-friendly messages with appropriate StreamErrorType
- Handle sendMessage result in completeWorkspaceCreation and emit
  stream-error events on failure
- Add unit tests for the new helper

This ensures users see error messages in the chat UI instead of silence.

_Generated with mux_
Two issues fixed:

1. Pre-stream error surfacing:
   - When sendMessage fails before streaming starts (e.g., API key not
     configured), the error was silently ignored
   - Modified StreamingMessageAggregator.handleStreamError to create a
     synthetic error message when no active stream exists
   - Added logging in workspaceService.completeWorkspaceCreation

2. Model persistence on workspace creation:
   - Model selected for creation was persisted at project scope but not
     synced to workspace scope
   - On restart, getSendOptionsFromStorage would fall back to default model
   - Added model sync in syncCreationPreferences alongside mode/thinking

_Generated with mux_
Added renamingWorkspaces set to track workspaces being renamed.
- sendMessage and resumeStream now check this flag and return error
- Both AI-generated rename and user-initiated rename set the flag
- Flag is cleared in finally blocks to ensure cleanup

This prevents a race where:
1. Stream ends, rename starts
2. Auto-resume or user triggers new stream
3. Stream uses old paths while rename is changing them

_Generated with mux_
Tests verify:
- sendMessage returns error when workspace is being renamed
- resumeStream returns error when workspace is being renamed
- rename returns error when workspace is streaming

_Generated with mux_
@ibetitsmike ibetitsmike force-pushed the async-workspace-name-generation branch from edc1191 to 3c3862c Compare December 3, 2025 22:37
@ibetitsmike ibetitsmike added this pull request to the merge queue Dec 3, 2025
Merged via the queue into main with commit 4eef087 Dec 3, 2025
15 of 16 checks passed
@ibetitsmike ibetitsmike deleted the async-workspace-name-generation branch December 3, 2025 22:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants