Merge pull request #17 from southseact-3d/cto-task-ok-so-for-the-plan-messages-when-the-proceed-with-build-butt

Add model selector to plan messages proceed button
This commit is contained in:
cto-new[bot]
2026-02-10 10:19:13 +00:00
committed by GitHub
3 changed files with 221 additions and 2 deletions

View File

@@ -0,0 +1,57 @@
# Model Selector for Plan Messages - Implementation Complete
## What Was Implemented
When the "Proceed with Build" button appears in plan messages, a model selector dropdown is now displayed above it, allowing users to choose which AI model to use for the build process.
## Changes Made
### 1. New Function: `createInlineModelSelector()`
Location: chat/public/builder.js (line 1900-1975)
This helper function:
- Creates a container div with the class 'inline-model-selector'
- Adds a label "Select Model for Build:" above the dropdown
- Creates a styled select dropdown element
- Populates it with all available models from state.models
- Shows model labels, names, and multipliers (e.g., "2x")
- Pre-selects the currently chosen model
- Handles user selection changes and syncs with the main model selector
- Updates state.selectedModelId and calls markUserModelChange()
### 2. Modified "Proceed with Build" Button Section
Location: chat/public/builder.js (line 2174-2193)
The proceed button section now:
- Creates a container div (buildActionsContainer) using flexbox layout
- Adds the inline model selector above the button
- Adds the "Proceed with Build" button below the selector
- Appends the entire container to the message body
## Key Features
Model selector appears inline in plan messages
User can change model before proceeding with build
Selection syncs with main model selector in composer
State is properly managed and protected from server overwrites
Handles edge cases (no models available)
Matches existing UI styling and design system
JavaScript syntax validation passed
No breaking changes to existing functionality
## How It Works
1. User receives a plan message from AI
2. The renderMessages function detects it's a plan message ready for building
3. A buildActionsContainer is created with the inline model selector and proceed button
4. User can select a different model from the dropdown if desired
5. Selection changes update state and sync with main selector
6. When user clicks "Proceed with Build", the selected model is used for the build
## Technical Details
- Uses flexbox for layout (gap: 12px, margin-top: 16px)
- Select element styled with custom SVG dropdown arrow
- Full-width design for easy selection on all devices
- Integrates with existing state management functions
- No backend changes required

View File

@@ -0,0 +1,72 @@
# Model Selector for Plan Messages Implementation
## Summary
When the "Proceed with Build" button appears in plan messages, a model selector dropdown is now displayed above it, allowing users to choose the AI model they want to use for the build process.
## Changes Made
### 1. New Helper Function: `createInlineModelSelector()`
**Location:** `chat/public/builder.js` (lines ~1899-1975)
Created a new helper function that generates an inline model selector specifically for plan messages:
- Creates a labeled select dropdown with the title "Select Model for Build:"
- Populates the dropdown with all available models from `state.models`
- Shows model labels, names, and multiplier indicators (e.g., "2x")
- Pre-selects the currently selected model from `state.selectedModelId`
- Handles model selection changes and updates:
- The inline selector's value
- The main model selector in the composer area
- The state's selectedModelId
- Marks the change as user-initiated to prevent server overwrites
### 2. Modified "Proceed with Build" Button Section
**Location:** `chat/public/builder.js` (lines ~2174-2193)
Updated the code where the "Proceed with Build" button is created:
- Creates a container div (`buildActionsContainer`) to hold both the model selector and the button
- Adds the inline model selector above the button
- Maintains the existing "Proceed with Build" button functionality
- Uses flexbox layout with proper spacing (gap: 12px, margin-top: 16px)
## How It Works
1. **Plan Message Displayed**: When an AI plan message is received and ready for building
2. **Model Selector Created**: The `createInlineModelSelector()` function is called to generate the dropdown
3. **User Selection**: User can select a different model for the build if desired
4. **State Sync**: Selection changes are synchronized with the main model selector
5. **Build Process**: When "Proceed with Build" is clicked, the selected model is used for the build
## Benefits
- **Better UX**: Users can now choose their model right where they need it (in the plan message)
- **Flexibility**: No need to go back to the composer area to change models before proceeding
- **Clear Context**: Model selector is clearly labeled as "Select Model for Build:"
- **State Consistency**: Model selection is synchronized across all UI elements
- **Prevents Conflicts**: User model selections are protected from server overwrites
## Technical Details
### Styling
The inline model selector uses:
- Consistent styling with the rest of the UI
- Custom SVG dropdown arrow
- Proper padding and borders matching the design system
- Full-width layout for easy selection on all devices
### State Management
- Updates `state.selectedModelId` when changed
- Calls `markUserModelChange()` to prevent server overwrites
- Syncs with the main model selector in the composer
- Preserves existing state management patterns
### Integration
- Works with the existing `updateModelSelectDisplay()` function
- Compatible with `markUserModelChange()` for state protection
- Integrates seamlessly with the current build flow
- No changes to backend or API required
## Testing
- JavaScript syntax check: ✓ Passed
- Function definition: ✓ Present at line 1900
- Function call: ✓ Present at line 2181
- No breaking changes to existing functionality

View File

@@ -1895,6 +1895,85 @@ function hideLoadingIndicator() {
}
// Expose for builder.html
// Helper function to create inline model selector for plan messages
function createInlineModelSelector() {
const container = document.createElement('div');
container.className = 'inline-model-selector';
container.style.cssText = 'display: flex; flex-direction: column; gap: 8px;';
// Label
const label = document.createElement('label');
label.textContent = 'Select Model for Build:';
label.style.cssText = 'font-weight: 600; font-size: 13px; color: var(--ink);';
// Create a select element (simple and reliable)
const select = document.createElement('select');
select.className = 'inline-model-select';
select.style.cssText = `
padding: 10px 12px;
border: 1px solid var(--border);
border-radius: 10px;
background: #fff;
font-weight: 600;
color: var(--ink);
font-size: 14px;
cursor: pointer;
width: 100%;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 12px center;
background-size: 14px;
padding-right: 40px;
`;
// Populate with available models
if (state.models && state.models.length > 0) {
state.models.forEach(model => {
const option = document.createElement('option');
option.value = model.id || model.name || model;
option.textContent = model.label || model.name || model.id || model;
if (model.multiplier && model.multiplier !== 1) {
option.textContent += ` (${model.multiplier}x)`;
}
select.appendChild(option);
});
// Set current selection
const currentSelection = state.selectedModelId || el.modelSelect?.value;
if (currentSelection) {
select.value = currentSelection;
}
} else {
const option = document.createElement('option');
option.value = '';
option.textContent = 'No models available';
option.disabled = true;
select.appendChild(option);
}
// Handle selection change
select.addEventListener('change', (e) => {
const selectedModel = e.target.value;
console.log('[Inline Model Selector] Model selected:', selectedModel);
// Update state
state.selectedModelId = selectedModel;
// Also update the main model selector if it exists
if (el.modelSelect) {
el.modelSelect.value = selectedModel;
updateModelSelectDisplay(selectedModel);
}
// Mark that user changed model (prevent server from overwriting)
markUserModelChange();
});
container.appendChild(label);
container.appendChild(select);
return container;
}
window.hideLoadingIndicator = hideLoadingIndicator;
function renderMessages(session) {
@@ -2093,13 +2172,24 @@ function renderMessages(session) {
const needsClarification = clarificationPatterns.some(pattern => pattern.test(replyContent));
if (isOpenRouterMessage && hasReply && (isPlanPhase || isBuildPhase) && !needsClarification) {
// Create a container for model selector and proceed button
const buildActionsContainer = document.createElement('div');
buildActionsContainer.className = 'build-actions-container';
buildActionsContainer.style.cssText = 'display: flex; flex-direction: column; gap: 12px; margin-top: 16px;';
// Create inline model selector for plan messages
const inlineModelSelector = createInlineModelSelector();
buildActionsContainer.appendChild(inlineModelSelector);
// Create proceed button
const proceedBtn = document.createElement('button');
proceedBtn.className = 'primary';
proceedBtn.style.marginTop = '12px';
proceedBtn.style.width = '100%';
proceedBtn.textContent = 'Proceed with Build';
proceedBtn.onclick = () => proceedWithBuild(replyContent);
assistantBody.appendChild(proceedBtn);
buildActionsContainer.appendChild(proceedBtn);
assistantBody.appendChild(buildActionsContainer);
}
// Add Download ZIP button for OpenCode messages that are finished and are the latest message