-
-
setFormData({...formData, maxTokens: e.target.value})}
- className="h-10"
- />
- {defaultConfig?.max_tokens && (
-
- 🔧 Default: {defaultConfig.max_tokens?.toLocaleString()}
-
- )}
-
diff --git a/src/components/model-config-tabs.tsx b/src/components/model-config-tabs.tsx
index 1b957a7d..910d2a74 100644
--- a/src/components/model-config-tabs.tsx
+++ b/src/components/model-config-tabs.tsx
@@ -2,7 +2,6 @@ import { useState, useCallback } from 'react';
import {
Settings,
Rocket,
- Wrench,
Code,
Bug,
Brain,
@@ -17,7 +16,7 @@ import { Badge } from '@/components/ui/badge';
import { toast } from 'sonner';
import { ConfigCard } from './config-card';
import { ConfigModal } from './config-modal';
-import type { ModelConfig, UserModelConfigWithMetadata, ModelConfigUpdate } from '@/api-types';
+import type { ModelConfig, UserModelConfigWithMetadata, ModelConfigUpdate, AgentDisplayConfig } from '@/api-types';
// Define workflow-based tab structure with dynamic agent categorization
export const WORKFLOW_TABS = {
@@ -49,13 +48,6 @@ export const WORKFLOW_TABS = {
description: 'Code fixing and review',
patterns: ['fixer', 'fix', 'review', 'debug']
},
- advanced: {
- id: 'advanced',
- label: 'Advanced',
- icon: Wrench,
- description: 'Specialized operations',
- patterns: ['screenshot', 'analysis', 'image', 'vision']
- }
} as const;
// Helper function to categorize agents dynamically with specific mappings
@@ -64,11 +56,11 @@ const categorizeAgent = (agentKey: string): string => {
const specificMappings: Record
= {
// Quick Start - Most commonly used
'templateSelection': 'quickstart',
- 'blueprint': 'quickstart',
'conversationalResponse': 'quickstart',
// Planning - Project planning and setup
'phaseGeneration': 'planning',
+ 'blueprint': 'quickstart',
'projectSetup': 'planning',
// Coding - Development and implementation
@@ -77,12 +69,7 @@ const categorizeAgent = (agentKey: string): string => {
'fileRegeneration': 'coding', // Fix: was going to planning due to "generation"
// Debugging - Code fixing and review
- 'realtimeCodeFixer': 'debugging',
- 'fastCodeFixer': 'debugging',
- 'codeReview': 'debugging',
-
- // Advanced - Specialized operations
- 'screenshotAnalysis': 'advanced'
+ 'deepDebugger': 'debugging',
};
// Check specific mappings first
@@ -117,13 +104,6 @@ const categorizeAgent = (agentKey: string): string => {
return 'advanced';
};
-// Frontend-specific agent display interface
-export interface AgentDisplayConfig {
- key: string;
- name: string;
- description: string;
-}
-
interface ModelConfigTabsProps {
agentConfigs: AgentDisplayConfig[];
modelConfigs: Record;
diff --git a/src/components/monaco-editor/monaco-editor.tsx b/src/components/monaco-editor/monaco-editor.tsx
index 5777877e..b4900047 100644
--- a/src/components/monaco-editor/monaco-editor.tsx
+++ b/src/components/monaco-editor/monaco-editor.tsx
@@ -36,7 +36,7 @@ self.MonacoEnvironment = {
};
// From GitHub Dark theme
-monaco.editor.defineTheme('v1-dev-dark', {
+monaco.editor.defineTheme('vibesdk-dark', {
base: 'vs-dark',
inherit: true,
rules: [
@@ -77,7 +77,7 @@ monaco.editor.defineTheme('v1-dev-dark', {
},
});
-monaco.editor.defineTheme('v1-dev', {
+monaco.editor.defineTheme('vibesdk', {
base: 'vs',
inherit: true,
rules: [
@@ -116,43 +116,13 @@ monaco.editor.defineTheme('v1-dev', {
},
});
-monaco.editor.setTheme('v1-dev');
-
-monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
- noSemanticValidation: true,
- noSyntaxValidation: true,
-});
-
-// Configure TypeScript defaults for JSX support
-monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
- jsx: monaco.languages.typescript.JsxEmit.React,
- allowJs: true,
- allowSyntheticDefaultImports: true,
- esModuleInterop: true,
- moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
- module: monaco.languages.typescript.ModuleKind.ESNext,
- target: monaco.languages.typescript.ScriptTarget.ESNext,
- jsxFactory: 'React.createElement',
- jsxFragmentFactory: 'React.Fragment',
-});
-
-// Configure JavaScript defaults for JSX support
-monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
- allowJs: true,
- allowSyntheticDefaultImports: true,
- esModuleInterop: true,
- jsx: monaco.languages.typescript.JsxEmit.React,
- moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
- module: monaco.languages.typescript.ModuleKind.ESNext,
- target: monaco.languages.typescript.ScriptTarget.ESNext,
- jsxFactory: 'React.createElement',
- jsxFragmentFactory: 'React.Fragment',
-});
+monaco.editor.setTheme('vibesdk');
export type MonacoEditorProps = React.ComponentProps<'div'> & {
createOptions?: monaco.editor.IStandaloneEditorConstructionOptions;
find?: string;
replace?: string;
+ enableTypeScriptFeatures?: 'auto' | boolean;
};
/**
@@ -163,6 +133,7 @@ export const MonacoEditor = memo(function MonacoEditor({
createOptions = {},
find,
replace,
+ enableTypeScriptFeatures = 'auto',
...props
}) {
const containerRef = useRef(null);
@@ -171,6 +142,63 @@ export const MonacoEditor = memo(function MonacoEditor({
const stickyScroll = useRef(true);
const { theme } = useTheme();
+ const shouldEnableTypeScript = React.useMemo(() => {
+ if (enableTypeScriptFeatures === 'auto') {
+ return !createOptions.readOnly;
+ }
+ return enableTypeScriptFeatures;
+ }, [enableTypeScriptFeatures, createOptions.readOnly]);
+
+ // Configure TypeScript diagnostics based on mode
+ useEffect(() => {
+ const tsDefaults = monaco.languages.typescript.typescriptDefaults;
+ const jsDefaults = monaco.languages.typescript.javascriptDefaults;
+
+ if (shouldEnableTypeScript) {
+ // Enable full IntelliSense for editing
+ tsDefaults.setDiagnosticsOptions({
+ noSemanticValidation: false,
+ noSyntaxValidation: false,
+ });
+ tsDefaults.setCompilerOptions({
+ jsx: monaco.languages.typescript.JsxEmit.React,
+ allowJs: true,
+ allowSyntheticDefaultImports: true,
+ esModuleInterop: true,
+ moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
+ module: monaco.languages.typescript.ModuleKind.ESNext,
+ target: monaco.languages.typescript.ScriptTarget.ESNext,
+ jsxFactory: 'React.createElement',
+ jsxFragmentFactory: 'React.Fragment',
+ });
+ jsDefaults.setCompilerOptions({
+ allowJs: true,
+ allowSyntheticDefaultImports: true,
+ esModuleInterop: true,
+ jsx: monaco.languages.typescript.JsxEmit.React,
+ moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
+ module: monaco.languages.typescript.ModuleKind.ESNext,
+ target: monaco.languages.typescript.ScriptTarget.ESNext,
+ jsxFactory: 'React.createElement',
+ jsxFragmentFactory: 'React.Fragment',
+ });
+ } else {
+ // Disable expensive features for viewing
+ tsDefaults.setDiagnosticsOptions({
+ noSemanticValidation: true,
+ noSyntaxValidation: true,
+ });
+ tsDefaults.setCompilerOptions({
+ jsx: monaco.languages.typescript.JsxEmit.React,
+ target: monaco.languages.typescript.ScriptTarget.ESNext,
+ });
+ jsDefaults.setCompilerOptions({
+ jsx: monaco.languages.typescript.JsxEmit.React,
+ target: monaco.languages.typescript.ScriptTarget.ESNext,
+ });
+ }
+ }, [shouldEnableTypeScript]);
+
useEffect(() => {
let configuredTheme = theme;
@@ -180,7 +208,7 @@ export const MonacoEditor = memo(function MonacoEditor({
editor.current = monaco.editor.create(containerRef.current!, {
language: createOptions.language || 'typescript',
minimap: { enabled: false },
- theme: configuredTheme === 'dark' ? 'v1-dev-dark' : 'v1-dev',
+ theme: configuredTheme === 'dark' ? 'vibesdk-dark' : 'vibesdk',
automaticLayout: true,
value: defaultCode,
fontSize: 13,
@@ -207,6 +235,10 @@ export const MonacoEditor = memo(function MonacoEditor({
}
return () => {
+ const model = editor.current?.getModel();
+ if (model) {
+ model.dispose();
+ }
editor.current?.dispose();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -217,10 +249,16 @@ export const MonacoEditor = memo(function MonacoEditor({
const model = editor.current.getModel();
if (!model) return;
- editor.current.setValue(createOptions.value || '');
+ model.pushEditOperations(
+ [],
+ [{
+ range: model.getFullModelRange(),
+ text: createOptions.value || ''
+ }],
+ () => null
+ );
if (stickyScroll.current) {
- // Scroll to bottom
const lineCount = model.getLineCount();
editor.current.revealLine(lineCount);
}
@@ -293,7 +331,7 @@ export const MonacoEditor = memo(function MonacoEditor({
// Update theme when app theme changes
useEffect(() => {
if (editor.current) {
- monaco.editor.setTheme(theme === 'dark' ? 'v1-dev-dark' : 'v1-dev');
+ monaco.editor.setTheme(theme === 'dark' ? 'vibesdk-dark' : 'vibesdk');
}
}, [theme]);
diff --git a/src/components/ui/model-selector.tsx b/src/components/ui/model-selector.tsx
index 0677d92d..7fbc6155 100644
--- a/src/components/ui/model-selector.tsx
+++ b/src/components/ui/model-selector.tsx
@@ -111,7 +111,7 @@ export function ModelSelector({
className="w-full justify-between"
disabled={disabled}
>
- {getSelectedDisplay() || placeholder}
+ {getSelectedDisplay() || placeholder}
@@ -203,7 +203,7 @@ export function ModelSelector({
{/* System default display */}
{systemDefault && (
-
+
🔧 System default: {getModelDisplayName(systemDefault)}
)}
diff --git a/src/lib/api-client.ts b/src/lib/api-client.ts
index a6ea0952..ae87ebe9 100644
--- a/src/lib/api-client.ts
+++ b/src/lib/api-client.ts
@@ -684,11 +684,14 @@ class ApiClient {
/**
* Get BYOK providers and available models
+ * @param agentAction - Optional agent action to filter models by constraints
*/
- async getByokProviders(): Promise> {
- return this.request(
- '/api/model-configs/byok-providers',
- );
+ async getByokProviders(agentAction?: string): Promise> {
+ const endpoint = agentAction
+ ? `/api/model-configs/byok-providers?agentAction=${encodeURIComponent(agentAction)}`
+ : '/api/model-configs/byok-providers';
+
+ return this.request(endpoint);
}
/**
diff --git a/src/routes/app/index.tsx b/src/routes/app/index.tsx
index b576d1f9..03a9cdc1 100644
--- a/src/routes/app/index.tsx
+++ b/src/routes/app/index.tsx
@@ -1000,7 +1000,7 @@ export default function AppView() {
'on',
scrollBeyondLastLine: false,
fontSize: 13,
- theme: 'v1-dev',
+ theme: 'vibesdk',
automaticLayout: true,
}}
/>
diff --git a/src/routes/chat/chat.tsx b/src/routes/chat/chat.tsx
index 71803cea..df1a3c47 100644
--- a/src/routes/chat/chat.tsx
+++ b/src/routes/chat/chat.tsx
@@ -36,7 +36,6 @@ import { useAutoScroll } from '@/hooks/use-auto-scroll';
import { useImageUpload } from '@/hooks/use-image-upload';
import { useDragDrop } from '@/hooks/use-drag-drop';
import { ImageAttachmentPreview } from '@/components/image-attachment-preview';
-import { createAIMessage } from './utils/message-helpers';
import { Button } from '@/components/ui/button';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
@@ -113,14 +112,12 @@ export default function Chat() {
totalFiles,
websocket,
sendUserMessage,
- sendAiMessage,
blueprint,
previewUrl,
clearEdit,
projectStages,
phaseTimeline,
isThinking,
- onCompleteBootstrap,
// Deployment and generation control
isDeploying,
cloudflareDeploymentUrl,
@@ -235,7 +232,7 @@ export default function Chat() {
const imageInputRef = useRef(null);
// Fake stream bootstrap files
- const { streamedFiles: streamedBootstrapFiles, doneStreaming } =
+ const { streamedFiles: streamedBootstrapFiles } =
useFileContentStream(bootstrapFiles, {
tps: 600,
enabled: isBootstrapping,
@@ -413,28 +410,7 @@ export default function Chat() {
setView('editor');
}
}, [isGeneratingBlueprint, view]);
-
- useEffect(() => {
- // Only show bootstrap completion message for NEW chats, not when reloading existing ones
- if (doneStreaming && !isGeneratingBlueprint && !blueprint && urlChatId === 'new') {
- onCompleteBootstrap();
- sendAiMessage(
- createAIMessage(
- 'creating-blueprint',
- 'Bootstrapping complete, now creating a blueprint for you...',
- true,
- ),
- );
- }
- }, [
- doneStreaming,
- isGeneratingBlueprint,
- sendAiMessage,
- blueprint,
- onCompleteBootstrap,
- urlChatId,
- ]);
-
+
const isRunning = useMemo(() => {
return (
isBootstrapping || isGeneratingBlueprint // || codeGenState === 'active'
@@ -1183,7 +1159,7 @@ export default function Chat() {
lineNumbers: 'on',
scrollBeyondLastLine: false,
fontSize: 13,
- theme: 'v1-dev',
+ theme: 'vibesdk',
automaticLayout: true,
}}
find={
diff --git a/src/routes/chat/components/model-config-info.tsx b/src/routes/chat/components/model-config-info.tsx
index 36113211..4dda644d 100644
--- a/src/routes/chat/components/model-config-info.tsx
+++ b/src/routes/chat/components/model-config-info.tsx
@@ -10,8 +10,7 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
-import type { ModelConfig, UserModelConfigWithMetadata } from '@/api-types';
-import type { AgentDisplayConfig } from '@/components/model-config-tabs';
+import type { AgentDisplayConfig, ModelConfig, UserModelConfigWithMetadata } from '@/api-types';
// Reuse workflow tabs from settings (DRY principle)
const WORKFLOW_TABS = {
diff --git a/src/routes/chat/components/preview-iframe.tsx b/src/routes/chat/components/preview-iframe.tsx
index eae8d601..1b1986af 100644
--- a/src/routes/chat/components/preview-iframe.tsx
+++ b/src/routes/chat/components/preview-iframe.tsx
@@ -336,6 +336,7 @@ export const PreviewIframe = forwardRef(
if (loadState.status === 'loaded' && loadState.loadedSrc) {
return (