diff --git a/.env.example b/.env.example index e3d7904..03d61fa 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,11 @@ ZAI_API_KEY= ZAI_GENERAL_ENDPOINT=https://api.z.ai/api/paas/v4 ZAI_CODING_ENDPOINT=https://api.z.ai/api/coding/paas/v4 +# OpenRouter API +# Get API key from https://openrouter.ai/keys +OPENROUTER_API_KEY= +OPENROUTER_DEFAULT_MODEL=google/gemini-2.0-flash-exp:free + # Site Configuration (Required for OAuth in production) # Set to your production URL (e.g., https://your-app.vercel.app) NEXT_PUBLIC_SITE_URL=http://localhost:6002 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2874db7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,115 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.3.0] - 2025-03-18 + +### Added +- **OpenRouter Integration** — 4th AI provider with API key auth, 20+ model support + - New `lib/services/openrouter.ts` streaming service + - Provider selector in AI Assist: Qwen, Ollama, Z.AI, OpenRouter + - Default model: `google/gemini-2.0-flash-exp:free` + - Custom model selector with popular free/paid model presets + - Settings panel: API key input with validation and model picker +- **Plan-First Workflow** — AI now generates a structured plan before code + - PLAN MODE instructions injected into all 4 service system prompts + - Plan card UI with architecture, tech stack, files, and steps + - `parsePlanFromResponse()` extracts plans from AI markdown output + - `[PLAN]` tags hidden from displayed chat messages + - Three action buttons: **Modify Plan** / **Start Coding** / **Skip to Code** +- **Post-Coding UX** — Preview + Request Modifications after code generation + - After "Start Coding" approval, AI generates code with `[PREVIEW]` tags + - Canvas opens automatically with renderable previews + - Two post-coding buttons: **Preview** (re-opens canvas) and **Request Modifications** + - `isApproval` flag prevents stale React closure bugs in approval flow +- **Enhanced Prompt Engine** — New modular prompt enhancement system + - `lib/enhance-engine.ts` with 9 enhancement strategies + - Strategies: clarify, add-context, add-constraints, structure, add-examples, set-tone, expand, simplify, chain-of-thought + - Context-aware enhancement based on detected intent type + - 11+ intent detection patterns (coding, creative, analysis, etc.) + - Smart strategy selection per intent for optimal prompt refinement +- **Streaming Plan Mode** — Real-time plan parsing during AI response + - `wasIdle` flag captures initial request phase before state updates + - Canvas display suppressed during plan generation, enabled after approval + - Post-stream routing: plan card for initial requests, preview for approvals + - Tab `showCanvas` state gated by plan phase + +### Changed +- **AIAssist.tsx** — Major refactor for plan-first flow + - `handleSendMessage` now accepts `isApproval` parameter to prevent stale closures + - `approveAndGenerate()` passes `isApproval=true` to bypass idle detection + - `assistStep` state machine: `idle -> plan -> generating -> preview` + - `parseStreamingContent()` filters `[PLAN]` tags from displayed output +- **PromptEnhancer.tsx** — Rebuilt with modular enhance engine + - Moved enhancement logic to `lib/enhance-engine.ts` + - Added expand, simplify, and chain-of-thought strategies + - Improved intent detection and strategy mapping +- **SettingsPanel.tsx** — Added OpenRouter provider configuration + - API key input with validation + - Model selector with preset dropdown + - Provider-specific endpoint display +- **model-adapter.ts** — Extended with OpenRouter provider support + - New adapter mapping for OpenRouter service + - Unified interface across all 4 providers +- **translations.ts** — Added i18n keys for plan mode, OpenRouter, post-coding actions + - Keys: `modifyPlan`, `startCoding`, `skipToCode`, `requestModifications` + - OpenRouter provider labels and descriptions + - English, Russian, Hebrew translations updated +- **store.ts** — Added `selectedProvider` state for multi-provider selection +- **types/index.ts** — Added `PreviewData` interface for typed canvas rendering +- **adapter-instance.ts** — Registered OpenRouter in provider registry + +### Fixed +- **Stale React closure** in `approveAndGenerate` — `setAssistStep("generating")` followed by `handleSendMessage()` read stale `assistStep` value. Fixed with explicit `isApproval` boolean parameter. +- **Plan card reappearing after code generation** — Post-stream logic now correctly routes to `preview` mode after approval coding, not back to `plan` mode. +- **Canvas auto-opening during plan phase** — `setShowCanvas(true)` in `onChunk` now gated by `!wasIdle` flag. +- **i18n missing keys** — Added `syncComplete` for Hebrew, fixed double commas in multiple translation strings. + +### Technical Details +- Files modified: 11 (960 insertions, 194 deletions) +- Files added: 2 (`lib/enhance-engine.ts`, `lib/services/openrouter.ts`) +- Total project lines: ~10,179 across core files +- System prompt PLAN MODE block added to: `qwen-oauth.ts`, `ollama-cloud.ts`, `zai-plan.ts`, `openrouter.ts` + +## [1.2.0] - 2025-01-19 + +### Added +- **SEO Agent Behavior Fixes** + - SEO agent now stays locked and answers queries through an SEO lens + - Smart agent suggestions via `[SUGGEST_AGENT:xxx]` marker for clearly non-SEO tasks + - Visual suggestion banner with Switch/Dismiss buttons + - Prevented unwanted agent auto-switching mid-response +- **z.ai API Validation** + - Real-time API key validation with 500ms debounce + - Inline status indicators: + - Checkmark with "Validated Xm ago" for valid keys + - Red X with error message for invalid keys + - Loading spinner during validation + - "Test Connection" button for manual re-validation + - Persistent validation cache (5 minutes) in localStorage + +### Changed +- Updated Settings panel with improved UX for API key management +- Enhanced agent selection behavior to prevent unintended switches + +## [1.1.0] - 2025-01-15 + +### Added +- GitHub integration for pushing AI-generated artifacts +- XLSX export functionality for Google Ads campaigns +- High-fidelity HTML report generation +- OAuth token management for Qwen API + +## [1.0.0] - 2025-01-01 + +### Added +- Initial release of PromptArch +- Multi-provider AI support (Qwen, Ollama, Z.AI) +- Prompt Enhancer with 11+ intent patterns +- PRD Generator with structured output +- Action Plan generator with framework recommendations +- Visual canvas for live code rendering +- Multi-language support (English, Russian, Hebrew) diff --git a/README.md b/README.md index b0167d8..20fb88d 100644 --- a/README.md +++ b/README.md @@ -1,165 +1,171 @@ -# PromptArch: The Prompt Enhancer 🚀 - -> **Development Note**: This entire platform was developed exclusively using [TRAE.AI IDE](https://trae.ai) powered by elite [GLM 4.7 model](https://z.ai/subscribe?ic=R0K78RJKNW). -> **Learn more about this architecture [here](https://z.ai/subscribe?ic=R0K78RJKNW).** - ---- - -> **Fork Note**: This project is a specialized fork of [ClavixDev/Clavix](https://github.com/ClavixDev/Clavix), reimagined as a modern web-based platform for visual prompt engineering and product planning. - -Transform vague ideas into production-ready prompts and PRDs. PromptArch is an elite AI orchestration platform designed for software architects and Vibe Coders. - -**Developed by Roman | RyzenAdvanced** - -- 📦 **Gitea Repository**: [admin/PromptArch](https://github.rommark.dev/admin/PromptArch) -- 📮 **Telegram**: [@VibeCodePrompterSystem](https://t.me/VibeCodePrompterSystem) - -## 🌟 Visual Overview - -### 🛠 Core Capabilities - -- **Prompt Enhancer**: Refine vague prompts into surgical instructions for AI agents. -- **PRD Generator**: Convert ideas into structured Product Requirements Documents. -- **Action Plan**: Decompose PRDs into actionable development steps and framework recommendations. - -## ✨ Features - -- **Multi-Provider Ecosystem**: Native support for Qwen Code (OAuth), Ollama Cloud, and Z.AI Plan API. -- **Visual Prompt Engineering**: Patterns-based enhancement with 11+ intent types. -- **Architectural Decomposition**: Automatic generation of PRDs and structured Action Plans. -- **Resilient Fallbacks**: Multi-tier provider system that ensures uptime even if primary APIs fail. -- **Modern UI/UX**: Built with Next.js 15, Tailwind CSS, and shadcn/ui for a seamless developer experience. -- **OAuth Integration**: Secure Qwen authentication with 2,000 free daily requests. - -## 🚀 Quick Start - -1. **Clone & Install**: - ```bash - git clone https://github.rommark.dev/admin/PromptArch.git - cd PromptArch - npm install - ``` - -2. **Configuration**: - Copy `.env.example` to `.env` and add your API keys: - ```bash - cp .env.example .env - ``` - -3. **Launch**: - ```bash - npm run dev - ``` - -4. Open [http://localhost:3000](http://localhost:3000) to begin. - -## 📋 Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -### [1.2.0] - 2025-01-19 - -#### Added -- **SEO Agent Behavior Fixes** - - SEO agent now stays locked and answers queries through an SEO lens - - Smart agent suggestions via `[SUGGEST_AGENT:xxx]` marker for clearly non-SEO tasks - - Visual suggestion banner with Switch/Dismiss buttons - - Prevented unwanted agent auto-switching mid-response -- **z.ai API Validation** - - Real-time API key validation with 500ms debounce - - Inline status indicators: - - ✓ Green checkmark with "Validated Xm ago" for valid keys - - ✗ Red X with error message for invalid keys - - 🔄 Loading spinner during validation - - "Test Connection" button for manual re-validation - - Persistent validation cache (5 minutes) in localStorage - - Clear error messages: "Invalid API key", "Network error", etc. -- **Store Enhancements** - - `ApiValidationStatus` interface for tracking connection states - - `apiValidationStatus` state with per-provider tracking - - `setApiValidationStatus` action for updating validation results - -#### Changed -- Updated Settings panel with improved UX for API key management -- Enhanced agent selection behavior to prevent unintended switches -- Improved error handling for authentication failures - -#### Technical Details -- Files modified: - - `lib/store.ts` - Added validation state management - - `lib/services/zai-plan.ts` - Added `validateConnection()` method - - `lib/services/model-adapter.ts` - Added validation proxy - - `components/SettingsPanel.tsx` - Complete rewrite with validation UI - - `components/AIAssist.tsx` - Added suggestion handling and UI - -### [1.1.0] - 2025-01-15 - -#### Added -- GitHub integration for pushing AI-generated artifacts -- XLSX export functionality for Google Ads campaigns -- High-fidelity HTML report generation -- OAuth token management for Qwen API - -### [1.0.0] - 2025-01-01 - -#### Added -- Initial release of PromptArch -- Multi-provider AI support (Qwen, Ollama, Z.AI) -- Prompt Enhancer with 11+ intent patterns -- PRD Generator with structured output -- Action Plan generator with framework recommendations -- Visual canvas for live code rendering -- Multi-language support (English, Russian, Hebrew) - -## 🛠 Tech Stack - -- **Framework**: [Next.js 15.5](https://nextjs.org/) (App Router) -- **Styling**: [Tailwind CSS](https://tailwindcss.com/) -- **State Management**: [Zustand](https://zustand-demo.pmnd.rs/) -- **Components**: [shadcn/ui](https://ui.shadcn.com/) -- **Icons**: [Lucide React](https://lucide.dev/) - -## 🤝 Attribution & Credits - -**Author**: Roman | RyzenAdvanced -- 📦 **Gitea**: [admin/PromptArch](https://github.rommark.dev/admin/PromptArch) -- 📮 **Telegram**: [@VibeCodePrompterSystem](https://t.me/VibeCodePrompterSystem) - -**Forked from**: [ClavixDev/Clavix](https://github.com/ClavixDev/Clavix) -- This project is a visual and architectural evolution of the Clavix framework -- Clavix focuses on agentic-first Markdown templates -- PromptArch provides a centralized web interface with advanced model orchestration - -**Development Platform**: [TRAE.AI IDE](https://trae.ai) powered by elite [GLM 4.7 model](https://z.ai/subscribe?ic=R0K78RJKNW) -- 100% AI-assisted development using TRAE.AI's advanced coding capabilities -- Learn more about the architecture [here](https://z.ai/subscribe?ic=R0K78RJKNW) - -## Development - -```bash -# Install dependencies -npm install - -# Run development server -npm run dev - -# Build for production -npm run build - -# Start production server -npm start - -# Lint code -npm run lint -``` - -## License - -ISC - -## Contributing - -Contributions are welcome! Please feel free to submit a Pull Request. +# PromptArch: AI Orchestration Platform + +> **Development Note**: This entire platform was developed exclusively using [TRAE.AI IDE](https://trae.ai) powered by elite [GLM 4.7 model](https://z.ai/subscribe?ic=R0K78RJKNW). +> **Learn more about this architecture [here](https://z.ai/subscribe?ic=R0K78RJKNW).** + +--- + +> **Fork Note**: This project is a specialized fork of [ClavixDev/Clavix](https://github.com/ClavixDev/Clavix), reimagined as a modern web-based platform for visual prompt engineering and product planning. + +Transform vague ideas into production-ready prompts and PRDs. PromptArch is an AI orchestration platform designed for software architects and Vibe Coders, featuring a **plan-first workflow** with multi-provider AI support and live canvas rendering. + +**Developed by Roman | RyzenAdvanced** + +- **Gitea Repository**: [admin/PromptArch](https://github.rommark.dev/admin/PromptArch) +- **Live Site**: [rommark.dev/tools/promptarch](https://rommark.dev/tools/promptarch/) +- **Telegram**: [@VibeCodePrompterSystem](https://t.me/VibeCodePrompterSystem) + +## Core Capabilities + +| Feature | Description | +|---------|-------------| +| **AI Assist** | Plan-first workflow: describe a task, get a structured plan, approve, then generate working code with live preview | +| **Prompt Enhancer** | Refine vague prompts into surgical instructions using 9 enhancement strategies and 11+ intent patterns | +| **PRD Generator** | Convert ideas into structured Product Requirements Documents | +| **Action Plan** | Decompose PRDs into actionable development steps and framework recommendations | +| **Google Ads Generator** | Generate ad campaigns with XLSX and HTML report export | +| **Slides Generator** | Create presentation decks from prompts | +| **Market Researcher** | AI-powered market research and analysis | + +## Features + +### Plan-First Workflow (v1.3.0) +- AI generates a structured plan (architecture, tech stack, files, steps) before any code +- Plan Review Card with **Modify Plan**, **Start Coding**, and **Skip to Code** actions +- After code generation: **Preview** canvas + **Request Modifications** buttons +- Streaming plan mode with real-time parsing and canvas suppression + +### Multi-Provider AI (4 Providers) +| Provider | Auth | Models | +|----------|------|--------| +| **Qwen Code** | OAuth (2,000 free req/day) | Qwen Coder models | +| **Ollama Cloud** | API Key | Open-source models | +| **Z.AI Plan** | API Key | GLM general + coding models | +| **OpenRouter** | API Key | 20+ models (Gemini, Llama, Mistral, etc.) | + +### Visual Canvas +- Live code rendering with `[PREVIEW]` tags +- HTML, React, Python, and more — rendered in-browser +- Auto-detect renderable vs. code-only previews + +### Enhanced Prompt Engine +- 9 strategies: clarify, add-context, add-constraints, structure, add-examples, set-tone, expand, simplify, chain-of-thought +- Context-aware strategy selection based on detected intent +- 11+ intent detection patterns (coding, creative, analysis, etc.) + +### Other +- Multi-language support (English, Russian, Hebrew) +- Download generated artifacts as ZIP +- Push to GitHub integration +- Resilient multi-tier provider fallbacks + +## Quick Start + +1. **Clone & Install**: + ```bash + git clone https://github.rommark.dev/admin/PromptArch.git + cd PromptArch + npm install + ``` + +2. **Configuration**: + Copy `.env.example` to `.env` and add your API keys: + ```bash + cp .env.example .env + ``` + + Configure at least one provider: + - **Qwen**: Get OAuth credentials from [qwen.ai](https://qwen.ai) + - **Ollama**: Get API key from [ollama.com/cloud](https://ollama.com/cloud) + - **Z.AI**: Get API key from [docs.z.ai](https://docs.z.ai) + - **OpenRouter**: Get API key from [openrouter.ai/keys](https://openrouter.ai/keys) (free tier available) + +3. **Launch**: + ```bash + npm run dev + ``` + +4. Open [http://localhost:3000](http://localhost:3000) to begin. + +## Tech Stack + +- **Framework**: Next.js 15 (App Router, Turbopack) +- **Styling**: Tailwind CSS +- **State Management**: Zustand +- **Components**: shadcn/ui (Radix UI) +- **Icons**: Lucide React +- **Markdown**: react-markdown +- **Language**: TypeScript + +## Project Structure + +``` +promptarch/ + components/ + AIAssist.tsx # Main AI chat with plan-first workflow (1453 lines) + PromptEnhancer.tsx # Prompt enhancement UI with intent detection (556 lines) + SettingsPanel.tsx # Provider configuration and API key management (569 lines) + Sidebar.tsx # Navigation sidebar + GoogleAdsGenerator.tsx # Google Ads campaign generator + PRDGenerator.tsx # Product Requirements Document generator + ActionPlanGenerator.tsx # Action plan decomposition + SlidesGenerator.tsx # Presentation deck generator + MarketResearcher.tsx # Market research tool + HistoryPanel.tsx # Chat history management + lib/ + enhance-engine.ts # Modular prompt enhancement (9 strategies) + store.ts # Zustand state store + artifact-utils.ts # Preview/rendering utilities + export-utils.ts # Export to XLSX/HTML/ZIP + services/ + qwen-oauth.ts # Qwen OAuth streaming service + ollama-cloud.ts # Ollama Cloud streaming service + zai-plan.ts # Z.AI Plan streaming service + openrouter.ts # OpenRouter streaming service + model-adapter.ts # Unified provider adapter + adapter-instance.ts # Provider registry + i18n/ + translations.ts # EN/RU/HE translations + types/ + index.ts # TypeScript interfaces +``` + +## Versioning + +This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). See [CHANGELOG.md](CHANGELOG.md) for detailed release notes. + +| Version | Date | Highlights | +|---------|------|------------| +| [1.3.0](CHANGELOG.md#130---2025-03-18) | 2025-03-18 | Plan-first workflow, OpenRouter, post-coding UX, enhanced prompt engine | +| [1.2.0](CHANGELOG.md#120---2025-01-19) | 2025-01-19 | SEO agent fixes, Z.AI API validation | +| [1.1.0](CHANGELOG.md#110---2025-01-15) | 2025-01-15 | GitHub push, XLSX/HTML export, OAuth management | +| [1.0.0](CHANGELOG.md#100---2025-01-01) | 2025-01-01 | Initial release | + +## Development + +```bash +npm install # Install dependencies +npm run dev # Development server (Turbopack) +npm run build # Production build +npm start # Start production server +npm run lint # Lint code +``` + +## Attribution & Credits + +**Author**: Roman | RyzenAdvanced +- **Gitea**: [admin/PromptArch](https://github.rommark.dev/admin/PromptArch) +- **Telegram**: [@VibeCodePrompterSystem](https://t.me/VibeCodePrompterSystem) + +**Forked from**: [ClavixDev/Clavix](https://github.com/ClavixDev/Clavix) +- Visual and architectural evolution of the Clavix framework + +**Development Platform**: [TRAE.AI IDE](https://trae.ai) powered by [GLM 4.7](https://z.ai/subscribe?ic=R0K78RJKNW) + +## License + +ISC + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. diff --git a/components/AIAssist.tsx b/components/AIAssist.tsx index ca60e7a..736f017 100644 --- a/components/AIAssist.tsx +++ b/components/AIAssist.tsx @@ -366,6 +366,9 @@ function parseStreamingContent(text: string, currentAgent: string) { .replace(/\[+PREVIEW:[\w-]+:?[\w-]+?\]+[\s\S]*?(?:\[\/(?:PREVIEW|APP|WEB|SEO|CODE|DESIGN|SMM|PM|CONTENT)\]+|$)/gi, "") // Hide closing tags .replace(/\[\/(?:PREVIEW|APP|WEB|SEO|CODE|DESIGN|SMM|PM|CONTENT)\]+/gi, "") + // Hide PLAN tags from chat display + .replace(/\[PLAN\][\s\S]*?\[\/PLAN\]/gi, "") + .replace(/\[PLAN\][\s\S]*?$/gi, "") // Hide ANY partial tag sequence at the very end (greedy) .replace(/\[+[^\]]*$/g, "") .trim(); @@ -437,6 +440,41 @@ function parseStreamingContent(text: string, currentAgent: string) { return { chatDisplay, preview, agent, status, suggestedAgent }; } +// --- Plan Parser --- +function parsePlanFromResponse(text: string): { plan: Record | null; cleanedText: string } { + let plan: Record | null = null; + let cleanedText = text; + const planTagMatch = text.match(/\[PLAN\]([\s\S]*?)\[\/PLAN\]/i); + if (planTagMatch) { + try { + const d = JSON.parse(planTagMatch[1].trim()); + plan = { rawText: d.summary || d.description || "", architecture: d.architecture || "", techStack: Array.isArray(d.techStack) ? d.techStack : [], files: Array.isArray(d.files) ? d.files : [], steps: Array.isArray(d.steps) ? d.steps : [] }; + cleanedText = text.replace(/\[PLAN\][\s\S]*?\[\/PLAN\]/i, "").trim(); + return { plan, cleanedText }; + } catch (e) { /* not JSON */ } + } + const pLines = text.split("\n"); + let arch = "", stack: string[] = [], filesL: string[] = [], stepsL: string[] = [], summaryL: string[] = []; + let section = ""; + for (const ln of pLines) { + const s = ln.trim(); + if (/^#+\s*(?:technical\s*)?architecture/i.test(s)) { section = "arch"; continue; } + if (/^#+\s*(?:tech\s*stack|technologies|frameworks)/i.test(s)) { section = "stack"; continue; } + if (/^#+\s*(?:files|modules|components|pages)/i.test(s)) { section = "files"; continue; } + if (/^#+\s*(?:steps|implementation|tasks|action\s*plan|timeline)/i.test(s)) { section = "steps"; continue; } + if (/^#+/.test(s)) { if (section && section !== "summary") section = "summary"; continue; } + if (section === "arch" && s) arch += s + " "; + else if (section === "stack") { const m = s.match(/^[-*`\s]*(.+)/); if (m) stack.push(m[1].replace(/[`*_]/g, "").trim()); } + else if (section === "files") { const m = s.match(/^[-*]\s*(.+)/); if (m) filesL.push(m[1].replace(/[`*_]/g, "").trim()); } + else if (section === "steps") { const m = s.match(/\d+\.\s*(.+)/) || s.match(/^[-*]\s*(.+)/); if (m) stepsL.push(m[1].replace(/[`*_]/g, "").trim()); } + else if (!section && s && !/^#/.test(s)) summaryL.push(s); + } + if (arch || stack.length || filesL.length || stepsL.length) { + plan = { rawText: summaryL.slice(0, 10).join("\n").trim(), architecture: arch.trim(), techStack: stack, files: filesL, steps: stepsL }; + } + return { plan, cleanedText }; +} + // --- Main Component --- export default function AIAssist() { @@ -572,7 +610,7 @@ export default function AIAssist() { loadModels(); }, [selectedProvider, selectedModels, setSelectedModel]); - const handleSendMessage = async (e?: React.FormEvent, forcedPrompt?: string) => { + const handleSendMessage = async (e?: React.FormEvent, forcedPrompt?: string, isApproval?: boolean) => { if (e) e.preventDefault(); const finalInput = forcedPrompt || input; if (!finalInput.trim() || isProcessing) return; @@ -596,6 +634,8 @@ export default function AIAssist() { setInput(""); } + // Capture whether this is the initial plan phase (before any code generation) + const wasIdle = !isApproval && (assistStep === "idle" || assistStep === "plan"); setIsProcessing(true); if (assistStep === "idle") setAssistStep("plan"); @@ -650,8 +690,11 @@ export default function AIAssist() { if (preview && JSON.stringify(preview) !== JSON.stringify(lastParsedPreview)) { setPreviewData(preview); lastParsedPreview = preview; - setShowCanvas(true); - if (isPreviewRenderable(preview)) setViewMode("preview"); + // Only show canvas if NOT in initial plan phase + if (!wasIdle) { + setShowCanvas(true); + if (isPreviewRenderable(preview)) setViewMode("preview"); + } } if (agent !== currentAgent) { @@ -672,7 +715,7 @@ export default function AIAssist() { history: [...updatedHistory.slice(0, -1), lastMsg], previewData: preview || undefined, currentAgent: agent, - showCanvas: !!preview + showCanvas: !!preview && !wasIdle }); }, signal: controller.signal @@ -683,10 +726,22 @@ export default function AIAssist() { if (!response.success) throw new Error(response.error); - if (assistStep === "plan" || assistStep === "idle") { + // When this was the initial request from idle/plan, ALWAYS show plan card + if (wasIdle) { setAssistStep("plan"); - } else { + const { plan: parsedPlan } = parsePlanFromResponse(accumulated); + if (parsedPlan) { + setAiPlan(parsedPlan); + } else { + setAiPlan({ rawText: accumulated, architecture: "", techStack: [], files: [], steps: [] }); + } + } else if ((lastParsedPreview as PreviewData | null)?.data) { + // After approval: show the generated preview setAssistStep("preview"); + setShowCanvas(true); + if (isPreviewRenderable(lastParsedPreview)) setViewMode("preview"); + } else { + setAssistStep("idle"); } } catch (error) { @@ -703,7 +758,7 @@ export default function AIAssist() { const approveAndGenerate = () => { setAssistStep("generating"); - handleSendMessage(undefined, "Approved. Please generate the code according to the plan."); + handleSendMessage(undefined, "Approved. Please generate the code according to the plan.", true); }; const stopGeneration = () => { @@ -793,7 +848,7 @@ export default function AIAssist() {
- {(["qwen", "ollama", "zai"] as const).map((provider) => ( + {(["qwen", "ollama", "zai", "openrouter"] as const).map((provider) => ( ))}
@@ -1060,6 +1115,12 @@ export default function AIAssist() {
+ {aiPlan.rawText && ( +
+

{t.planSummary}

+

{aiPlan.rawText}

+
+ )}

{t.architecture}

{aiPlan.architecture}

@@ -1077,12 +1138,30 @@ export default function AIAssist() {

{t.filesPlanned(aiPlan.files?.length || 0)}

+
+ + +
@@ -1103,6 +1182,25 @@ export default function AIAssist() { {t.activateArtifact} )} + + {/* Post-coding action buttons */} + {msg.role === "assistant" && assistStep === "preview" && i === aiAssistHistory.length - 1 && !isProcessing && ( +
+ + +
+ )} {msg.role === "assistant" && isProcessing && i === aiAssistHistory.length - 1 && status && ( @@ -1137,7 +1235,7 @@ export default function AIAssist() {
setInput(e.target.value)} placeholder={t.placeholder} disabled={isProcessing} diff --git a/components/PromptEnhancer.tsx b/components/PromptEnhancer.tsx index 9acf493..1a7400e 100644 --- a/components/PromptEnhancer.tsx +++ b/components/PromptEnhancer.tsx @@ -1,14 +1,54 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Textarea } from "@/components/ui/textarea"; import useStore from "@/lib/store"; import modelAdapter from "@/lib/services/adapter-instance"; -import { Sparkles, Copy, RefreshCw, Loader2, CheckCircle2, Settings } from "lucide-react"; +import { + Sparkles, Copy, RefreshCw, Loader2, CheckCircle2, Settings, + AlertTriangle, Info, ChevronDown, ChevronUp, Target, Layers, + Zap, Brain, FileCode, Bot, Search, Image, Code, Globe +} from "lucide-react"; import { cn } from "@/lib/utils"; import { translations } from "@/lib/i18n/translations"; +import { + runDiagnostics, + detectToolCategory, + selectTemplate, + generateAnalysisReport, + estimateTokens, + type AnalysisReport, + type DiagnosticResult, + TOOL_CATEGORIES, + TEMPLATES, + type ToolCategory, +} from "@/lib/enhance-engine"; + +const toolCategoryIcons: Record = { + reasoning: Brain, + thinking: Brain, + openweight: Zap, + agentic: Bot, + ide: Code, + fullstack: Globe, + image: Image, + search: Search, +}; + +const toolCategoryNames: Record = { + reasoning: "Reasoning LLM", + thinking: "Thinking LLM", + openweight: "Open-Weight", + agentic: "Agentic AI", + ide: "IDE AI", + fullstack: "Full-Stack Gen", + image: "Image AI", + search: "Search AI", +}; + +type EnhanceMode = "quick" | "deep"; export default function PromptEnhancer() { const { @@ -34,6 +74,13 @@ export default function PromptEnhancer() { const common = translations[language].common; const [copied, setCopied] = useState(false); + const [toolCategory, setToolCategory] = useState("reasoning"); + const [templateId, setTemplateId] = useState("RTF"); + const [enhanceMode, setEnhanceMode] = useState("deep"); + const [showDiagnostics, setShowDiagnostics] = useState(false); + const [diagnostics, setDiagnostics] = useState([]); + const [analysis, setAnalysis] = useState(null); + const [autoDetected, setAutoDetected] = useState(false); const selectedModel = selectedModels[selectedProvider]; const models = availableModels[selectedProvider] || modelAdapter.getAvailableModels(selectedProvider); @@ -55,6 +102,36 @@ export default function PromptEnhancer() { } }, [selectedProvider]); + const analyzePrompt = useCallback((prompt: string) => { + if (!prompt.trim()) return; + + const report = generateAnalysisReport(prompt); + + if (!autoDetected) { + if (report.suggestedTool) setToolCategory(report.suggestedTool); + if (report.suggestedTemplate) setTemplateId(report.suggestedTemplate.framework); + setAutoDetected(true); + } + + setDiagnostics(report.diagnostics); + setAnalysis(report); + }, [autoDetected]); + + useEffect(() => { + if (!currentPrompt.trim()) { + setDiagnostics([]); + setAnalysis(null); + setAutoDetected(false); + return; + } + + const timer = setTimeout(() => { + analyzePrompt(currentPrompt); + }, 600); + + return () => clearTimeout(timer); + }, [currentPrompt, analyzePrompt]); + const loadAvailableModels = async () => { const fallbackModels = modelAdapter.getAvailableModels(selectedProvider); setAvailableModels(selectedProvider, fallbackModels); @@ -86,21 +163,28 @@ export default function PromptEnhancer() { setProcessing(true); setError(null); - console.log("[PromptEnhancer] Starting enhancement...", { selectedProvider, selectedModel, hasQwenAuth: modelAdapter.hasQwenAuth() }); + const diagnosticsText = enhanceMode === "deep" && diagnostics.length > 0 + ? diagnostics.filter(d => d.detected).map(d => `- ${d.pattern.name}: ${d.suggestion}`).join("\n") + : ""; + + const options = enhanceMode === "deep" + ? { toolCategory, template: templateId.toLowerCase(), diagnostics: diagnosticsText } + : { toolCategory: "reasoning", template: "rtf", diagnostics: "" }; try { - const result = await modelAdapter.enhancePrompt(currentPrompt, selectedProvider, selectedModel); - - console.log("[PromptEnhancer] Enhancement result:", result); + const result = await modelAdapter.enhancePrompt( + currentPrompt, + selectedProvider, + selectedModel, + options + ); if (result.success && result.data) { setEnhancedPrompt(result.data); } else { - console.error("[PromptEnhancer] Enhancement failed:", result.error); setError(result.error || t.errorEnhance); } } catch (err) { - console.error("[PromptEnhancer] Enhancement error:", err); setError(err instanceof Error ? err.message : t.errorEnhance); } finally { setProcessing(false); @@ -119,125 +203,346 @@ export default function PromptEnhancer() { setCurrentPrompt(""); setEnhancedPrompt(null); setError(null); + setDiagnostics([]); + setAnalysis(null); + setAutoDetected(false); }; + const criticalCount = diagnostics.filter(d => d.detected && d.severity === "critical").length; + const warningCount = diagnostics.filter(d => d.detected && d.severity === "warning").length; + + const toolEntries = Object.entries(TOOL_CATEGORIES) as [ToolCategory, typeof TOOL_CATEGORIES[ToolCategory]][]; + return (
- - - - - {t.title} - - - {t.description} - - - -
- -
- {(["qwen", "ollama", "zai"] as const).map((provider) => ( + {/* Left Column */} +
+ + + + + {t.title} + + + {t.description} + + + + {/* Enhancement Mode Toggle */} +
+ +
- ))} + +
-
-
- - -
- -
- -