Skip to content

feat: issue 2097 wave 3 features#2109

Open
embire2 wants to merge 2 commits intostackblitz-labs:mainfrom
embire2:feat/issue-2097-wave2
Open

feat: issue 2097 wave 3 features#2109
embire2 wants to merge 2 commits intostackblitz-labs:mainfrom
embire2:feat/issue-2097-wave2

Conversation

@embire2
Copy link

@embire2 embire2 commented Feb 5, 2026

Summary

This PR continues issue #2097 by shipping the next 5 community requests plus a few QoL items already in this branch.

Detailed Change Log

Wave 2 (QoL + performance + workflow)

  • Agent mode (backend planning step)
    • Adds an internal planning pass in build mode and injects the plan into the system prompt for better multi-step execution.
    • Toggle: Settings -> Features -> Agent Mode.
  • Confirm file changes (git-like approvals)
    • File writes are staged as pending actions with diff previews.
    • Apply/Discard per file or batch.
    • Toggle: Settings -> Features -> Confirm File Changes and quick toggle in the chat box.
  • Auto prompt enhancement
    • Optional auto-enhance step before sending a message; avoids manual clicks for smaller-context models.
    • Toggle in Settings + chat box toggle button.
  • Mobile-friendly UI
    • Responsive chat width on small screens.
    • Mobile toggle to switch between chat and workbench views.
  • Performance mode
    • Disables heavier prompt effects and background visuals to reduce CPU/GPU load.
    • Toggle in Settings + quick toggle in chat box.

Wave 3 (new providers + stability + workflow)

  • Azure OpenAI provider support
    • Adds AzureOpenAI provider with deployment-based model selection and API version support.
    • Env keys: AZURE_OPENAI_API_KEY, AZURE_OPENAI_BASE_URL, AZURE_OPENAI_API_VERSION.
    • Base URL configurable in provider settings.
  • Vertex AI provider support
    • Adds VertexAI provider with Google Vertex AI Gemini endpoints.
    • Env keys: VERTEX_AI_ACCESS_TOKEN, VERTEX_AI_BASE_URL.
    • Base URL configurable in provider settings.
  • Framework lock hint (prevents stack drift)
    • Detects framework from package.json and injects a hint into the system prompt.
    • Toggle: Settings -> Features -> Framework Lock.
  • Customizable keyboard shortcuts
    • Record shortcuts for theme/terminal actions; reset to defaults; persisted in local storage.
    • UI in Settings -> Features.
  • Pause / Resume preview
    • Adds a pause toggle in the preview toolbar that hides the iframe to reduce lag.

Tracker Update

  • Updated docs/issue-2097-tracker.txt with Wave 3 entries.

Testing

  • pnpm typecheck
  • pnpm lint

Refs #2097

@embire2 embire2 mentioned this pull request Feb 5, 2026
@Stijnus Stijnus self-assigned this Feb 5, 2026
Copy link
Collaborator

@Stijnus Stijnus left a comment

Choose a reason for hiding this comment

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

Code Review — PR #2109

Same author as #2108, same pattern — this PR bundles 10 unrelated features across 2 "waves" in a single PR (+1417/-75, 22 files). Reviewing each feature:


Structural Issue: This needs to be split

This PR contains 10 independent features across 22 files in 2 commits. Each feature should be its own PR:

  • Agent mode, confirm file writes, auto prompt enhancement, mobile UI, performance mode (Wave 2)
  • Azure OpenAI, Vertex AI, framework lock, keyboard shortcuts, pause/resume preview (Wave 3)

Bundling makes it impossible to review, revert, or bisect individual features.


Critical Issues

1. Agent Mode doubles LLM cost with no user visibility

In stream-text.ts, Agent Mode makes a separate LLM call before every response to generate a plan:

const planResult = await _streamText({
  model: provider.getModelInstance({...}),
  system: planPrompt,
  messages: convertToCoreMessages(processedMessages as any),
  ...planTokenParams,
});

This silently doubles API costs on every message. There's no indication to the user that an extra call is happening, no cost estimate, and no way to see the generated plan. The plan is injected into the system prompt but never shown to the user — making it impossible to debug if it generates bad plans.

2. Confirm File Writes can lose user work permanently

When confirmFileWrites is enabled, file write actions are intercepted and queued as pending. But:

  • If the user closes the browser/tab, all pending actions are lost forever (stored only in a nanostores map, not persisted)
  • Actions queued during streaming (isStreaming check) are silently skipped — the user sees no feedback about why files weren't written
  • Discarding an action marks it as aborted but subsequent LLM responses may reference files they assume were written, causing cascading confusion

3. Azure OpenAI provider has authentication issues

In azure-openai.ts, the custom fetch wrapper sends both Authorization header (from the SDK) and api-key header. It then tries to remove Authorization and re-set api-key:

const headers = new Headers(init?.headers);
headers.delete('Authorization');
headers.set('api-key', apiKey);

But it also passes apiKey to createOpenAI() which sets the Authorization header. This dual-auth approach is fragile. Azure OpenAI requires either api-key header OR Authorization: Bearer — not both. The compatibility: 'compatible' flag with the OpenAI SDK may also cause issues with Azure's slightly different API shape.

4. Vertex AI provider uses wrong SDK

In vertex-ai.ts, it uses createGoogleGenerativeAI from @ai-sdk/google:

import { createGoogleGenerativeAI } from '@ai-sdk/google';

But this creates a Google AI Studio client, not a Vertex AI client. The Vertex AI API has a different URL structure and authentication scheme (OAuth2 service account tokens vs API keys). The @ai-sdk/google-vertex package exists specifically for Vertex AI. Using @ai-sdk/google with a custom base URL and Bearer token may work for some endpoints but is not the correct integration and will likely break for certain models or features.

5. Framework detection runs on every render

In Chat.client.tsx:

const frameworkHint = useMemo(() => {
  if (!frameworkLock) return undefined;
  const detected = detectFrameworkFromFiles(files);
  ...
}, [files, frameworkLock]);

files is a nanostores FileMap that changes frequently (on every file save, every LLM file write). This means detectFrameworkFromFiles — which parses package.json from the file map — runs on every file change. While not catastrophic, it's unnecessary. The framework rarely changes; this should be debounced or cached.

6. Keyboard shortcuts can conflict with browser/OS shortcuts

The shortcut recording in FeaturesTab.tsx captures any key combo without checking for conflicts:

updateShortcutBinding(recordingShortcut, {
  key: event.key,
  ctrlKey: event.ctrlKey || undefined,
  metaKey: event.metaKey || undefined,
  ...
});

A user could record Cmd+W (close tab), Cmd+Q (quit browser), Cmd+T (new tab), etc. There's no validation or warning about conflicts with browser shortcuts. Also, the ctrlOrMetaKey field is always set to undefined when recording — meaning the cross-platform behavior is lost. If a user records Ctrl+D on Mac, it won't match Cmd+D.

7. Mobile toggle manipulates stores directly without coordination

const toggleMobileView = () => {
  const nextShowWorkbench = !showWorkbench;
  workbenchStore.showWorkbench.set(nextShowWorkbench);
  chatStore.setKey('showChat', !nextShowWorkbench);
};

This directly sets two independent stores. If either setter triggers side effects or if there's a listener that reads both stores, they may see inconsistent state. The sidebar toggle button also had its disabled check removed (disabled={!canHideChat} instead of disabled={!canHideChat || isSmallViewport}), which could cause layout issues.


Minor Issues

8. docs/issue-2097-tracker.txt — Same as #2108, tracking files don't belong in the repo.

9. Performance mode is cosmetic only — It removes backdrop-blur and background rays, but these are CSS-only effects that browsers already GPU-accelerate. The actual CPU/GPU drain comes from the WebContainer, iframe preview, and CodeMirror editor — none of which are affected by this toggle. The feature risks being misleading.

10. Auto prompt enhancement UX — When enabled, every message silently gets enhanced before sending. The user types one thing but a different prompt gets sent. There's a toast notification but no way to see/approve the enhanced version before it's sent. Combined with Agent Mode (which adds another invisible planning step), a single user message could trigger 3 LLM calls.


What's done well

  • Framework detection logic in framework.ts is comprehensive and well-ordered (specific frameworks before generic ones)
  • The PendingFileActions component UI with diff preview is a nice concept
  • Keyboard shortcut persistence with proper defaults merging is solid
  • Pause/resume preview is clean and simple
  • The mobile toggle idea addresses a real need

Recommendation: Do NOT approve

  1. Split into individual PRs — each feature needs independent review
  2. Agent Mode — needs user visibility (show the plan), cost warning, and opt-in per message
  3. Vertex AI — use the correct SDK (@ai-sdk/google-vertex)
  4. Azure OpenAI — fix dual-auth, test with actual Azure endpoints
  5. Confirm File Writes — persist pending actions, handle the streaming case properly
  6. Keyboard shortcuts — add conflict detection, preserve ctrlOrMetaKey behavior
  7. Remove tracker file from the repo

@embire2 embire2 closed this Feb 6, 2026
@embire2 embire2 reopened this Feb 6, 2026
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.

3 participants