Skip to content

Conversation

@kylecarbs
Copy link
Member

@kylecarbs kylecarbs commented Nov 2, 2025

Changes the "New Workspace" modal to instead be inline in the chat form.

mux-titles-new-2025-11-13_09.43.32.mp4

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".

- Add workspaceTitleGenerator service using Vercel AI SDK
- Generate human-readable titles and git-safe branch names
- Add sendFirstMessage IPC handler that creates workspace automatically
- Add ProjectSelector and FirstMessageInput components for empty state
- Update App.tsx to show project selector when no workspace exists
- Gracefully fall back to timestamp names if AI generation fails

Users can now type a message and hit send to create a workspace
with an AI-generated title and branch name based on their message.

Generated with `cmux`
The 'name' field is used throughout the backend to compute filesystem
paths (e.g., runtime.getWorkspacePath uses metadata.name as the directory).
Storing the AI-generated title there would break path resolution.

Solution:
- Add optional 'displayName' field to WorkspaceMetadata
- Store git-safe branch name in 'name' (used for paths)
- Store human-readable title in 'displayName' (used for display)
- UI prefers displayName over name when rendering

This maintains backward compatibility - existing workspaces without
displayName continue to work, showing the branch name as before.

Generated with `cmux`
FirstMessageInput was using useSendMessageOptions which internally uses
useThinking hook, causing 'useThinking must be used within a
ThinkingProvider' error in E2E tests when empty state was rendered.

Instead, directly use useModelLRU to get the most recent model without
requiring context providers.

Generated with `cmux`
Instead of showing a project selector dropdown when no workspace is
selected, we now:
- If only one project exists: Show FirstMessageInput immediately
- If multiple projects exist: Show welcome message asking user to
  select/create workspace via sidebar

This is cleaner UX - users already interact with projects via the
left sidebar, no need for duplicate selection UI.

Generated with `cmux`
1. Merge sendFirstMessage into sendMessage - make workspaceId optional
   to reduce duplication in IPC layer. When null, automatically creates
   workspace with AI-generated title/branch.

2. Use standard useSendMessageOptions in FirstMessageInput instead of
   manually managing model selection.

3. Use the same model as provided in send message options for title
   generation instead of hardcoding cheap models. This respects custom
   BaseURL configurations and avoids manual updates when models change.

4. Remove redundant WORKSPACE_SEND_FIRST_MESSAGE IPC channel and handler.

Generated with `cmux`
useSendMessageOptions internally uses useThinking which requires
ThinkingProvider context. Since FirstMessageInput is rendered outside
of context providers, manually build send options instead.

Generated with `cmux`
Fixes floating promise lint error in sendMessage when creating
workspaces without explicit workspaceId.

editConfig() returns a promise that must be awaited before
continuing to retrieve the complete metadata.
Changes workspace creation UX to show FirstMessageInput instead of
NewWorkspaceModal when user clicks the '+ Add Workspace' button.

User flow:
1. Click '+ Add Workspace' in sidebar
2. See FirstMessageInput (same as single-project empty state)
3. Type message and hit send
4. Workspace created with AI-generated title/branch
5. Message sent to new workspace

Added cancel functionality:
- Escape key cancels workspace creation
- Cancel button shown when in 'add workspace' mode
- Returns user to empty state on cancel

NewWorkspaceModal still exists for advanced users (can be triggered
via command palette or other flows in the future).
Redesigned FirstMessageInput to use the same visual style as ChatInput
for a unified user experience.

Changes:
- Replaced custom textarea with VimTextArea component (matches ChatInput)
- Added ModelSelector component for choosing AI model
- Added runtime config selector (Local vs SSH) with SSH host input
- Styled with same CSS classes as ChatInput (bg-separator, border-border-light, etc.)
- Options displayed inline below input (Model | Runtime | Cancel/Send)
- Added helpful tooltip for runtime configuration

All workspace creation options now visible and accessible without
needing to open a separate modal.
Changes:
- Removed Send and Cancel buttons (use Cmd+Enter to send like ChatInput)
- Input now takes full width (removed button constraints)
- Added project title in center of empty view
- Shows trunk branch below project name (auto-detected, informational)
- Removed manual trunk branch selector (backend auto-detects it)
- Cleaner, more unified UX matching ChatInput behavior
- Import useMode hook from ModeContext
- Add MODE_OPTIONS and ModeHelpTooltip (matching ChatInput)
- Add mode selector UI with responsive layouts (full and compact)
- VimTextArea now uses mode state instead of hardcoded 'exec'
- Includes tooltip explaining Exec vs Plan mode

Related to #500
…ut backend

- Import useThinkingLevel, use1MContext hooks and policy utilities
- Build SendMessageOptions with all required fields (mode, toolPolicy, thinkingLevel, providerOptions)
- Add ThinkingSliderComponent and Context1MCheckbox UI (matching ChatInput layout)
- Mode selector now positioned with ml-auto (right-aligned like ChatInput)
- All message options (mode, thinking, 1M context) now properly passed to backend

This ensures the first message respects the same settings as regular messages.

Related to #500
FirstMessageInput doesn't have a workspace yet, so it can't use the
ModeProvider context (which requires a workspaceId). Instead, use
usePersistedState directly with a project-scoped mode key.

This matches the pattern already used for the model preference and
ensures the mode persists per-project before workspace creation.

Fixes: "useMode must be used inside ModeProvider" error

Related to #500
…eInput

Similar to the mode fix, thinking level also requires a provider with
workspaceId. Use usePersistedState directly with a project-scoped key
to avoid the "useThinking must be used within a ThinkingProvider" error.

All three preferences now use the same pattern:
- Mode: project-scoped (persists per-project)
- Thinking level: project-scoped (persists per-project)
- 1M context: global (already uses usePersistedState directly)

Related to #500
…cies

ThinkingSliderComponent and Context1MCheckbox both require context providers
with workspaceId. Created simple inline versions for FirstMessageInput:

- SimpleThinkingControl: Clickable button that cycles through thinking levels
- Simple1MCheckbox: Standard checkbox with label

These components accept state as props instead of using context hooks,
eliminating the provider dependency while maintaining the same functionality.

Fixes: "useThinking must be used within a ThinkingProvider" error

Related to #500
- Made workspaceId optional in ModeProvider and ThinkingProvider
  - Falls back to global key (__global__) when workspaceId not provided
- Wrapped FirstMessageInput in ModeProvider and ThinkingProvider in App.tsx
- Removed inline SimpleThinkingControl and Simple1MCheckbox components
- Now uses actual ThinkingSliderComponent and Context1MCheckbox
- Uses context hooks (useMode, useThinkingLevel) instead of direct usePersistedState

This ensures FirstMessageInput uses the exact same components as ChatInput,
providing UI consistency and shared behavior.

Related to #500
- Added trunk branch dropdown in options row (label: "From:")
- Updates sendMessage IPC to accept optional trunkBranch parameter
- Backend uses provided trunkBranch if specified, otherwise auto-detects
- Trunk branch selector shows all available branches from the project
- Matches styling of other controls (Runtime selector, etc.)

This allows users to choose which branch to branch from when creating
a new workspace, just like the NewWorkspaceModal did.

Related to #500
- Removed 'Based on {trunkBranch}' text from center display
- Made trunk branch selector narrower (max-w-[120px])
- Center now just shows project name, all controls in options row

Related to #500
1. Workspace title generation now prioritizes fast/cheap models:
   - Haiku (Anthropic) first
   - GPT-4o-mini (OpenAI) second
   - Falls back to user's selected model if neither available

   This makes workspace creation much faster - no longer uses slow
   models like Sonnet for simple title/branch generation.

2. Fixed Enter key to send message (was requiring Shift+Enter):
   - Now uses matchesKeybind(KEYBINDS.SEND_MESSAGE) like ChatInput
   - Plain Enter sends, Shift+Enter adds newline
   - Matches ChatInput behavior exactly

Related to #500
- Shows animated spinner in center when isSending is true
- Displays "Creating workspace..." message below spinner
- Replaces project title temporarily during creation
- Uses accent color for spinner to match theme

This provides visual feedback during the workspace creation process,
preventing the UI from appearing frozen while AI generates the title
and workspace is being created.

Related to #500
Added descriptive text below project title explaining:
- Describe what you want to build
- Workspace created automatically with generated branch name
- Runtime and model options configurable below

Makes the first-time experience more clear and guides users on what to do.

Related to #500
- Add projectPath prop to ModeProvider and ThinkingProvider
- Use project-scoped storage keys when workspaceId not provided
- Scoping priority: workspace > project > global
- Matches existing pattern for model selection (__project__ prefix)
- FirstMessageInput now persists mode/thinking per-project, not globally
Matches the standard naming convention used throughout codebase
(slash commands, tests, tokenizer mappings)
- Created ModeSelector.tsx with MODE_OPTIONS and ModeHelpTooltip
- Replaced duplicate mode selector code in ChatInput and FirstMessageInput
- Ensures mode UI changes are reflected in both places
- Includes responsive layouts (full/compact) and keyboard shortcut tooltip
- Remove unused cn import from ChatInput and FirstMessageInput
- Remove unused UIMode import from ChatInput
- Format ModeSelector.tsx with prettier
- Use '/' delimiter in project scope IDs (e.g. __project__/path not __project__path)
- Always use user's model for title generation (not hardcoded fast models)
- Extract createInitLogger() helper to avoid duplication (3 occurrences)

Addresses ammario's feedback on delimiter choice, model selection maintainability,
and code duplication patterns.
- Regenerate missing title/branch on workspace load (WORKSPACE_GET_INFO handler)
- Add Config.updateWorkspaceMetadata() for updating workspace fields
- Extract createWorkspaceForFirstMessage() to reduce sendMessage handler complexity
- Decomposed 140+ line function into focused helper method

Addresses ammario's feedback on robustness and code decomposition.
- Await updateWorkspaceMetadata() call
- Format ipcMain.ts with prettier
- Prioritize fast/cheap models for workspace title generation
- Use claude-haiku-4-5 (Anthropic) instead of user's model
- Use gpt-5-mini (OpenAI) as second choice
- Fall back to user's model if neither provider available
@kylecarbs kylecarbs added this pull request to the merge queue Nov 13, 2025
@kylecarbs kylecarbs removed this pull request from the merge queue due to a manual request Nov 13, 2025
@kylecarbs kylecarbs merged commit 43bce08 into main Nov 13, 2025
14 checks passed
@kylecarbs kylecarbs deleted the titles branch November 13, 2025 16:11
ammar-agent added a commit that referenced this pull request Nov 13, 2025
Fixes two issues introduced in PR #500:

1. Runtime saving regression: The FirstMessageInput component wasn't
   persisting runtime selection to localStorage after workspace creation.
   Added runtime preference saving using updatePersistedState helper.

2. UI layout jank: Controls specific to new workspace creation (trunk
   branch selector and runtime selector) were mixed with general chat
   controls. Separated them into two rows for better visual organization.

Also fixed: Use persistedState helpers (readPersistedState,
updatePersistedState) instead of direct localStorage calls throughout
FirstMessageInput for consistency and cross-component synchronization.

Added note to AGENTS.md about using persistedState helpers and keeping
edits minimal/token-efficient.

_Generated with `cmux`_
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