diff --git a/AGENTIC_AUDIT_REPORT.md b/AGENTIC_AUDIT_REPORT.md
deleted file mode 100644
index 94f8ecd..0000000
--- a/AGENTIC_AUDIT_REPORT.md
+++ /dev/null
@@ -1,791 +0,0 @@
-# WP Agentic Writer - Comprehensive Agentic Audit Report
-
-**Audit Date:** January 21, 2026
-**Auditor:** Cascade AI
-**Plugin Version:** 0.1.0
-**Goal:** Evaluate "Agentic-like IDE" capabilities in WordPress Gutenberg editor
-
----
-
-## Executive Summary
-
-WP Agentic Writer is a sophisticated AI-powered writing assistant with a **solid foundation** for agentic workflows. The plugin successfully implements the core "plan-first" approach: `Scribble → Research → Plan → Execute → Refine`. However, several gaps exist between the current implementation and a truly **IDE-like agentic experience**.
-
-**Overall Agentic Score: 7.5/10**
-
-### Strengths
-- ✅ Multi-phase workflow (planning → execution)
-- ✅ Clarification quiz for context gathering
-- ✅ `@mention` system for block targeting (IDE-like)
-- ✅ Slash commands (`/add below`, `/add above`, `/append code`)
-- ✅ Real-time streaming with timeline progress
-- ✅ Section-aware refinement with context
-- ✅ Plan preview with diff-style actions
-- ✅ Cost tracking and budget management
-
-### Gaps Identified
-- ⚠️ No undo/redo for AI changes
-- ⚠️ No diff view before applying changes
-- ⚠️ No "Accept/Reject" workflow for refinements
-- ⚠️ Limited autonomous decision-making
-- ⚠️ No agent memory across sessions (post-level only)
-- ⚠️ No multi-step autonomous execution
-- ⚠️ Missing keyboard shortcuts for power users
-
----
-
-## Part 1: Current Architecture Analysis
-
-### 1.1 Core Workflow Trace
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ USER INPUT (Chat Sidebar) │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ CLARITY CHECK (if enabled) │
-│ - Evaluates 7 context categories │
-│ - Generates clarification quiz if confidence < threshold │
-│ - Categories: outcome, audience, tone, depth, expertise, │
-│ content type, POV │
-└─────────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ MODE DETECTION │
-│ - "writing" mode → Full article generation │
-│ - "planning" mode → Outline only │
-│ - Refinement detected → Chat refinement flow │
-│ - Insert command detected → Add block flow │
-└─────────────────────────────────────────────────────────────────┘
- │
- ┌───────────────┴───────────────┐
- ▼ ▼
-┌──────────────────────┐ ┌──────────────────────┐
-│ PLAN GENERATION │ │ CHAT REFINEMENT │
-│ - Stream outline │ │ - @mention resolve │
-│ - Section breakdown │ │ - Edit plan create │
-│ - Auto-execute │ │ - Block replacement │
-└──────────────────────┘ └──────────────────────┘
- │ │
- ▼ ▼
-┌─────────────────────────────────────────────────────────────────┐
-│ GUTENBERG BLOCK OPERATIONS │
-│ - createBlock(), insertBlocks(), replaceBlocks() │
-│ - Section tracking (sectionBlocksRef) │
-│ - Real-time editor updates │
-└─────────────────────────────────────────────────────────────────┘
-```
-
-### 1.2 File Structure Analysis
-
-| File | Purpose | Lines | Agentic Features |
-|------|---------|-------|------------------|
-| `sidebar.js` | Main UI + logic | 4,359 | @mentions, slash commands, plan execution |
-| `class-gutenberg-sidebar.php` | REST API + AI calls | 4,274 | Streaming, refinement, memory |
-| `class-openrouter-provider.php` | AI provider | 566 | Multi-model, web search |
-| `block-refine.js` | Toolbar integration | 115 | @chat button on blocks |
-| `sidebar.css` | Styling | 1,817 | Timeline, quiz UI |
-
-### 1.3 Agent Modes
-
-| Mode | Description | Agentic Level |
-|------|-------------|---------------|
-| **Writing** | Full article generation from prompt | ⭐⭐⭐ Medium |
-| **Planning** | Outline-only with manual execution | ⭐⭐ Low |
-| **Refinement** | Block-level changes via @mentions | ⭐⭐⭐⭐ High |
-
----
-
-## Part 2: UI/UX Analysis
-
-### 2.1 Sidebar Interface
-
-**Current Structure:**
-```
-┌─────────────────────────────────────────┐
-│ 💬 Chat │ ⚙️ Config │ 💰 Cost │ ← Tab Navigation
-├─────────────────────────────────────────┤
-│ [Status Bar - Mode + Cost] │
-├─────────────────────────────────────────┤
-│ ┌─────────────────────────────────────┐ │
-│ │ Messages Area (scrollable) │ │
-│ │ - User messages │ │
-│ │ - Assistant responses │ │
-│ │ - Timeline entries (progress) │ │
-│ │ - Plan cards │ │
-│ │ - Error messages │ │
-│ └─────────────────────────────────────┘ │
-├─────────────────────────────────────────┤
-│ ┌─────────────────────────────────────┐ │
-│ │ Input Area │ │
-│ │ - Mode selector │ │
-│ │ - Textarea with @mention support │ │
-│ │ - Send button │ │
-│ └─────────────────────────────────────┘ │
-└─────────────────────────────────────────┘
-```
-
-**✅ Good:**
-- Dark theme matches IDE aesthetic
-- Monospace fonts for code-like feel
-- Timeline progress shows "agent thinking"
-- @mention autocomplete is discoverable
-
-**❌ Issues:**
-1. **No keyboard shortcuts** - Power users expect Cmd+Enter to send
-2. **No command palette** - IDEs have Cmd+Shift+P for quick actions
-3. **Config tab is underutilized** - Only article length selector
-4. **No block outline view** - Can't see article structure at a glance
-
-### 2.2 Block Toolbar Integration
-
-**Current:** `@chat` button in block toolbar sends mention to sidebar
-
-**Issue:** The button label is just "@chat" - unclear what it does
-
-**Recommendation:** Rename to "Refine with AI" or add tooltip
-
-### 2.3 Clarification Quiz UX
-
-**Current Flow:**
-1. Quiz appears as modal overlay in chat
-2. Radio buttons for predefined options
-3. Progress bar shows completion
-4. Skip button available
-
-**✅ Good:**
-- Predefined options reduce friction
-- Progress indicator is clear
-- Fallback questions when AI fails
-
-**❌ Issues:**
-1. **No "Don't ask again" option** - Users may want to skip permanently
-2. **Quiz interrupts flow** - Could be inline instead of modal
-3. **No learning from previous posts** - Always starts fresh
-
----
-
-## Part 3: Functionality Deep Dive
-
-### 3.1 Generation Flow
-
-**Strengths:**
-- Streaming responses with real-time timeline
-- Section-by-section execution
-- Automatic title update from AI
-- Resume capability after errors
-
-**Gaps:**
-1. **No preview before insertion** - Blocks appear directly
-2. **No staged commits** - Can't review all changes before applying
-3. **No branch/version history** - Can't revert to previous state
-
-### 3.2 Refinement System
-
-**Supported Commands:**
-| Command | Action |
-|---------|--------|
-| `@this` | Current selected block |
-| `@previous` | Block before current |
-| `@next` | Block after current |
-| `@all` | All content blocks |
-| `@paragraph-N` | Nth paragraph |
-| `@heading-N` | Nth heading |
-| `@list-N` | Nth list |
-| `/add below @block` | Insert paragraph below |
-| `/add above @block` | Insert paragraph above |
-| `/append code @block` | Insert code block |
-| `/reformat @block` | Convert markdown to blocks |
-
-**✅ This is very IDE-like!**
-
-**Gaps:**
-1. **No `@code-N`** - Can't target code blocks directly
-2. **No `@image-N`** - Can't target images
-3. **No range selection** - Can't say `@paragraph-1:3` for range
-4. **No diff preview** - Changes apply immediately
-
-### 3.3 Edit Plan System
-
-**Current:**
-```javascript
-// Edit plan structure
-{
- "summary": "short summary",
- "actions": [
- {"action": "keep", "blockId": "..."},
- {"action": "replace", "blockId": "...", "blockType": "...", "content": "..."},
- {"action": "insert_after", "blockId": "...", "blockType": "...", "content": "..."},
- {"action": "delete", "blockId": "..."}
- ]
-}
-```
-
-**✅ Good:**
-- Diff-style action preview
-- Click-to-scroll to target block
-- Execute/Cancel buttons
-
-**❌ Issues:**
-1. **All-or-nothing execution** - Can't apply individual actions
-2. **No partial accept** - Can't accept some, reject others
-3. **No inline editing** - Can't modify plan before applying
-
-### 3.4 Memory System
-
-**Current:**
-- Post-level memory stored in `_wpaw_memory` meta
-- Contains: summary, last_prompt, last_intent
-- Chat history persisted per post
-
-**Gaps:**
-1. **No global memory** - Can't learn user preferences across posts
-2. **No style guide storage** - Can't save writing style preferences
-3. **No context from other posts** - Can't reference previous work
-
----
-
-## Part 4: Agentic Gaps & Recommendations
-
-### 4.1 Critical Missing Features (High Priority)
-
-#### 4.1.1 Undo/Redo for AI Changes
-**Problem:** No way to revert AI changes without manual Cmd+Z
-**Solution:**
-```javascript
-// Add undo stack for AI operations
-const aiUndoStack = [];
-
-const executeWithUndo = (operation) => {
- const snapshot = captureEditorState();
- aiUndoStack.push(snapshot);
- operation();
-};
-
-// UI: Add "Undo AI" button in timeline entries
-```
-
-#### 4.1.2 Diff View Before Apply
-**Problem:** Users can't see what will change before it happens
-**Solution:**
-- Add "Preview Changes" mode
-- Show side-by-side or inline diff
-- GitHub-style green/red highlighting
-
-#### 4.1.3 Accept/Reject Workflow
-**Problem:** Changes apply immediately with no approval
-**Solution:**
-```
-┌─────────────────────────────────────────┐
-│ AI suggests: Replace paragraph 3 │
-│ │
-│ Before: "The old content..." │
-│ After: "The new content..." │
-│ │
-│ [Accept] [Reject] [Edit] [Skip] │
-└─────────────────────────────────────────┘
-```
-
-### 4.2 Agentic Enhancements (Medium Priority)
-
-#### 4.2.1 Autonomous Multi-Step Execution
-**Current:** User must approve each step
-**Agentic:** Agent completes entire task autonomously
-
-**Recommendation:** Add "Full Auto" mode
-```javascript
-const agentModes = {
- 'supervised': 'Approve each change', // Current
- 'semi-auto': 'Approve plan, auto-execute', // New
- 'full-auto': 'Complete task autonomously' // New (advanced)
-};
-```
-
-#### 4.2.2 Agent Memory & Learning
-**Current:** No learning across sessions
-**Agentic:** Remember user preferences, writing style
-
-**Recommendation:**
-```php
-// Global user preferences in wp_usermeta
-update_user_meta($user_id, '_wpaw_preferences', [
- 'tone' => 'professional',
- 'avoid_words' => ['leverage', 'synergy'],
- 'preferred_length' => 'medium',
- 'always_include' => ['code examples'],
-]);
-```
-
-#### 4.2.3 Context-Aware Suggestions
-**Current:** Agent only responds to commands
-**Agentic:** Agent proactively suggests improvements
-
-**Recommendation:**
-- Analyze article on idle
-- Suggest improvements in sidebar
-- "I noticed paragraph 3 could be clearer. Want me to refine it?"
-
-### 4.3 IDE-Like Features (Medium Priority)
-
-#### 4.3.1 Keyboard Shortcuts
-| Shortcut | Action |
-|----------|--------|
-| `Cmd+Enter` | Send message |
-| `Cmd+Shift+P` | Command palette |
-| `Cmd+/` | Quick refine selected block |
-| `Cmd+G` | Generate from selection |
-| `Escape` | Cancel current operation |
-
-#### 4.3.2 Command Palette
-```
-┌─────────────────────────────────────────┐
-│ > _ │
-├─────────────────────────────────────────┤
-│ 📝 Generate article from prompt │
-│ ✏️ Refine selected block │
-│ 📋 Create outline only │
-│ 🔄 Regenerate current section │
-│ 🌐 Enable web search │
-│ ⚙️ Open settings │
-└─────────────────────────────────────────┘
-```
-
-#### 4.3.3 Block Outline Panel
-```
-┌─────────────────────────────────────────┐
-│ ARTICLE STRUCTURE │
-├─────────────────────────────────────────┤
-│ ▼ Introduction │
-│ ├─ paragraph-1 │
-│ └─ paragraph-2 │
-│ ▼ Getting Started │
-│ ├─ heading-2 │
-│ ├─ paragraph-3 │
-│ └─ code-1 │
-│ ▼ Advanced Usage │
-│ ├─ heading-3 │
-│ └─ list-1 │
-└─────────────────────────────────────────┘
-```
-
-### 4.4 UX Improvements (Lower Priority)
-
-#### 4.4.1 Inline Refinement
-**Current:** Must use sidebar for all refinements
-**Improvement:** Click block → inline popover with quick actions
-
-#### 4.4.2 Streaming Preview
-**Current:** Content appears in editor directly
-**Improvement:** Show in preview pane first, then "Apply All"
-
-#### 4.4.3 Smart Suggestions Bar
-Show contextual actions based on selection:
-```
-┌─────────────────────────────────────────┐
-│ 💡 Make concise │ 🔄 Rephrase │ 📝 Expand │
-└─────────────────────────────────────────┘
-```
-
----
-
-## Part 5: Technical Debt & Code Quality
-
-### 5.1 Identified Issues
-
-1. **`sidebar.js` is 4,359 lines** - Should be split into modules
-2. **Mixed concerns** - UI, state, API calls in same file
-3. **No TypeScript** - Type safety would prevent bugs
-4. **Hardcoded strings** - Should use i18n throughout
-
-### 5.2 Recommendations
-
-1. **Modularize sidebar.js:**
- - `hooks/useChat.js`
- - `hooks/usePlan.js`
- - `hooks/useRefinement.js`
- - `components/ChatTab.js`
- - `components/ConfigTab.js`
- - `utils/blockHelpers.js`
-
-2. **Add error boundaries** - React error boundaries for graceful failures
-
-3. **Implement proper state management** - Consider Redux or Zustand
-
----
-
-## Part 6: Prioritized Action Items
-
-### Tier 1: Critical (Do First)
-| Item | Effort | Impact | Status |
-|------|--------|--------|--------|
-| Add Undo for AI changes | Medium | High | ❌ Not Implemented |
-| Add Accept/Reject workflow | Medium | High | ✅ Implemented (Apply/Cancel buttons) |
-| Add Cmd+Enter to send | Low | Medium | ✅ Implemented (line 2326 sidebar.js) |
-| Add diff preview for edit plans | Medium | High | ✅ Implemented (edit_plan type with before/after) |
-
-> **Note:** Cross-verified on Jan 21, 2026. Only **Undo for AI changes** remains to be implemented in Tier 1.
-
-### Tier 2: Important (Do Next)
-| Item | Effort | Impact |
-|------|--------|--------|
-| Command palette (Cmd+Shift+P) | Medium | High |
-| Per-action accept/reject in plans | Medium | Medium |
-| Block outline panel | Medium | Medium |
-| Global user preferences | Low | Medium |
-
-### Tier 3: Nice to Have
-| Item | Effort | Impact |
-|------|--------|--------|
-| Inline refinement popover | High | Medium |
-| Streaming preview pane | High | Medium |
-| Smart suggestions bar | Medium | Low |
-| Full-auto mode | High | Low |
-
----
-
-## Part 7: Conclusion
-
-### What's Already Agentic ✅
-1. **@mention system** - Best-in-class block targeting
-2. **Slash commands** - IDE-like quick actions
-3. **Clarification quiz** - Proactive context gathering
-4. **Edit plan preview** - Shows intent before action
-5. **Section tracking** - Maintains document structure
-
-### What's Missing for True Agentic ❌
-1. **Approval workflow** - Changes should be reviewable
-2. **Undo/history** - Need to revert AI mistakes
-3. **Autonomous execution** - Agent should complete tasks independently
-4. **Learning/memory** - Should improve over time
-5. **Keyboard-first UX** - Power users need shortcuts
-
-### Final Recommendation
-
-The plugin has **strong agentic bones** but needs the **safety net** features that make IDEs trustworthy:
-
-1. **Immediate wins:** Keyboard shortcuts + Undo button
-2. **Medium-term:** Accept/Reject workflow + Command palette
-3. **Long-term:** Autonomous mode + Learning system
-
-The goal should be: *"I can trust this agent to make changes because I can always review, approve, or revert."*
-
----
-
-## Part 8: Proactive AI Suggestions (NEW REQUIREMENT)
-
-### 8.1 Current State
-**Problem:** Agent only responds to commands - purely reactive.
-
-### 8.2 Target State
-**Goal:** Agent proactively analyzes content and suggests improvements.
-
-### 8.3 Implementation Specification
-
-#### 8.3.1 Idle Analysis Trigger
-```javascript
-// Trigger analysis after user stops editing for N seconds
-const IDLE_THRESHOLD_MS = 5000; // 5 seconds
-let idleTimer = null;
-
-const startIdleAnalysis = () => {
- clearTimeout(idleTimer);
- idleTimer = setTimeout(() => {
- analyzeArticleForSuggestions();
- }, IDLE_THRESHOLD_MS);
-};
-
-// Hook into editor changes
-wp.data.subscribe(() => {
- startIdleAnalysis();
-});
-```
-
-#### 8.3.2 Suggestion Types
-| Category | Example Suggestion |
-|----------|--------------------|
-| **Clarity** | "Paragraph 3 could be clearer. Want me to simplify it?" |
-| **Flow** | "The transition between sections 2 and 3 feels abrupt." |
-| **Depth** | "This section could use more examples or data." |
-| **SEO** | "Consider adding keyword 'X' to heading 2." |
-| **Structure** | "This article could benefit from a summary section." |
-| **Engagement** | "Consider adding a question to engage readers here." |
-
-#### 8.3.3 UI Component
-```
-┌─────────────────────────────────────────────────┐
-│ 💡 Suggestion │
-│ │
-│ "I noticed paragraph 3 could be clearer. │
-│ Want me to refine it?" │
-│ │
-│ [Apply] [Dismiss] [Don't show again] │
-└─────────────────────────────────────────────────┘
-```
-
-#### 8.3.4 Backend Endpoint
-```php
-// New REST endpoint: /analyze-for-suggestions
-public function analyze_for_suggestions() {
- $blocks = $this->get_all_blocks();
- $prompt = "Analyze this article and suggest 1-3 improvements...";
- // Return structured suggestions
-}
-```
-
-#### 8.3.5 User Preferences
-- Toggle: "Enable proactive suggestions"
-- Frequency: "Aggressive / Balanced / Minimal"
-- Categories: Checkboxes for which suggestion types to show
-
----
-
-## Part 9: SEO Specialist Capabilities (NEW REQUIREMENT)
-
-### 9.1 Vision
-Agentic Writer should not only write well but write **SEO-optimized content** that ranks.
-
-### 9.2 SEO Feature Matrix
-
-| Feature | Description | Priority |
-|---------|-------------|----------|
-| **Keyword Analysis** | Analyze target keyword, suggest density | High |
-| **Keyword Placement** | Ensure keyword in title, H1, first paragraph | High |
-| **Heading Structure** | Validate H1→H2→H3 hierarchy | High |
-| **Meta Generation** | Auto-generate meta title & description | High |
-| **Readability Score** | Flesch-Kincaid or similar | Medium |
-| **Internal Linking** | Suggest links to other posts | Medium |
-| **Image Alt Text** | Auto-generate SEO-friendly alt text | Medium |
-| **Schema Markup** | Suggest FAQ, HowTo, Article schema | Medium |
-| **Competitor Analysis** | Compare with top-ranking articles | Low |
-| **SERP Preview** | Show how it will appear in Google | Low |
-
-### 9.3 SEO Workflow Integration
-
-#### 9.3.1 Pre-Writing Phase
-```
-┌─────────────────────────────────────────────────┐
-│ 🎯 SEO Setup │
-│ │
-│ Target Keyword: [_______________] │
-│ Secondary Keywords: [_______________] │
-│ │
-│ ☑ Analyze competition before writing │
-│ ☑ Include keyword in title │
-│ ☑ Suggest internal links │
-│ │
-│ [Analyze Competition] [Skip to Writing] │
-└─────────────────────────────────────────────────┘
-```
-
-#### 9.3.2 During Writing (Real-time)
-- **Keyword density indicator** in sidebar
-- **Heading structure validator**
-- **Reading time & word count**
-- **Readability score (live)**
-
-#### 9.3.3 Post-Writing (SEO Audit)
-```
-┌─────────────────────────────────────────────────┐
-│ 📊 SEO Score: 78/100 │
-│ │
-│ ✅ Keyword in title │
-│ ✅ Keyword in first paragraph │
-│ ⚠️ Keyword density low (0.8%, target 1-2%) │
-│ ❌ Missing meta description │
-│ ❌ No internal links found │
-│ ✅ Proper heading hierarchy │
-│ ⚠️ Images missing alt text (2 of 3) │
-│ │
-│ [Fix All Issues] [Generate Meta] [Add Links] │
-└─────────────────────────────────────────────────┘
-```
-
-### 9.4 SEO-Aware System Prompts
-
-Modify the plan generation prompt to include SEO considerations:
-
-```
-You are an SEO-optimized content writer. When creating content:
-
-1. KEYWORD PLACEMENT:
- - Include target keyword in H1 and first 100 words
- - Use keyword naturally 1-2% density
- - Include semantic variations
-
-2. STRUCTURE:
- - Use proper heading hierarchy (H1→H2→H3)
- - Include table of contents for long articles
- - Use bullet points and numbered lists
- - Keep paragraphs under 150 words
-
-3. ENGAGEMENT:
- - Start with a hook
- - Use questions to engage readers
- - Include actionable takeaways
-
-4. TECHNICAL:
- - Suggest descriptive image alt text
- - Recommend internal link opportunities
- - Optimize for featured snippets where applicable
-```
-
-### 9.5 Post Config Additions
-
-```javascript
-const seoConfig = {
- target_keyword: '',
- secondary_keywords: [],
- enable_seo_mode: true,
- keyword_density_target: 1.5, // percentage
- min_word_count: 1500,
- include_meta: true,
- include_schema: false,
- internal_linking: true,
-};
-```
-
-### 9.6 New REST Endpoints
-
-| Endpoint | Purpose |
-|----------|--------|
-| `/seo/analyze-keyword` | Get keyword difficulty, volume |
-| `/seo/audit-content` | Full SEO audit of current content |
-| `/seo/generate-meta` | Generate meta title/description |
-| `/seo/suggest-links` | Find internal linking opportunities |
-| `/seo/competitor-analysis` | Analyze top-ranking content |
-
----
-
-## Part 10: AI Model Recommendations (NEW REQUIREMENT)
-
-### 10.1 Purpose
-Help users choose the **cheapest AND best** models for agentic workflows.
-
-### 10.2 Model Tiers by Use Case
-
-#### 10.2.1 Planning Phase (Fast, Cheap)
-| Model | Cost (per 1M tokens) | Speed | Quality | Recommendation |
-|-------|---------------------|-------|---------|----------------|
-| `google/gemini-2.0-flash-exp` | ~$0.10 in / $0.40 out | ⚡ Very Fast | Good | **Best Value** |
-| `google/gemini-flash-1.5` | ~$0.075 in / $0.30 out | ⚡ Very Fast | Good | Budget Option |
-| `anthropic/claude-3-haiku` | ~$0.25 in / $1.25 out | Fast | Good | Reliable |
-| `openai/gpt-4o-mini` | ~$0.15 in / $0.60 out | Fast | Good | Alternative |
-
-#### 10.2.2 Execution Phase (Quality Critical)
-| Model | Cost (per 1M tokens) | Speed | Quality | Recommendation |
-|-------|---------------------|-------|---------|----------------|
-| `anthropic/claude-sonnet-4` | ~$3 in / $15 out | Medium | Excellent | **Best for Writing** |
-| `anthropic/claude-3.5-sonnet` | ~$3 in / $15 out | Medium | Excellent | Proven Quality |
-| `openai/gpt-4o` | ~$2.50 in / $10 out | Medium | Excellent | Alternative |
-| `google/gemini-pro-1.5` | ~$1.25 in / $5 out | Medium | Very Good | Cost-Conscious |
-
-#### 10.2.3 Image Generation
-| Model | Cost (per image) | Speed | Quality | Recommendation |
-|-------|-----------------|-------|---------|----------------|
-| `black-forest-labs/flux-schnell` | ~$0.003 | ⚡ Very Fast | Good | **Best Value** |
-| `black-forest-labs/flux-1.1-pro` | ~$0.04 | Fast | Excellent | Premium |
-| `openai/dall-e-3` | ~$0.04-0.08 | Medium | Excellent | Alternative |
-
-### 10.3 Recommended Configurations
-
-#### 10.3.1 Budget-Conscious Setup (~$0.05 per article)
-```
-Planning Model: google/gemini-2.0-flash-exp
-Execution Model: google/gemini-pro-1.5
-Image Model: black-forest-labs/flux-schnell
-```
-
-#### 10.3.2 Balanced Setup (~$0.15 per article)
-```
-Planning Model: google/gemini-2.0-flash-exp
-Execution Model: anthropic/claude-3.5-sonnet
-Image Model: black-forest-labs/flux-schnell
-```
-
-#### 10.3.3 Premium Quality Setup (~$0.30+ per article)
-```
-Planning Model: anthropic/claude-3-haiku
-Execution Model: anthropic/claude-sonnet-4
-Image Model: black-forest-labs/flux-1.1-pro
-```
-
-### 10.4 Model Selection UI
-
-```
-┌─────────────────────────────────────────────────┐
-│ 🤖 Model Configuration │
-│ │
-│ Preset: [Budget ▾] [Balanced ▾] [Premium ▾] │
-│ │
-│ Planning Model: │
-│ [google/gemini-2.0-flash-exp ▾] │
-│ 💰 ~$0.10/1M tokens • ⚡ Fast │
-│ │
-│ Execution Model: │
-│ [anthropic/claude-sonnet-4 ▾] │
-│ 💰 ~$3/1M tokens • ✨ Best Quality │
-│ │
-│ Image Model: │
-│ [black-forest-labs/flux-schnell ▾] │
-│ 💰 ~$0.003/image • ⚡ Fast │
-│ │
-│ Estimated cost per article: ~$0.15 │
-└─────────────────────────────────────────────────┘
-```
-
-### 10.5 Smart Model Suggestions
-
-The plugin should analyze usage patterns and suggest:
-
-1. **If budget is tight:**
- > "You've spent $45 this month. Switch to Budget preset to save ~60%."
-
-2. **If quality issues detected:**
- > "Multiple refinements on recent articles. Consider upgrading execution model."
-
-3. **If speed is priority:**
- > "For faster generation, switch planning to Gemini Flash."
-
----
-
-## Part 11: Updated Roadmap
-
-### Phase 1: Complete Tier 1 ✅ COMPLETED
-- [x] Cmd+Enter to send
-- [x] Accept/Reject workflow (Apply/Cancel)
-- [x] Diff preview for edit plans
-- [x] **Undo for AI changes** (sidebar.js: aiUndoStack, pushUndoSnapshot, undoLastAiOperation)
-- [x] **Budget tracker enhanced** (Cost tab with refresh, remaining display, warnings)
-- [x] **Settings page revamp** (Modern card-based UI with preset configurations)
-
-### Phase 2: SEO Foundation ✅ COMPLETED
-- [x] Add SEO config fields (focus keyword, secondary keywords, meta description)
-- [x] Integrate SEO considerations into system prompts (build_seo_context)
-- [x] Add keyword density indicator (in SEO audit)
-- [x] Add SEO audit endpoint (/seo-audit/{post_id})
-- [x] Add meta generation (/generate-meta with AI)
-
-### Phase 3: Proactive Suggestions (2-3 weeks)
-- [ ] Implement idle detection
-- [ ] Create suggestion analysis endpoint
-- [ ] Add suggestion UI component
-- [ ] Add user preferences for suggestions
-
-### Phase 4: Model Recommendations ✅ COMPLETED
-- [x] Add preset configurations (Budget, Balanced, Premium)
-- [x] Add model selection UI with cost estimates
-- [ ] Add smart suggestions based on usage
-
-### Phase 5: Tier 2 Features (3-4 weeks)
-- [ ] Command palette (Cmd+Shift+P)
-- [ ] Per-action accept/reject in plans
-- [ ] Block outline panel
-- [ ] Global user preferences
-
----
-
-**Report Updated:** January 22, 2026
-**Implementation Status:** Phase 1, Phase 2 (SEO Foundation) & Phase 4 completed. Ready for Phase 3 (Proactive Suggestions).
diff --git a/AGENTIC_CONTEXT_STRATEGY.md b/AGENTIC_CONTEXT_STRATEGY.md
deleted file mode 100644
index 7e7e27b..0000000
--- a/AGENTIC_CONTEXT_STRATEGY.md
+++ /dev/null
@@ -1,786 +0,0 @@
-# Agentic Context Management Strategy
-
-**Date:** January 25, 2026
-**Version:** 0.1.3+
-**Purpose:** AI-powered context management for multilingual, intelligent user experience
-
----
-
-## 🎯 Core Philosophy: Let AI Handle AI Context
-
-### **The Problem with Hardcoded Solutions**
-
-**Previous Approach (FLAWED):**
-```javascript
-// ❌ English-only, brittle, not scalable
-if (content.includes('outline') || content.includes('structure')) {
- return 'create_outline';
-}
-```
-
-**Issues:**
-- ❌ Only works in English
-- ❌ Breaks in Indonesian, Arabic, Chinese, etc.
-- ❌ Misses nuanced intent
-- ❌ Requires constant maintenance
-- ❌ Goes against "agentic" philosophy
-
-### **Agentic Principle**
-
-> **"If AI is smart enough to write articles, it's smart enough to manage its own context."**
-
-**New Approach:**
-- ✅ Use AI to summarize chat history
-- ✅ Use AI to detect user intent
-- ✅ Language-agnostic (works in any language)
-- ✅ Adapts to context automatically
-- ✅ True "agentic" experience
-
----
-
-## 💰 Cost Analysis: AI-Powered Context Management
-
-### **Your Cost Reference**
-
-```
-Action: meta_description
-Model: deepseek-chat-v3-032
-Tokens: 510
-Cost: $0.0001
-```
-
-**This is EXTREMELY cheap!** Let's use this model for context operations.
-
-### **Proposed Actions**
-
-#### **1. Action: `summarize_context`**
-
-**Purpose:** Condense long chat history into key points
-
-**Input:**
-```json
-{
- "action": "summarize_context",
- "chat_history": [
- {"role": "user", "content": "Saya ingin menulis tentang keamanan WordPress"},
- {"role": "assistant", "content": "[Long response in Indonesian...]"},
- {"role": "user", "content": "Fokus pada plugin vulnerabilities saja"},
- {"role": "assistant", "content": "[Detailed plugin security response...]"}
- ]
-}
-```
-
-**Prompt:**
-```
-Summarize this conversation into key points that capture the user's intent and requirements.
-Focus on:
-- Main topic
-- Specific focus areas
-- Rejected/excluded topics
-- User preferences (tone, audience, etc.)
-
-Keep the summary concise (max 200 words) but preserve critical context.
-Write in the same language as the conversation.
-
-Output format:
-TOPIC: [main topic]
-FOCUS: [what to include]
-EXCLUDE: [what to avoid]
-PREFERENCES: [any specific requirements]
-```
-
-**Expected Output:**
-```
-TOPIC: WordPress security
-FOCUS: Plugin vulnerabilities only
-EXCLUDE: Performance optimization, backup strategies (user rejected these)
-PREFERENCES: Technical audience, detailed explanations
-```
-
-**Cost Estimate:**
-- Input: 4,000 tokens (long chat history)
-- Output: 100 tokens (summary)
-- Model: deepseek-chat-v3-032
-- **Cost: ~$0.0001 per summarization**
-
-**When to Use:**
-- Chat history > 6 messages
-- Before generating outline
-- Before executing article
-
----
-
-#### **2. Action: `detect_intent`**
-
-**Purpose:** Understand what user wants to do next
-
-**Input:**
-```json
-{
- "action": "detect_intent",
- "last_message": "Baiklah, sekarang buatkan outline-nya",
- "has_plan": false,
- "current_mode": "chat"
-}
-```
-
-**Prompt:**
-```
-Based on the user's message, determine their intent. Choose ONE:
-
-1. "create_outline" - User wants to create an article outline/structure
-2. "start_writing" - User wants to write the full article
-3. "refine_content" - User wants to improve existing content
-4. "continue_chat" - User wants to continue discussing/exploring
-5. "clarify" - User is asking questions or needs clarification
-
-Consider:
-- The user's explicit request
-- Whether they have an outline already (has_plan: {has_plan})
-- Current mode (current_mode: {current_mode})
-
-Respond with ONLY the intent code (e.g., "create_outline").
-```
-
-**Expected Output:**
-```
-create_outline
-```
-
-**Cost Estimate:**
-- Input: 100 tokens (last message + context)
-- Output: 5 tokens (intent code)
-- Model: deepseek-chat-v3-032
-- **Cost: ~$0.00002 per detection**
-
-**When to Use:**
-- After every user message in Chat mode
-- To show contextual action buttons
-- To auto-suggest next steps
-
----
-
-## 📊 Cost Comparison: Full History vs AI-Powered
-
-### **Scenario: 5 Agent + 4 Human Messages**
-
-| Approach | Input Tokens | Output Tokens | Cost per Request | Quality | Language Support |
-|----------|--------------|---------------|------------------|---------|------------------|
-| **Full History** | 4,365 | 0 | $0.013 (Claude) | ✅ Best | ✅ All |
-| **AI Summarization** | 100 (summary) | 0 | $0.003 (Claude) + $0.0001 (summary) | ✅ Good | ✅ All |
-| **Hardcoded Pruning** | 1,800 | 0 | $0.005 (Claude) | ⚠️ Fair | ❌ English only |
-| **No Context** | 0 | 0 | $0.000 | ❌ Poor | ✅ All |
-
-### **Cost Breakdown for 100 Articles/Month**
-
-**Full History:**
-- Planning: 100 × $0.00033 = $0.033
-- Execution: 100 × $0.013 = $1.30
-- **Total: $1.33/month**
-
-**AI Summarization:**
-- Summarization: 100 × $0.0001 = $0.01
-- Planning: 100 × $0.00008 = $0.008
-- Execution: 100 × $0.003 = $0.30
-- **Total: $0.32/month**
-- **Savings: $1.01/month (76% reduction)**
-
-**Intent Detection:**
-- Per message: $0.00002
-- Average 10 messages per article: 100 × 10 × $0.00002 = $0.02
-- **Total: $0.02/month (negligible)**
-
----
-
-## 🎯 The Big Picture: Agentic Experience
-
-### **User Journey Analysis**
-
-**Current Flow (Fragmented):**
-```
-1. User opens editor
-2. User manually switches to Chat mode
-3. User types message
-4. Agent responds
-5. User types more
-6. Agent responds
-7. User manually switches to Planning mode
-8. User types "create outline"
-9. Outline generated
-10. User manually clicks "Start Writing"
-11. Article generated
-```
-
-**Problems:**
-- Too many manual mode switches
-- User must know when to switch
-- No guidance on next steps
-- Friction in workflow
-
----
-
-### **Proposed Agentic Flow (Seamless):**
-
-```
-1. User opens editor (any mode)
-2. User types: "Saya ingin menulis tentang keamanan WordPress"
-3. Agent responds with suggestions
-4. User types: "Fokus pada plugin vulnerabilities"
-5. Agent responds with refined ideas
-6. 💡 UI shows: [📝 Ready to create outline?] (AI-detected intent)
-7. User clicks button (or types "yes" or "buatkan outline")
-8. ✨ AI summarizes chat history (0.1 seconds)
-9. Outline generated with clean context
-10. 💡 UI shows: [✍️ Start Writing] (auto-suggested)
-11. User clicks
-12. Article generated
-```
-
-**Improvements:**
-- ✅ No manual mode switching needed
-- ✅ AI suggests next steps proactively
-- ✅ Context automatically optimized
-- ✅ Smooth, guided experience
-- ✅ Works in any language
-
----
-
-## 🔧 Implementation Design
-
-### **Backend: New Actions**
-
-```php
-/**
- * Handle context summarization request.
- *
- * @param WP_REST_Request $request REST request.
- * @return WP_REST_Response|WP_Error Response.
- */
-public function handle_summarize_context( $request ) {
- $params = $request->get_json_params();
- $chat_history = $params['chatHistory'] ?? array();
-
- if ( empty( $chat_history ) || count( $chat_history ) < 4 ) {
- // No need to summarize short history
- return new WP_REST_Response(
- array(
- 'summary' => '',
- 'use_full_history' => true,
- ),
- 200
- );
- }
-
- // Build summarization prompt
- $history_text = '';
- foreach ( $chat_history as $msg ) {
- $role = ucfirst( $msg['role'] ?? 'Unknown' );
- $content = $msg['content'] ?? '';
- $history_text .= "{$role}: {$content}\n\n";
- }
-
- $prompt = "Summarize this conversation into key points that capture the user's intent and requirements.
-
-Focus on:
-- Main topic
-- Specific focus areas
-- Rejected/excluded topics
-- User preferences (tone, audience, etc.)
-
-Keep the summary concise (max 200 words) but preserve critical context.
-Write in the same language as the conversation.
-
-Output format:
-TOPIC: [main topic]
-FOCUS: [what to include]
-EXCLUDE: [what to avoid]
-PREFERENCES: [any specific requirements]
-
-Conversation:
-{$history_text}";
-
- $provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
- $messages = array(
- array(
- 'role' => 'user',
- 'content' => $prompt,
- ),
- );
-
- // Use cheap model for summarization
- $response = $provider->chat( $messages, array(), 'summarize' );
-
- if ( is_wp_error( $response ) ) {
- return $response;
- }
-
- // Track cost
- do_action(
- 'wp_aw_after_api_request',
- $params['postId'] ?? 0,
- $response['model'] ?? '',
- 'summarize_context',
- $response['input_tokens'] ?? 0,
- $response['output_tokens'] ?? 0,
- $response['cost'] ?? 0
- );
-
- return new WP_REST_Response(
- array(
- 'summary' => $response['content'] ?? '',
- 'use_full_history' => false,
- 'cost' => $response['cost'] ?? 0,
- ),
- 200
- );
-}
-
-/**
- * Handle intent detection request.
- *
- * @param WP_REST_Request $request REST request.
- * @return WP_REST_Response|WP_Error Response.
- */
-public function handle_detect_intent( $request ) {
- $params = $request->get_json_params();
- $last_message = $params['lastMessage'] ?? '';
- $has_plan = $params['hasPlan'] ?? false;
- $current_mode = $params['currentMode'] ?? 'chat';
-
- if ( empty( $last_message ) ) {
- return new WP_REST_Response(
- array( 'intent' => 'continue_chat' ),
- 200
- );
- }
-
- $prompt = "Based on the user's message, determine their intent. Choose ONE:
-
-1. \"create_outline\" - User wants to create an article outline/structure
-2. \"start_writing\" - User wants to write the full article
-3. \"refine_content\" - User wants to improve existing content
-4. \"continue_chat\" - User wants to continue discussing/exploring
-5. \"clarify\" - User is asking questions or needs clarification
-
-Consider:
-- The user's explicit request
-- Whether they have an outline already (has_plan: " . ( $has_plan ? 'true' : 'false' ) . ")
-- Current mode (current_mode: {$current_mode})
-
-User's message: \"{$last_message}\"
-
-Respond with ONLY the intent code (e.g., \"create_outline\").";
-
- $provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
- $messages = array(
- array(
- 'role' => 'user',
- 'content' => $prompt,
- ),
- );
-
- $response = $provider->chat( $messages, array(), 'intent_detection' );
-
- if ( is_wp_error( $response ) ) {
- return $response;
- }
-
- // Track cost
- do_action(
- 'wp_aw_after_api_request',
- $params['postId'] ?? 0,
- $response['model'] ?? '',
- 'detect_intent',
- $response['input_tokens'] ?? 0,
- $response['output_tokens'] ?? 0,
- $response['cost'] ?? 0
- );
-
- $intent = trim( strtolower( $response['content'] ?? 'continue_chat' ) );
-
- return new WP_REST_Response(
- array(
- 'intent' => $intent,
- 'cost' => $response['cost'] ?? 0,
- ),
- 200
- );
-}
-```
-
----
-
-### **Frontend: Agentic UX**
-
-```javascript
-// Auto-detect intent after each message
-const handleMessageSent = async (userMessage) => {
- // Send message to chat
- const chatResponse = await sendChatMessage(userMessage);
-
- // Detect intent in background
- const intentResponse = await fetch('/wp-json/wp-agentic-writer/v1/detect-intent', {
- method: 'POST',
- body: JSON.stringify({
- lastMessage: userMessage,
- hasPlan: !!currentPlan,
- currentMode: agentMode,
- postId: postId
- })
- });
-
- const { intent } = await intentResponse.json();
-
- // Show contextual action based on intent
- setDetectedIntent(intent);
- showContextualAction(intent);
-};
-
-// Render contextual action buttons
-const renderContextualAction = () => {
- if (!detectedIntent) return null;
-
- switch (detectedIntent) {
- case 'create_outline':
- return (
-
-
💡 Ready to create an outline?
-
-
- );
-
- case 'start_writing':
- if (!currentPlan) {
- return (
-
-
⚠️ You need an outline first
-
-
- );
- }
- return (
-
-
💡 Ready to write the article?
-
-
- );
-
- case 'refine_content':
- return (
-
-
💡 Use @block to refine specific sections
-
- );
-
- default:
- return null;
- }
-};
-
-// Create outline with AI summarization
-const handleCreateOutlineWithSummary = async () => {
- setIsLoading(true);
-
- // Step 1: Summarize chat history if needed
- let contextToSend = messages;
-
- if (messages.length > 6) {
- showStatus('Optimizing context...');
-
- const summaryResponse = await fetch('/wp-json/wp-agentic-writer/v1/summarize-context', {
- method: 'POST',
- body: JSON.stringify({
- chatHistory: messages,
- postId: postId
- })
- });
-
- const { summary, use_full_history, cost } = await summaryResponse.json();
-
- if (!use_full_history && summary) {
- // Use summarized context
- contextToSend = [
- {
- role: 'system',
- content: `Context Summary:\n${summary}`
- },
- ...messages.slice(-2) // Keep last exchange
- ];
-
- console.log('Context optimized. Cost:', cost);
- }
- }
-
- // Step 2: Generate outline with optimized context
- showStatus('Creating outline...');
-
- const outlineResponse = await fetch('/wp-json/wp-agentic-writer/v1/generate-plan', {
- method: 'POST',
- body: JSON.stringify({
- topic: extractTopic(messages),
- chatHistory: contextToSend,
- postId: postId,
- postConfig: postConfig,
- stream: true
- })
- });
-
- // Handle streaming response...
-};
-```
-
----
-
-## 🎨 UX Enhancements
-
-### **1. Contextual Action Cards**
-
-```
-┌─────────────────────────────────────────────────────┐
-│ Agent: "I can help you create a comprehensive │
-│ outline for WordPress plugin security..." │
-├─────────────────────────────────────────────────────┤
-│ 💡 Detected Intent: Create Outline │
-│ │
-│ [📝 Create Outline] [💬 Continue Discussing] │
-│ │
-│ 💰 Context will be optimized (~$0.0001) │
-└─────────────────────────────────────────────────────┘
-```
-
-### **2. Context Optimization Indicator**
-
-```
-┌─────────────────────────────────────────────────────┐
-│ ⚡ Optimizing context... │
-│ • 9 messages → Summary (200 words) │
-│ • Token reduction: 4,365 → 450 (90%) │
-│ • Cost: $0.0001 │
-│ ✓ Done in 0.2s │
-└─────────────────────────────────────────────────────┘
-```
-
-### **3. Smart Mode Transitions**
-
-```
-User in Chat mode types: "buatkan outline-nya"
-
-┌─────────────────────────────────────────────────────┐
-│ 💡 Switching to Planning mode... │
-│ • Detected intent: Create outline │
-│ • Optimizing 7 messages of context │
-│ • Generating outline... │
-└─────────────────────────────────────────────────────┘
-
-[Outline appears]
-
-┌─────────────────────────────────────────────────────┐
-│ ✨ Outline ready! │
-│ │
-│ Next step: │
-│ [✍️ Start Writing Article] │
-└─────────────────────────────────────────────────────┘
-```
-
----
-
-## 📊 Decision Matrix: When to Use What?
-
-| Situation | Recommended Approach | Reason |
-|-----------|---------------------|--------|
-| **Chat history ≤ 4 messages** | Send full history | Short enough, no optimization needed |
-| **Chat history 5-8 messages** | AI summarization | Balance cost and quality |
-| **Chat history > 8 messages** | AI summarization + last 2 | Keep recent context verbatim |
-| **User switches modes** | Detect intent | Guide user to next action |
-| **Before outline generation** | Summarize context | Clean, focused input |
-| **Before article execution** | Use plan (no chat history) | Plan already has all context |
-| **Block refinement** | No chat history | Block content is sufficient |
-| **User types "/reset"** | Clear all context | Fresh start |
-
----
-
-## 🎯 Recommendation: Hybrid Intelligent Approach
-
-### **The Winning Strategy**
-
-**Combine AI-powered + Smart Defaults:**
-
-1. **Default Behavior (No User Action)**
- - Chat history ≤ 4 messages → Send full history
- - Chat history > 4 messages → Auto-summarize with AI
- - Cost: ~$0.0001 per summarization (negligible)
-
-2. **Intent Detection (Automatic)**
- - After every user message → Detect intent
- - Show contextual action buttons
- - Cost: ~$0.00002 per detection (negligible)
-
-3. **User Control (Optional)**
- - Settings: "Context Mode" → Auto/Full/Minimal
- - "/reset" command → Clear context
- - Manual selection UI (advanced users)
-
-### **Why This Works**
-
-✅ **Language-Agnostic**
-- Works in English, Indonesian, Arabic, Chinese, etc.
-- No hardcoded keywords
-
-✅ **Cost-Effective**
-- 76% cost reduction vs full history
-- Total added cost: ~$0.34/month for 100 articles
-- ROI: Better quality + Lower cost
-
-✅ **True Agentic Experience**
-- AI manages its own context
-- Proactive suggestions
-- Seamless workflow
-- No manual mode switching
-
-✅ **User-Friendly**
-- Automatic by default
-- Optional manual control
-- Transparent (shows what's happening)
-- Fast (summarization takes 0.1-0.3s)
-
----
-
-## 🔧 Implementation Plan
-
-### **Phase 1: Core Infrastructure** (Week 1)
-
-**Backend:**
-- [ ] Add `/summarize-context` endpoint
-- [ ] Add `/detect-intent` endpoint
-- [ ] Add `summarize` and `intent_detection` operation types to cost tracking
-- [ ] Update OpenRouter provider to support these actions
-
-**Frontend:**
-- [ ] Add `handleSummarizeContext()` function
-- [ ] Add `handleDetectIntent()` function
-- [ ] Add context optimization indicator component
-
-**Testing:**
-- [ ] Test summarization in English, Indonesian, Arabic
-- [ ] Test intent detection in multiple languages
-- [ ] Verify cost tracking
-
-### **Phase 2: UX Integration** (Week 2)
-
-**Frontend:**
-- [ ] Add contextual action cards
-- [ ] Auto-detect intent after each message
-- [ ] Show "Optimizing context..." status
-- [ ] Add smart mode transitions
-
-**Settings:**
-- [ ] Add "Context Mode" setting (Auto/Full/Minimal)
-- [ ] Add context optimization toggle
-- [ ] Add cost estimates in settings
-
-**Testing:**
-- [ ] Test full user journey (chat → outline → write)
-- [ ] Test in multiple languages
-- [ ] Verify smooth transitions
-
-### **Phase 3: Advanced Features** (Week 3)
-
-**Features:**
-- [ ] Add `/reset` command
-- [ ] Add manual context selection UI (optional)
-- [ ] Add context analytics (token usage, cost breakdown)
-- [ ] Add context caching (reuse summaries)
-
-**Optimization:**
-- [ ] Implement smart caching for summaries
-- [ ] Add context relevance scoring
-- [ ] Optimize prompt templates
-
-**Documentation:**
-- [ ] Update user guide
-- [ ] Add context management section
-- [ ] Document cost implications
-
----
-
-## 💰 Final Cost Analysis
-
-### **Per Article (Average)**
-
-| Component | Cost | Frequency |
-|-----------|------|-----------|
-| Intent detection | $0.00002 × 10 messages | = $0.0002 |
-| Context summarization | $0.0001 × 1 time | = $0.0001 |
-| Planning (with summary) | $0.003 | = $0.003 |
-| Execution (no history) | $0.50-$2.00 | = $1.00 avg |
-| **Total per article** | | **≈ $1.0033** |
-
-**Compared to Full History:**
-- Full history approach: $1.013 per article
-- AI-powered approach: $1.0033 per article
-- **Savings: $0.01 per article** (negligible)
-
-**But wait - the real benefit:**
-- ✅ Better quality (clean, focused context)
-- ✅ Language-agnostic (works everywhere)
-- ✅ Better UX (proactive suggestions)
-- ✅ Scalable (no hardcoded rules)
-
----
-
-## 🎯 Answer to Your Question
-
-### **"Send all chat history vs AI summarization?"**
-
-**Answer: AI Summarization is Better**
-
-**Reasons:**
-
-1. **Cost is Nearly Identical**
- - Full history: $1.013/article
- - AI summary: $1.0033/article
- - Difference: $0.01 (1% savings)
-
-2. **Quality is Better**
- - Summary removes contradicted ideas
- - Summary focuses on final intent
- - Summary prevents pollution
- - AI explicitly told what to focus on
-
-3. **Language Support**
- - Full history: Works in all languages ✅
- - AI summary: Works in all languages ✅
- - Hardcoded: Only English ❌
-
-4. **Agentic Experience**
- - AI managing AI context = true agentic
- - Proactive intent detection
- - Seamless workflow
- - No user friction
-
-5. **Scalability**
- - No hardcoded rules to maintain
- - Adapts to new languages automatically
- - Handles edge cases gracefully
-
-### **The Plan:**
-
-1. ✅ **Implement AI summarization** (not hardcoded)
-2. ✅ **Implement AI intent detection** (not hardcoded)
-3. ✅ **Make it automatic** (no user action needed)
-4. ✅ **Add user controls** (optional override)
-5. ✅ **Track costs transparently** (show user what's happening)
-
----
-
-**Status:** 🚀 READY TO IMPLEMENT
-**Approach:** AI-Powered (Agentic)
-**Cost Impact:** Negligible (+$0.34/month for 100 articles)
-**Quality Impact:** Significant improvement
-**UX Impact:** Seamless, guided experience
diff --git a/AGENTIC_VIBE_IMPLEMENTATION_PLAN.md b/AGENTIC_VIBE_IMPLEMENTATION_PLAN.md
deleted file mode 100644
index fa1f230..0000000
--- a/AGENTIC_VIBE_IMPLEMENTATION_PLAN.md
+++ /dev/null
@@ -1,1084 +0,0 @@
-# Agentic Vibe Implementation Plan
-**Based on: Improved Agentic Vibe UI Design Plan**
-
----
-
-## Overview
-
-This implementation plan transforms the WP Agentic Writer settings page using a **Bootstrap 5 + Custom CSS** approach that prioritizes:
-- **Usability over aesthetics**
-- **Real operational data over simulated terminal output**
-- **Responsive design** (mobile-first)
-- **Maintainability** (standard patterns, minimal custom JS)
-
-**Philosophy:** "Agentic" means intelligent, status-aware, and responsive — not terminal-themed.
-
----
-
-## Phase 1: Foundation & CSS Variables (Day 1-2)
-
-### 1.1 Create CSS Variable System
-**File:** `/assets/css/agentic-variables.css`
-
-```css
-:root {
- /* Primary Colors - Modern AI Blue */
- --wpaw-primary: #3b82f6;
- --wpaw-primary-dark: #1e40af;
- --wpaw-primary-light: #dbeafe;
-
- /* Neutral Palette */
- --wpaw-bg-primary: #ffffff;
- --wpaw-bg-secondary: #f9fafb;
- --wpaw-bg-tertiary: #f3f4f6;
- --wpaw-text-primary: #111827;
- --wpaw-text-secondary: #6b7280;
- --wpaw-text-tertiary: #9ca3af;
-
- /* Status Colors */
- --wpaw-success: #10b981;
- --wpaw-warning: #f59e0b;
- --wpaw-error: #ef4444;
- --wpaw-info: #06b6d4;
-
- /* Typography */
- --wpaw-font-mono: 'Fira Code', 'JetBrains Mono', 'Consolas', monospace;
- --wpaw-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
-
- /* Spacing Scale */
- --wpaw-space-xs: 0.25rem;
- --wpaw-space-sm: 0.5rem;
- --wpaw-space-md: 1rem;
- --wpaw-space-lg: 1.5rem;
- --wpaw-space-xl: 2rem;
-
- /* Border Radius */
- --wpaw-radius-sm: 4px;
- --wpaw-radius-md: 8px;
- --wpaw-radius-lg: 12px;
-
- /* Shadows */
- --wpaw-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
- --wpaw-shadow-md: 0 4px 12px rgba(59, 130, 246, 0.1);
- --wpaw-shadow-lg: 0 8px 24px rgba(59, 130, 246, 0.15);
-
- /* Transitions */
- --wpaw-transition-fast: 150ms ease-out;
- --wpaw-transition-normal: 200ms ease-out;
- --wpaw-transition-slow: 300ms ease-out;
-}
-
-/* Dark Mode Variables */
-@media (prefers-color-scheme: dark) {
- :root {
- --wpaw-bg-primary: #0f172a;
- --wpaw-bg-secondary: #1e293b;
- --wpaw-bg-tertiary: #334155;
- --wpaw-text-primary: #f1f5f9;
- --wpaw-text-secondary: #cbd5e1;
- --wpaw-text-tertiary: #94a3b8;
- --wpaw-primary: #0ea5e9;
- }
-}
-```
-
-**Tasks:**
-- [ ] Create `agentic-variables.css`
-- [ ] Enqueue in `class-settings-v2.php` before other styles
-- [ ] Test variable inheritance across components
-
----
-
-### 1.2 Bootstrap Customization
-**File:** `/assets/css/agentic-bootstrap-custom.css`
-
-```css
-/* Override Bootstrap defaults with our variables */
-.wpaw-settings-v2 {
- --bs-primary: var(--wpaw-primary);
- --bs-success: var(--wpaw-success);
- --bs-warning: var(--wpaw-warning);
- --bs-danger: var(--wpaw-error);
- --bs-info: var(--wpaw-info);
- --bs-body-bg: var(--wpaw-bg-primary);
- --bs-body-color: var(--wpaw-text-primary);
-}
-
-/* Bootstrap component overrides */
-.wpaw-settings-v2 .btn {
- transition: all var(--wpaw-transition-fast);
- border-radius: var(--wpaw-radius-md);
-}
-
-.wpaw-settings-v2 .btn:active {
- transform: scale(0.98);
-}
-
-.wpaw-settings-v2 .form-control,
-.wpaw-settings-v2 .form-select {
- border-radius: var(--wpaw-radius-sm);
- border-color: var(--wpaw-bg-tertiary);
- transition: all var(--wpaw-transition-fast);
-}
-
-.wpaw-settings-v2 .form-control:focus,
-.wpaw-settings-v2 .form-select:focus {
- border-color: var(--wpaw-primary);
- box-shadow: 0 0 0 0.2rem rgba(59, 130, 246, 0.25);
-}
-
-.wpaw-settings-v2 .card {
- border-radius: var(--wpaw-radius-md);
- border: 1px solid var(--wpaw-bg-tertiary);
- transition: all var(--wpaw-transition-normal);
-}
-
-.wpaw-settings-v2 .card:hover {
- box-shadow: var(--wpaw-shadow-md);
-}
-```
-
-**Tasks:**
-- [ ] Create `agentic-bootstrap-custom.css`
-- [ ] Apply `.wpaw-settings-v2` wrapper to main layout
-- [ ] Test Bootstrap components with custom variables
-
----
-
-### 1.3 Component Library Base
-**File:** `/assets/css/agentic-components.css`
-
-```css
-/* Stat Cards */
-.wpaw-stat-card {
- background: var(--wpaw-bg-secondary);
- padding: var(--wpaw-space-md);
- border-radius: var(--wpaw-radius-md);
- border-left: 3px solid var(--wpaw-primary);
- transition: all var(--wpaw-transition-normal);
-}
-
-.wpaw-stat-card:hover {
- background: var(--wpaw-bg-tertiary);
- transform: translateY(-2px);
- box-shadow: var(--wpaw-shadow-md);
-}
-
-.wpaw-stat-label {
- font-size: 0.75rem;
- text-transform: uppercase;
- letter-spacing: 0.05em;
- color: var(--wpaw-text-tertiary);
- margin-bottom: var(--wpaw-space-sm);
- font-weight: 600;
-}
-
-.wpaw-stat-value {
- font-size: 1.75rem;
- font-weight: 600;
- color: var(--wpaw-primary);
- font-family: var(--wpaw-font-mono);
-}
-
-/* Status Badges */
-.wpaw-status-badge {
- display: inline-flex;
- align-items: center;
- gap: var(--wpaw-space-xs);
- padding: var(--wpaw-space-xs) var(--wpaw-space-sm);
- border-radius: var(--wpaw-radius-sm);
- font-size: 0.875rem;
- font-weight: 500;
-}
-
-.wpaw-status-online {
- background: rgba(16, 185, 129, 0.1);
- color: var(--wpaw-success);
-}
-
-.wpaw-status-offline {
- background: rgba(239, 68, 68, 0.1);
- color: var(--wpaw-error);
-}
-
-/* Pulse Animation */
-@keyframes wpaw-pulse {
- 0%, 100% { opacity: 1; }
- 50% { opacity: 0.5; }
-}
-
-.wpaw-animate-pulse {
- animation: wpaw-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
-}
-
-/* Code/Monospace Elements */
-.wpaw-code {
- font-family: var(--wpaw-font-mono);
- background: var(--wpaw-bg-secondary);
- padding: 2px 6px;
- border-radius: var(--wpaw-radius-sm);
- font-size: 0.85em;
- color: var(--wpaw-text-primary);
-}
-
-.wpaw-code-muted {
- color: var(--wpaw-text-tertiary);
-}
-```
-
-**Tasks:**
-- [ ] Create `agentic-components.css`
-- [ ] Document component usage in comments
-- [ ] Create example HTML snippets for each component
-
----
-
-## Phase 2: Header & Status Section (Day 3-4)
-
-### 2.1 Update Header Layout
-**File:** `/views/settings/layout.php`
-
-**Replace existing header card with:**
-
-```php
-
-```
-
-**Tasks:**
-- [ ] Update header HTML in `layout.php`
-- [ ] Add CSS for `.wpaw-agentic-header`
-- [ ] Test responsive behavior on mobile
-
----
-
-### 2.2 Add Header Stats JavaScript
-**File:** `/assets/js/settings-v2.js`
-
-**Add function to load header stats:**
-
-```javascript
-/**
- * Load and update header statistics
- */
-function loadHeaderStats() {
- $.ajax({
- url: wpawSettingsV2.ajaxUrl,
- type: 'POST',
- data: {
- action: 'wpaw_get_header_stats',
- nonce: wpawSettingsV2.nonce
- },
- success: function(response) {
- if (response.success) {
- const stats = response.data;
- $('#wpaw-stat-articles').text(stats.articles || '--');
- $('#wpaw-stat-total-cost').text('$' + (stats.total_cost || '0.00'));
- $('#wpaw-stat-api-status').text(stats.api_status || 'Unknown')
- .removeClass('text-success text-danger')
- .addClass(stats.api_online ? 'text-success' : 'text-danger');
- $('#wpaw-stat-last-updated').text(stats.last_updated || '--');
- }
- }
- });
-}
-
-// Call on page load
-$(document).ready(function() {
- loadHeaderStats();
- // Refresh every 30 seconds
- setInterval(loadHeaderStats, 30000);
-});
-```
-
-**Tasks:**
-- [ ] Add `loadHeaderStats()` function to JS
-- [ ] Create AJAX handler in `class-settings-v2.php`
-- [ ] Test real-time updates
-
----
-
-### 2.3 Create AJAX Handler for Header Stats
-**File:** `/includes/class-settings-v2.php`
-
-**Add method:**
-
-```php
-/**
- * AJAX handler for header statistics.
- *
- * @since 0.2.0
- */
-public function ajax_get_header_stats() {
- check_ajax_referer( 'wpaw_settings', 'nonce' );
-
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => 'Permission denied' ) );
- }
-
- global $wpdb;
- $table_name = $wpdb->prefix . 'wpaw_cost_tracking';
-
- // Get total articles
- $total_articles = $wpdb->get_var(
- "SELECT COUNT(DISTINCT post_id) FROM {$table_name} WHERE post_id > 0"
- );
-
- // Get total cost
- $total_cost = $wpdb->get_var( "SELECT SUM(cost) FROM {$table_name}" );
-
- // Check API status
- $settings = get_option( 'wp_agentic_writer_settings', array() );
- $api_key = $settings['openrouter_api_key'] ?? '';
- $api_online = ! empty( $api_key );
-
- // Get last activity
- $last_activity = $wpdb->get_var(
- "SELECT created_at FROM {$table_name} ORDER BY created_at DESC LIMIT 1"
- );
- $last_updated = $last_activity ? human_time_diff( strtotime( $last_activity ), current_time( 'timestamp' ) ) . ' ago' : 'Never';
-
- wp_send_json_success( array(
- 'articles' => intval( $total_articles ),
- 'total_cost' => number_format( (float) $total_cost, 2 ),
- 'api_status' => $api_online ? 'Online' : 'Offline',
- 'api_online' => $api_online,
- 'last_updated' => $last_updated,
- ) );
-}
-```
-
-**Tasks:**
-- [ ] Add AJAX action hook in constructor
-- [ ] Implement `ajax_get_header_stats()` method
-- [ ] Test with real database data
-
----
-
-## Phase 3: Workflow Pipeline Visualization (Day 5)
-
-### 3.1 Create Workflow Component
-**File:** `/assets/css/agentic-workflow.css`
-
-```css
-.wpaw-workflow-progress {
- background: var(--wpaw-bg-secondary);
- padding: var(--wpaw-space-lg);
- border-radius: var(--wpaw-radius-md);
- margin-bottom: var(--wpaw-space-lg);
-}
-
-.wpaw-progress-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: var(--wpaw-space-lg);
-}
-
-.wpaw-progress-steps {
- display: flex;
- align-items: center;
- gap: 0;
- justify-content: space-between;
-}
-
-.wpaw-step {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: var(--wpaw-space-sm);
- flex: 0 0 auto;
-}
-
-.wpaw-step-circle {
- width: 40px;
- height: 40px;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: 600;
- font-size: 0.9rem;
- border: 2px solid var(--wpaw-text-tertiary);
- background: var(--wpaw-bg-primary);
- color: var(--wpaw-text-primary);
- transition: all var(--wpaw-transition-normal);
-}
-
-.wpaw-step.completed .wpaw-step-circle {
- background: var(--wpaw-success);
- border-color: var(--wpaw-success);
- color: white;
-}
-
-.wpaw-step.active .wpaw-step-circle {
- background: var(--wpaw-primary);
- border-color: var(--wpaw-primary);
- color: white;
- box-shadow: 0 0 0 8px rgba(59, 130, 246, 0.15);
-}
-
-.wpaw-step.pending .wpaw-step-circle {
- opacity: 0.5;
-}
-
-.wpaw-step-label {
- font-size: 0.75rem;
- font-weight: 500;
- text-align: center;
- color: var(--wpaw-text-secondary);
- width: 60px;
-}
-
-.wpaw-step-connector {
- flex: 1;
- height: 2px;
- background: var(--wpaw-text-tertiary);
- margin: 0 var(--wpaw-space-sm);
- position: relative;
- top: -20px;
- min-width: 40px;
-}
-
-.wpaw-step-connector.completed {
- background: var(--wpaw-success);
-}
-
-.wpaw-step-connector.active {
- background: var(--wpaw-primary);
- animation: wpaw-slide-progress 1s ease-in-out infinite;
-}
-
-@keyframes wpaw-slide-progress {
- 0%, 100% { opacity: 1; }
- 50% { opacity: 0.6; }
-}
-
-@keyframes wpaw-spin {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
-}
-
-.wpaw-animate-spin {
- animation: wpaw-spin 2s linear infinite;
-}
-
-/* Responsive */
-@media (max-width: 768px) {
- .wpaw-progress-steps {
- flex-wrap: wrap;
- gap: var(--wpaw-space-md);
- }
-
- .wpaw-step-connector {
- display: none;
- }
-}
-```
-
-**Tasks:**
-- [ ] Create `agentic-workflow.css`
-- [ ] Add workflow HTML to layout (optional, for demo)
-- [ ] Test responsive behavior
-
----
-
-## Phase 4: Enhanced Cost Log Table (Day 6-7)
-
-### 4.1 Redesign Cost Log Table
-**File:** `/views/settings/tab-cost-log.php`
-
-**Update table structure:**
-
-```php
-
-
-
-
- |
- |
- |
- |
- |
- |
- |
- |
-
-
-
-
-
-
-
-```
-
-**Add CSS:**
-
-```css
-.wpaw-cost-table {
- font-size: 0.9rem;
- border-radius: var(--wpaw-radius-md);
- overflow: hidden;
-}
-
-.wpaw-cost-table thead {
- background: var(--wpaw-bg-secondary);
- font-weight: 600;
- text-transform: uppercase;
- font-size: 0.75rem;
- letter-spacing: 0.05em;
-}
-
-.wpaw-cost-table tbody tr {
- transition: background-color var(--wpaw-transition-fast);
- border-left: 3px solid transparent;
-}
-
-.wpaw-cost-table tbody tr:hover {
- background: var(--wpaw-bg-secondary) !important;
-}
-
-.wpaw-cost-table tbody tr.row-success {
- border-left-color: var(--wpaw-success);
-}
-
-.wpaw-cost-table tbody tr.row-warning {
- border-left-color: var(--wpaw-warning);
-}
-
-.wpaw-cost-table tbody tr.row-error {
- border-left-color: var(--wpaw-error);
-}
-
-.wpaw-cost-table .wpaw-code {
- font-size: 0.85em;
-}
-```
-
-**Tasks:**
-- [ ] Update table HTML structure
-- [ ] Add status column with icons
-- [ ] Apply CSS styling
-- [ ] Update JS rendering to include status
-
----
-
-### 4.2 Update JavaScript Table Rendering
-**File:** `/assets/js/settings-v2.js`
-
-**Update `renderCostLogTable()` function:**
-
-```javascript
-function renderCostLogTable(data) {
- const $tbody = $('#wpaw-cost-log-tbody');
- const records = data.records || [];
-
- if (records.length === 0) {
- $tbody.html('| No cost records found. |
');
- return;
- }
-
- let html = '';
- records.forEach(record => {
- const postCell = record.post_link
- ? `${escapeHtml(record.post_title)}`
- : `${escapeHtml(record.post_title)}`;
-
- // Determine row status class
- const cost = parseFloat(record.cost);
- let rowClass = 'row-success';
- if (cost > 0.10) rowClass = 'row-warning';
- if (cost > 0.50) rowClass = 'row-error';
-
- html += `
-
- ${escapeHtml(record.created_at)} |
- ${postCell} |
- ${escapeHtml(record.model)} |
- ${escapeHtml(record.action)} |
- ${record.input_tokens} |
- ${record.output_tokens} |
- $${record.cost} |
-
-
- |
-
- `;
- });
-
- $tbody.html(html);
-
- // Update records info
- const start = (data.current_page - 1) * data.per_page + 1;
- const end = Math.min(data.current_page * data.per_page, data.total_items);
- $('#wpaw-records-info').text(`Showing ${start}-${end} of ${data.total_items} records`);
-}
-```
-
-**Tasks:**
-- [ ] Update `renderCostLogTable()` function
-- [ ] Add status icons (dashicons or custom)
-- [ ] Test with various cost amounts
-
----
-
-## Phase 5: Model Configuration Cards (Day 8)
-
-### 5.1 Create Model Card Component
-**File:** `/assets/css/agentic-models.css`
-
-```css
-.wpaw-model-card {
- background: var(--wpaw-bg-secondary);
- border: 1px solid var(--wpaw-bg-tertiary);
- border-radius: var(--wpaw-radius-md);
- padding: var(--wpaw-space-lg);
- transition: all var(--wpaw-transition-normal);
- height: 100%;
-}
-
-.wpaw-model-card:hover {
- border-color: var(--wpaw-primary);
- box-shadow: var(--wpaw-shadow-md);
-}
-
-.wpaw-model-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: var(--wpaw-space-md);
-}
-
-.wpaw-model-header h5 {
- margin-bottom: var(--wpaw-space-xs);
- color: var(--wpaw-text-primary);
-}
-
-.wpaw-model-header p {
- font-size: 0.875rem;
- color: var(--wpaw-text-tertiary);
- font-family: var(--wpaw-font-mono);
-}
-
-.wpaw-model-stat {
- margin-top: var(--wpaw-space-md);
-}
-
-.wpaw-model-stat label {
- font-size: 0.75rem;
- text-transform: uppercase;
- color: var(--wpaw-text-tertiary);
- margin-bottom: var(--wpaw-space-xs);
-}
-
-.wpaw-model-metrics {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: var(--wpaw-space-md);
- padding-top: var(--wpaw-space-md);
- border-top: 1px solid var(--wpaw-bg-tertiary);
- margin-top: var(--wpaw-space-md);
-}
-
-.wpaw-metric {
- text-align: center;
-}
-
-.wpaw-metric-label {
- display: block;
- font-size: 0.75rem;
- text-transform: uppercase;
- color: var(--wpaw-text-tertiary);
- margin-bottom: var(--wpaw-space-xs);
-}
-
-.wpaw-metric-value {
- display: block;
- font-size: 1.25rem;
- font-weight: 600;
- color: var(--wpaw-primary);
- font-family: var(--wpaw-font-mono);
-}
-
-.wpaw-model-actions {
- margin-top: var(--wpaw-space-md);
-}
-```
-
-**Tasks:**
-- [ ] Create `agentic-models.css`
-- [ ] Design model card HTML structure
-- [ ] Test grid layout responsiveness
-
----
-
-## Phase 6: Animations & Polish (Day 9-10)
-
-### 6.1 Create Animation Library
-**File:** `/assets/css/agentic-animations.css`
-
-```css
-/* Fade In */
-@keyframes wpaw-fade-in {
- from {
- opacity: 0;
- transform: translateY(8px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-.wpaw-fade-in {
- animation: wpaw-fade-in 300ms ease-out;
-}
-
-/* Slide In */
-@keyframes wpaw-slide-in-right {
- from {
- opacity: 0;
- transform: translateX(20px);
- }
- to {
- opacity: 1;
- transform: translateX(0);
- }
-}
-
-.wpaw-slide-in-right {
- animation: wpaw-slide-in-right 300ms ease-out;
-}
-
-/* Scale In */
-@keyframes wpaw-scale-in {
- from {
- opacity: 0;
- transform: scale(0.95);
- }
- to {
- opacity: 1;
- transform: scale(1);
- }
-}
-
-.wpaw-scale-in {
- animation: wpaw-scale-in 200ms ease-out;
-}
-
-/* Shimmer Loading */
-@keyframes wpaw-shimmer {
- 0% {
- background-position: -1000px 0;
- }
- 100% {
- background-position: 1000px 0;
- }
-}
-
-.wpaw-shimmer {
- background: linear-gradient(
- 90deg,
- var(--wpaw-bg-secondary) 0%,
- var(--wpaw-bg-tertiary) 50%,
- var(--wpaw-bg-secondary) 100%
- );
- background-size: 1000px 100%;
- animation: wpaw-shimmer 2s infinite;
-}
-
-/* Hover Lift */
-.wpaw-hover-lift {
- transition: transform var(--wpaw-transition-normal);
-}
-
-.wpaw-hover-lift:hover {
- transform: translateY(-4px);
-}
-
-/* Glow Effect */
-.wpaw-glow-primary {
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
- transition: box-shadow var(--wpaw-transition-normal);
-}
-
-.wpaw-glow-primary:hover {
- box-shadow: 0 0 0 6px rgba(59, 130, 246, 0.2);
-}
-
-/* Smooth Height Transition */
-.wpaw-smooth-height {
- transition: height var(--wpaw-transition-slow);
- overflow: hidden;
-}
-```
-
-**Tasks:**
-- [ ] Create `agentic-animations.css`
-- [ ] Apply animations to key components
-- [ ] Test performance (60fps target)
-
----
-
-### 6.2 Add Tab Transition Animations
-**File:** `/assets/js/settings-v2.js`
-
-```javascript
-// Add smooth transitions between tabs
-$('.nav-tabs .nav-link').on('shown.bs.tab', function (e) {
- const $target = $($(e.target).data('bs-target'));
- $target.addClass('wpaw-fade-in');
-
- setTimeout(function() {
- $target.removeClass('wpaw-fade-in');
- }, 300);
-});
-```
-
-**Tasks:**
-- [ ] Add tab transition code
-- [ ] Test smooth switching between tabs
-- [ ] Ensure no layout shift
-
----
-
-## Phase 7: Dark Mode Implementation (Day 11)
-
-### 7.1 Enhance Dark Mode Support
-**File:** `/assets/css/agentic-dark-mode.css`
-
-```css
-@media (prefers-color-scheme: dark) {
- .wpaw-settings-v2 {
- background: var(--wpaw-bg-primary);
- color: var(--wpaw-text-primary);
- }
-
- .wpaw-settings-v2 .card {
- background: var(--wpaw-bg-secondary);
- border-color: var(--wpaw-bg-tertiary);
- }
-
- .wpaw-settings-v2 .table {
- --bs-table-bg: var(--wpaw-bg-secondary);
- --bs-table-hover-bg: var(--wpaw-bg-tertiary);
- color: var(--wpaw-text-primary);
- }
-
- .wpaw-settings-v2 .table-light {
- --bs-table-bg: var(--wpaw-bg-tertiary);
- }
-
- .wpaw-settings-v2 .form-control,
- .wpaw-settings-v2 .form-select {
- background: var(--wpaw-bg-secondary);
- border-color: var(--wpaw-bg-tertiary);
- color: var(--wpaw-text-primary);
- }
-
- .wpaw-settings-v2 .badge {
- filter: brightness(1.2);
- }
-}
-```
-
-**Tasks:**
-- [ ] Create `agentic-dark-mode.css`
-- [ ] Test all components in dark mode
-- [ ] Ensure proper contrast ratios
-
----
-
-## Phase 8: Testing & Optimization (Day 12-13)
-
-### 8.1 Responsive Testing Checklist
-- [ ] Desktop (1920px, 1440px, 1280px)
-- [ ] Tablet (768px, 1024px)
-- [ ] Mobile (375px, 414px, 390px)
-- [ ] Test all tabs on each breakpoint
-- [ ] Verify table scrolling on mobile
-- [ ] Check stat cards stacking
-
-### 8.2 Browser Compatibility
-- [ ] Chrome/Edge (latest)
-- [ ] Firefox (latest)
-- [ ] Safari (latest)
-- [ ] Test dark mode in each browser
-
-### 8.3 Performance Optimization
-- [ ] Minify CSS files
-- [ ] Combine CSS files (optional)
-- [ ] Test page load time
-- [ ] Check animation performance (60fps)
-- [ ] Optimize AJAX calls (debouncing)
-
-### 8.4 Accessibility Audit
-- [ ] Keyboard navigation works
-- [ ] Screen reader compatibility
-- [ ] Color contrast meets WCAG AA
-- [ ] Focus indicators visible
-- [ ] ARIA labels present
-
----
-
-## File Structure
-
-```
-wp-agentic-writer/
-├── assets/
-│ ├── css/
-│ │ ├── agentic-variables.css (Phase 1)
-│ │ ├── agentic-bootstrap-custom.css (Phase 1)
-│ │ ├── agentic-components.css (Phase 1)
-│ │ ├── agentic-workflow.css (Phase 3)
-│ │ ├── agentic-models.css (Phase 5)
-│ │ ├── agentic-animations.css (Phase 6)
-│ │ ├── agentic-dark-mode.css (Phase 7)
-│ │ └── settings-v2.css (existing, update)
-│ └── js/
-│ └── settings-v2.js (existing, enhance)
-├── includes/
-│ └── class-settings-v2.php (existing, add AJAX)
-└── views/
- └── settings/
- ├── layout.php (existing, update)
- ├── tab-general.php (existing)
- ├── tab-models.php (existing, enhance)
- ├── tab-cost-log.php (existing, update)
- └── tab-guide.php (existing)
-```
-
----
-
-## Enqueue Order in `class-settings-v2.php`
-
-```php
-// CSS Enqueue Order
-wp_enqueue_style( 'bootstrap', '...', array(), '5.3.3' );
-wp_enqueue_style( 'select2', '...', array(), '4.1.0' );
-wp_enqueue_style( 'select2-bootstrap-5', '...', array( 'select2', 'bootstrap' ), '1.3.0' );
-
-// Custom CSS (in order)
-wp_enqueue_style( 'wpaw-agentic-variables', WP_AGENTIC_WRITER_URL . 'assets/css/agentic-variables.css', array(), WP_AGENTIC_WRITER_VERSION );
-wp_enqueue_style( 'wpaw-agentic-bootstrap-custom', WP_AGENTIC_WRITER_URL . 'assets/css/agentic-bootstrap-custom.css', array( 'bootstrap', 'wpaw-agentic-variables' ), WP_AGENTIC_WRITER_VERSION );
-wp_enqueue_style( 'wpaw-agentic-components', WP_AGENTIC_WRITER_URL . 'assets/css/agentic-components.css', array( 'wpaw-agentic-variables' ), WP_AGENTIC_WRITER_VERSION );
-wp_enqueue_style( 'wpaw-agentic-workflow', WP_AGENTIC_WRITER_URL . 'assets/css/agentic-workflow.css', array( 'wpaw-agentic-variables' ), WP_AGENTIC_WRITER_VERSION );
-wp_enqueue_style( 'wpaw-agentic-models', WP_AGENTIC_WRITER_URL . 'assets/css/agentic-models.css', array( 'wpaw-agentic-variables' ), WP_AGENTIC_WRITER_VERSION );
-wp_enqueue_style( 'wpaw-agentic-animations', WP_AGENTIC_WRITER_URL . 'assets/css/agentic-animations.css', array(), WP_AGENTIC_WRITER_VERSION );
-wp_enqueue_style( 'wpaw-agentic-dark-mode', WP_AGENTIC_WRITER_URL . 'assets/css/agentic-dark-mode.css', array( 'wpaw-agentic-variables' ), WP_AGENTIC_WRITER_VERSION );
-
-// Existing styles
-wp_enqueue_style( 'wp-agentic-writer-admin-v2', WP_AGENTIC_WRITER_URL . 'assets/css/admin-v2.css', array(), WP_AGENTIC_WRITER_VERSION );
-wp_enqueue_style( 'wp-agentic-writer-settings-v2', WP_AGENTIC_WRITER_URL . 'assets/css/settings-v2.css', array(), WP_AGENTIC_WRITER_VERSION );
-```
-
----
-
-## Timeline Summary
-
-| Phase | Duration | Key Deliverables |
-|-------|----------|------------------|
-| Phase 1 | 1-2 days | CSS variables, Bootstrap customization, component library |
-| Phase 2 | 2 days | Header stats, AJAX handler, real-time updates |
-| Phase 3 | 1 day | Workflow pipeline visualization |
-| Phase 4 | 2 days | Enhanced cost log table with status |
-| Phase 5 | 1 day | Model configuration cards |
-| Phase 6 | 2 days | Animations, transitions, polish |
-| Phase 7 | 1 day | Dark mode implementation |
-| Phase 8 | 2 days | Testing, optimization, accessibility |
-
-**Total:** 11-13 days
-
----
-
-## Success Criteria
-
-### Functional Requirements
-- ✅ All existing features work (no regressions)
-- ✅ Real-time stats update automatically
-- ✅ Cost log loads and filters correctly
-- ✅ Model configuration saves properly
-- ✅ Responsive on all devices
-
-### Design Requirements
-- ✅ Consistent color system throughout
-- ✅ Smooth animations (60fps)
-- ✅ Dark mode works correctly
-- ✅ Accessible (WCAG AA)
-- ✅ Professional, modern appearance
-
-### Performance Requirements
-- ✅ Page load < 2 seconds
-- ✅ AJAX responses < 500ms
-- ✅ No layout shift (CLS < 0.1)
-- ✅ Smooth scrolling and interactions
-
----
-
-## Next Steps
-
-1. **Review this plan** with stakeholders
-2. **Create a branch** for implementation
-3. **Start with Phase 1** (foundation)
-4. **Test incrementally** after each phase
-5. **Gather feedback** from users
-6. **Iterate and refine** based on feedback
-
----
-
-## Notes
-
-- Keep existing functionality intact
-- Test thoroughly before merging
-- Document component usage
-- Consider creating a style guide
-- Plan for future enhancements
diff --git a/AGENTIC_VIBE_UI_PLAN.md b/AGENTIC_VIBE_UI_PLAN.md
deleted file mode 100644
index c9b6229..0000000
--- a/AGENTIC_VIBE_UI_PLAN.md
+++ /dev/null
@@ -1,299 +0,0 @@
-# Agentic Vibe UI Design Plan
-
-## Concept Overview
-Transform the settings page into an **AI-first, developer-centric interface** that reflects the "agentic" nature of the plugin - autonomous, intelligent, and workflow-driven.
-
-## Design Philosophy
-
-### Core Principles
-1. **Terminal/CLI Aesthetic** - Embrace developer tools aesthetics (VS Code, terminal, code editors)
-2. **Real-time Feedback** - Show AI "thinking" and processing states
-3. **Workflow Visualization** - Display the 5-phase workflow prominently
-4. **Data-Driven** - Emphasize metrics, costs, and performance
-5. **Dark Mode First** - Modern, eye-friendly interface
-
----
-
-## Proposed Design Elements
-
-### 1. **Terminal-Inspired Header**
-```
-┌─────────────────────────────────────────────────────────────┐
-│ > wp-agentic-writer --version 0.1.3 │
-│ [●] Connected to OpenRouter API │
-│ [i] 142 articles generated | $12.45 total cost │
-└─────────────────────────────────────────────────────────────┘
-```
-
-**Features:**
-- Monospace font (Fira Code, JetBrains Mono)
-- Green/amber status indicators
-- Command-line style output
-- Real-time API connection status
-
-### 2. **Workflow Pipeline Visualization**
-```
-[Scribble] → [Research] → [Plan] → [Execute] → [Revise]
- ✓ ✓ ✓ ⟳ ○
-```
-
-**Features:**
-- Horizontal pipeline with progress indicators
-- Show which phase is currently active
-- Click to jump to relevant settings
-- Animated transitions between phases
-
-### 3. **Code Editor-Style Tabs**
-```
-┌─[ General ]─┬─[ Models ]─┬─[ Cost Log ]─┬─[ Guide ]─┐
-│ │
-│ Settings content here... │
-│ │
-└────────────────────────────────────────────────────────┘
-```
-
-**Features:**
-- VS Code-style tab design
-- File icon indicators
-- Close/minimize animations
-- Breadcrumb navigation
-
-### 4. **Terminal Output for Cost Log**
-```
-$ tail -f /var/log/wpaw/costs.log
-
-[2026-01-26 12:30:15] POST #142 | claude-3.5-sonnet | writing | $0.0847
-[2026-01-26 12:28:03] POST #141 | gemini-2.5-flash | planning | $0.0012
-[2026-01-26 12:25:41] POST #140 | gpt-4o | image | $0.0030
-[2026-01-26 12:20:18] POST #139 | claude-3.5-sonnet | writing | $0.0921
-
-> filter --model claude-3.5-sonnet --date today
-```
-
-**Features:**
-- Log file aesthetic
-- Syntax highlighting for different actions
-- Command-line style filters
-- Real-time streaming updates
-
-### 5. **AI Model Cards with Stats**
-```
-┌─────────────────────────────────────────────┐
-│ anthropic/claude-3.5-sonnet │
-│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 87% usage │
-│ │
-│ • 142 requests this month │
-│ • $8.45 total cost │
-│ • Avg response: 1.2s │
-│ • Quality score: 9.2/10 │
-└─────────────────────────────────────────────┘
-```
-
-**Features:**
-- Progress bars for usage
-- Real-time metrics
-- Performance indicators
-- Cost breakdown
-
-### 6. **Live Activity Monitor**
-```
-┌─ System Status ──────────────────────────────┐
-│ │
-│ CPU: ▓▓▓▓▓▓▓▓░░░░░░░░ 45% │
-│ API: ▓▓░░░░░░░░░░░░░░ 12% │
-│ Queue: 3 pending requests │
-│ │
-│ [●] Writing article #143... │
-│ [○] Waiting for refinement... │
-└──────────────────────────────────────────────┘
-```
-
-**Features:**
-- Real-time processing status
-- Queue visualization
-- Resource usage meters
-- Active task indicators
-
----
-
-## Color Scheme Options
-
-### Option A: **Dark Terminal** (Recommended)
-```css
-Background: #1e1e1e (VS Code dark)
-Foreground: #d4d4d4
-Accent: #4ec9b0 (teal/cyan)
-Success: #4ec9b0
-Warning: #ce9178
-Error: #f48771
-```
-
-### Option B: **Cyberpunk Neon**
-```css
-Background: #0a0e27
-Foreground: #e0e0e0
-Accent: #00ffff (cyan)
-Success: #00ff00
-Warning: #ffff00
-Error: #ff0066
-```
-
-### Option C: **Hacker Green**
-```css
-Background: #0c0c0c
-Foreground: #00ff00
-Accent: #00cc00
-Success: #00ff00
-Warning: #ffcc00
-Error: #ff3300
-```
-
----
-
-## Typography
-
-### Recommended Fonts
-1. **Monospace:** JetBrains Mono, Fira Code, Source Code Pro
-2. **UI Text:** Inter, SF Pro, Segoe UI
-3. **Headers:** Space Grotesk, Outfit
-
-### Font Sizes
-- Terminal output: 13px
-- Body text: 14px
-- Headers: 18px-24px
-- Code: 12px
-
----
-
-## Interactive Elements
-
-### 1. **Command Palette** (Ctrl/Cmd + K)
-```
-> Search settings...
- ─────────────────────────────────────
- → Change writing model
- → View cost breakdown
- → Refresh API models
- → Export cost log
- → Test API connection
-```
-
-### 2. **Toast Notifications**
-```
-┌─────────────────────────────────┐
-│ ✓ Settings saved successfully │
-│ Changes applied to 6 models │
-└─────────────────────────────────┘
-```
-
-### 3. **Inline Validation**
-```
-API Key: ••••••••••••••••••••••••••• [✓]
- └─ Valid • Last tested 2m ago
-```
-
----
-
-## Animation & Transitions
-
-### Key Animations
-1. **Typing effect** for terminal output
-2. **Pulse animation** for active processes
-3. **Slide transitions** between tabs
-4. **Fade in/out** for modals and toasts
-5. **Progress bars** with smooth fills
-
-### Micro-interactions
-- Hover effects on buttons (glow, scale)
-- Click feedback (ripple effect)
-- Loading spinners (terminal-style)
-- Success checkmarks (animated)
-
----
-
-## Implementation Phases
-
-### Phase 1: Foundation (Quick Win)
-- [ ] Apply dark theme color scheme
-- [ ] Switch to monospace fonts for key areas
-- [ ] Add terminal-style header
-- [ ] Implement basic animations
-
-### Phase 2: Enhanced UX
-- [ ] Create workflow pipeline visualization
-- [ ] Redesign cost log as terminal output
-- [ ] Add model usage statistics
-- [ ] Implement command palette
-
-### Phase 3: Advanced Features
-- [ ] Real-time activity monitor
-- [ ] Live API status indicators
-- [ ] Performance metrics dashboard
-- [ ] Advanced filtering with CLI-style commands
-
-### Phase 4: Polish
-- [ ] Add sound effects (optional)
-- [ ] Implement keyboard shortcuts
-- [ ] Create onboarding tour
-- [ ] Add theme switcher (light/dark/custom)
-
----
-
-## Technical Requirements
-
-### CSS Framework
-- Keep Bootstrap 5 for grid/utilities
-- Add custom CSS for terminal aesthetic
-- Use CSS variables for theming
-
-### JavaScript Libraries
-- Keep existing: jQuery, Select2
-- Add: anime.js (animations), typed.js (typing effect)
-- Consider: xterm.js (full terminal emulation)
-
-### Performance
-- Lazy load terminal output
-- Virtualize long cost logs
-- Debounce real-time updates
-- Cache API responses
-
----
-
-## Inspiration Sources
-
-1. **VS Code Settings** - Clean, organized, searchable
-2. **GitHub CLI** - Terminal aesthetic, clear output
-3. **Vercel Dashboard** - Modern, data-driven
-4. **Railway.app** - Developer-focused, beautiful
-5. **Linear.app** - Smooth animations, keyboard-first
-
----
-
-## Next Steps
-
-1. **Review & Approve** this design direction
-2. **Create mockups** for key screens
-3. **Build prototype** of one section (e.g., cost log)
-4. **Gather feedback** and iterate
-5. **Implement** in phases
-
----
-
-## Questions to Consider
-
-1. Should we support **light mode** or go dark-only?
-2. Do we want **sound effects** for actions?
-3. Should the terminal be **interactive** (accept commands)?
-4. Do we need **mobile responsiveness** or desktop-only?
-5. Should we add **AI assistant chat** in the settings?
-
----
-
-## Estimated Development Time
-
-- **Phase 1:** 4-6 hours
-- **Phase 2:** 8-12 hours
-- **Phase 3:** 12-16 hours
-- **Phase 4:** 6-8 hours
-
-**Total:** ~30-42 hours for full implementation
diff --git a/BRAVE_SEARCH_IMPLEMENTATION_PLAN.md b/BRAVE_SEARCH_IMPLEMENTATION_PLAN.md
deleted file mode 100644
index 3463d17..0000000
--- a/BRAVE_SEARCH_IMPLEMENTATION_PLAN.md
+++ /dev/null
@@ -1,1293 +0,0 @@
-# WP Agentic Writer: Brave Search Integration Implementation Plan
-
-**Date:** January 29, 2026
-**Status:** Planning Phase
-**Integration Type:** Seamless addition to existing plugin architecture
-
----
-
-## Executive Summary
-
-This document outlines the complete implementation plan for integrating **Brave Search API** into WP Agentic Writer as an alternative web search provider alongside the existing OpenRouter `:online` models. The integration follows the plugin's existing architecture patterns and provides users with flexible, cost-effective web research capabilities.
-
-**Key Design Principle:** Brave Search API is positioned as an **alternative provider** to OpenRouter's online models, giving users choice based on cost, performance, and feature requirements.
-
----
-
-## Table of Contents
-
-1. [Architecture Overview](#architecture-overview)
-2. [Settings Integration](#settings-integration)
-3. [Database Schema](#database-schema)
-4. [Provider Architecture](#provider-architecture)
-5. [REST API Endpoints](#rest-api-endpoints)
-6. [Frontend Integration](#frontend-integration)
-7. [Agent Integration](#agent-integration)
-8. [Cost Tracking Integration](#cost-tracking-integration)
-9. [Implementation Phases](#implementation-phases)
-10. [File Structure](#file-structure)
-11. [Testing Strategy](#testing-strategy)
-
----
-
-## Architecture Overview
-
-### Current Plugin Structure
-
-```
-wp-agentic-writer/
-├── includes/
-│ ├── class-openrouter-provider.php ← Existing AI provider
-│ ├── class-gutenberg-sidebar.php ← Main REST API handler
-│ ├── class-settings.php ← Settings management
-│ ├── class-cost-tracker.php ← Cost tracking system
-│ └── class-markdown-parser.php ← Content parsing
-├── assets/
-│ └── js/
-│ └── sidebar.js ← Frontend React app
-└── views/
- └── settings/
- └── tab-models.php ← Model settings UI
-```
-
-### Integration Points
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ SETTINGS PANEL │
-│ │
-│ API Configuration │
-│ ├── OpenRouter API Key [sk-or-v1-...] │
-│ └── Brave Search API Key [BSA...] ← NEW │
-│ │
-│ Web Search Provider │
-│ ├── ○ OpenRouter :online models (perplexity, etc) │
-│ └── ○ Brave Search API (independent index) ← NEW │
-│ │
-│ [Only show if Brave API key is set] │
-└─────────────────────────────────────────────────────────────────┘
-```
-
----
-
-## Settings Integration
-
-### 1. Settings Schema Extension
-
-**File:** `includes/class-settings.php`
-
-Add Brave Search settings to existing settings array:
-
-```php
-// In sanitize_settings() method - line ~320
-$sanitized['openrouter_api_key'] = trim( $input['openrouter_api_key'] ?? '' );
-
-// ADD NEW:
-$sanitized['brave_api_key'] = trim( $input['brave_api_key'] ?? '' );
-$sanitized['brave_api_tier'] = sanitize_text_field( $input['brave_api_tier'] ?? 'base_ai' );
-$sanitized['web_search_provider'] = sanitize_text_field( $input['web_search_provider'] ?? 'openrouter' );
-$sanitized['brave_search_enabled'] = isset( $input['brave_search_enabled'] ) ? 1 : 0;
-$sanitized['brave_cache_enabled'] = isset( $input['brave_cache_enabled'] ) ? 1 : 0;
-$sanitized['brave_cache_duration_days'] = absint( $input['brave_cache_duration_days'] ?? 30 );
-$sanitized['brave_monthly_budget'] = floatval( $input['brave_monthly_budget'] ?? 50.00 );
-$sanitized['brave_include_citations'] = isset( $input['brave_include_citations'] ) ? 1 : 0;
-```
-
-### 2. Settings UI - API Keys Section
-
-**File:** `views/settings/tab-models.php`
-
-Add Brave API key field after OpenRouter API key (around line 480):
-
-```php
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-### 3. Settings UI - Web Search Provider Selection
-
-Add new section after model presets:
-
-```php
-
-
-
-
-```
-
----
-
-## Database Schema
-
-### New Tables
-
-Create three new tables for Brave Search integration. Add to plugin activation hook.
-
-**File:** `wp-agentic-writer.php` (activation hook)
-
-```php
-function wp_agentic_writer_activate() {
- global $wpdb;
- $charset_collate = $wpdb->get_charset_collate();
-
- // Existing tables...
-
- // NEW: Brave Search tables
- $sql_searches = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}wpaw_searches (
- id BIGINT AUTO_INCREMENT PRIMARY KEY,
- post_id BIGINT NOT NULL,
- search_query VARCHAR(500) NOT NULL,
- search_number INT,
- total_searches_for_post INT,
- results_count INT,
- results_json LONGTEXT,
- top_result_title VARCHAR(255),
- top_result_url VARCHAR(500),
- cost DECIMAL(10, 4),
- api_tier VARCHAR(50),
- cache_enabled TINYINT DEFAULT 1,
- cache_expires_at TIMESTAMP NULL,
- cache_hit TINYINT DEFAULT 0,
- search_category VARCHAR(100),
- status VARCHAR(30) DEFAULT 'completed',
- error_message TEXT,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- KEY idx_post (post_id),
- KEY idx_query (search_query(255)),
- KEY idx_cache_expires (cache_expires_at),
- KEY idx_status (status)
- ) $charset_collate;";
-
- $sql_citations = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}wpaw_citations (
- id BIGINT AUTO_INCREMENT PRIMARY KEY,
- post_id BIGINT NOT NULL,
- citation_number INT NOT NULL,
- citation_text VARCHAR(500),
- context_excerpt TEXT,
- search_id BIGINT,
- source_url VARCHAR(500) NOT NULL,
- source_title VARCHAR(255),
- source_domain VARCHAR(100),
- source_type VARCHAR(50),
- result_position INT,
- article_section VARCHAR(100),
- added_by VARCHAR(50),
- verified TINYINT DEFAULT 0,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- KEY idx_post (post_id),
- KEY idx_citation_number (post_id, citation_number),
- KEY idx_source_domain (source_domain)
- ) $charset_collate;";
-
- $sql_cache = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}wpaw_search_cache (
- id BIGINT AUTO_INCREMENT PRIMARY KEY,
- search_query_normalized VARCHAR(500) NOT NULL,
- search_category VARCHAR(100),
- cache_key VARCHAR(64),
- results_json LONGTEXT,
- result_count INT,
- cached_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- expires_at TIMESTAMP,
- hit_count INT DEFAULT 0,
- cost_saved DECIMAL(10, 4) DEFAULT 0,
- quality_score DECIMAL(3,2),
- UNIQUE KEY unique_query_category (search_query_normalized(255), search_category(100)),
- KEY idx_expires (expires_at),
- KEY idx_hit_count (hit_count)
- ) $charset_collate;";
-
- require_once ABSPATH . 'wp-admin/includes/upgrade.php';
- dbDelta( $sql_searches );
- dbDelta( $sql_citations );
- dbDelta( $sql_cache );
-}
-```
-
-**Also add to:** `CREATE_TABLE.sql` for manual creation
-
----
-
-## Provider Architecture
-
-### New File: `includes/class-brave-search-provider.php`
-
-Create a new provider class following the same pattern as OpenRouter provider:
-
-```php
-api_key = $settings['brave_api_key'] ?? '';
- $this->tier = $settings['brave_api_tier'] ?? 'base_ai';
- }
-
- /**
- * Perform web search
- *
- * @param string $query Search query
- * @param array $options Search options
- * @return array|WP_Error Search results or error
- */
- public function search( $query, $options = array() ) {
- if ( empty( $this->api_key ) ) {
- return new WP_Error( 'no_api_key', 'Brave Search API key not configured' );
- }
-
- // Check cache first
- if ( ! empty( $options['use_cache'] ) ) {
- $cached = $this->get_cached_result( $query, $options['category'] ?? null );
- if ( $cached ) {
- return array(
- 'results' => $cached['results'],
- 'from_cache' => true,
- 'cache_age_hours' => $cached['age_hours'],
- 'cost' => 0,
- );
- }
- }
-
- // Check budget
- $budget_check = $this->check_budget();
- if ( is_wp_error( $budget_check ) ) {
- return $budget_check;
- }
-
- // Call API
- $response = $this->call_api( $query, $options );
-
- if ( is_wp_error( $response ) ) {
- return $response;
- }
-
- // Calculate cost
- $cost = $this->calculate_cost();
-
- // Store search record
- $search_id = $this->store_search( $query, $response, $cost, $options );
-
- // Cache results
- if ( ! empty( $options['use_cache'] ) ) {
- $this->cache_results( $query, $response, $options );
- }
-
- // Track cost
- $this->track_cost( $cost, $options['post_id'] ?? 0 );
-
- return array(
- 'results' => $response,
- 'from_cache' => false,
- 'search_id' => $search_id,
- 'cost' => $cost,
- 'result_count' => count( $response['web']['results'] ?? array() ),
- );
- }
-
- /**
- * Call Brave Search API
- */
- private function call_api( $query, $options = array() ) {
- $endpoint = $this->api_base . '/web/search';
-
- $params = array(
- 'q' => $query,
- 'count' => $options['count'] ?? 10,
- 'safesearch' => 'moderate',
- 'search_lang' => $options['language'] ?? 'en',
- 'country' => $options['country'] ?? 'US',
- );
-
- $response = wp_remote_get(
- add_query_arg( $params, $endpoint ),
- array(
- 'headers' => array(
- 'X-Subscription-Token' => $this->api_key,
- 'Accept' => 'application/json',
- ),
- 'timeout' => 30,
- )
- );
-
- if ( is_wp_error( $response ) ) {
- return $response;
- }
-
- $status = wp_remote_retrieve_response_code( $response );
- $body = json_decode( wp_remote_retrieve_body( $response ), true );
-
- if ( 429 === $status ) {
- return new WP_Error( 'rate_limited', 'Brave API rate limit exceeded' );
- } elseif ( 401 === $status ) {
- return new WP_Error( 'invalid_api_key', 'Invalid Brave API key' );
- } elseif ( 200 !== $status ) {
- return new WP_Error( 'api_error', 'Brave API error: ' . $status );
- }
-
- return $body;
- }
-
- /**
- * Check cache for existing results
- */
- private function get_cached_result( $query, $category = null ) {
- global $wpdb;
-
- $cache_key = sha1( strtolower( trim( $query ) ) );
-
- $cached = $wpdb->get_row( $wpdb->prepare(
- "SELECT * FROM {$wpdb->prefix}wpaw_search_cache
- WHERE cache_key = %s
- AND expires_at > NOW()
- ORDER BY hit_count DESC
- LIMIT 1",
- $cache_key
- ) );
-
- if ( $cached ) {
- // Update cache stats
- $wpdb->update(
- $wpdb->prefix . 'wpaw_search_cache',
- array(
- 'hit_count' => $cached->hit_count + 1,
- 'cost_saved' => $cached->cost_saved + $this->calculate_cost(),
- ),
- array( 'id' => $cached->id )
- );
-
- $age_seconds = time() - strtotime( $cached->cached_at );
-
- return array(
- 'results' => json_decode( $cached->results_json, true ),
- 'age_hours' => ceil( $age_seconds / 3600 ),
- );
- }
-
- return null;
- }
-
- /**
- * Store search in database
- */
- private function store_search( $query, $response, $cost, $options = array() ) {
- global $wpdb;
-
- $top_result = $response['web']['results'][0] ?? null;
-
- $wpdb->insert(
- $wpdb->prefix . 'wpaw_searches',
- array(
- 'post_id' => $options['post_id'] ?? 0,
- 'search_query' => $query,
- 'search_number' => $options['search_number'] ?? 1,
- 'total_searches_for_post' => $options['total_searches'] ?? 1,
- 'results_count' => count( $response['web']['results'] ?? array() ),
- 'results_json' => wp_json_encode( $response ),
- 'top_result_title' => $top_result['title'] ?? null,
- 'top_result_url' => $top_result['url'] ?? null,
- 'cost' => $cost,
- 'api_tier' => $this->tier,
- 'search_category' => $options['category'] ?? 'general',
- 'status' => 'completed',
- )
- );
-
- return $wpdb->insert_id;
- }
-
- /**
- * Cache search results
- */
- private function cache_results( $query, $response, $options = array() ) {
- global $wpdb;
-
- $settings = get_option( 'wp_agentic_writer_settings', array() );
- $cache_days = absint( $settings['brave_cache_duration_days'] ?? 30 );
-
- $cache_key = sha1( strtolower( trim( $query ) ) );
-
- $wpdb->insert(
- $wpdb->prefix . 'wpaw_search_cache',
- array(
- 'search_query_normalized' => strtolower( trim( $query ) ),
- 'search_category' => $options['category'] ?? null,
- 'cache_key' => $cache_key,
- 'results_json' => wp_json_encode( $response ),
- 'result_count' => count( $response['web']['results'] ?? array() ),
- 'expires_at' => gmdate( 'Y-m-d H:i:s', strtotime( "+{$cache_days} days" ) ),
- 'quality_score' => 0.9,
- )
- );
- }
-
- /**
- * Calculate cost per search
- */
- private function calculate_cost() {
- $tiers = array(
- 'free' => 0,
- 'base_ai' => 0.005,
- 'pro_ai' => 0.009,
- );
-
- return $tiers[ $this->tier ] ?? 0;
- }
-
- /**
- * Check monthly budget
- */
- private function check_budget() {
- global $wpdb;
-
- $settings = get_option( 'wp_agentic_writer_settings', array() );
- $budget_limit = floatval( $settings['brave_monthly_budget'] ?? 50.00 );
-
- $monthly_cost = $wpdb->get_var(
- "SELECT COALESCE(SUM(cost), 0) FROM {$wpdb->prefix}wpaw_searches
- WHERE MONTH(created_at) = MONTH(NOW())
- AND YEAR(created_at) = YEAR(NOW())"
- );
-
- if ( $monthly_cost >= $budget_limit ) {
- return new WP_Error(
- 'budget_exceeded',
- sprintf( 'Monthly Brave Search budget of $%.2f exceeded', $budget_limit )
- );
- }
-
- return true;
- }
-
- /**
- * Track cost in cost tracker
- */
- private function track_cost( $cost, $post_id ) {
- do_action(
- 'wp_aw_after_api_request',
- $post_id,
- 'brave-search',
- 'web_search',
- 0, // No input tokens
- 0, // No output tokens
- $cost
- );
- }
-}
-```
-
----
-
-## REST API Endpoints
-
-### Add to `includes/class-gutenberg-sidebar.php`
-
-Add new REST endpoints for Brave Search:
-
-```php
-// In register_rest_routes() method, add:
-
-// Brave Search endpoint
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/brave-search',
- array(
- 'methods' => 'POST',
- 'callback' => array( $this, 'handle_brave_search' ),
- 'permission_callback' => array( $this, 'check_permissions' ),
- 'args' => array(
- 'query' => array(
- 'required' => true,
- 'type' => 'string',
- ),
- 'postId' => array(
- 'required' => true,
- 'type' => 'integer',
- ),
- 'category' => array(
- 'type' => 'string',
- 'default' => 'general',
- ),
- 'useCache' => array(
- 'type' => 'boolean',
- 'default' => true,
- ),
- ),
- )
-);
-
-// Get searches for post
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/searches/(?P\d+)',
- array(
- 'methods' => 'GET',
- 'callback' => array( $this, 'handle_get_searches' ),
- 'permission_callback' => array( $this, 'check_permissions' ),
- )
-);
-```
-
-### Handler Methods
-
-```php
-/**
- * Handle Brave Search request
- */
-public function handle_brave_search( $request ) {
- $query = $request->get_param( 'query' );
- $post_id = $request->get_param( 'postId' );
- $category = $request->get_param( 'category' );
- $use_cache = $request->get_param( 'useCache' );
-
- $provider = WP_Agentic_Writer_Brave_Search_Provider::get_instance();
-
- $result = $provider->search(
- $query,
- array(
- 'post_id' => $post_id,
- 'category' => $category,
- 'use_cache' => $use_cache,
- )
- );
-
- if ( is_wp_error( $result ) ) {
- return new WP_Error(
- $result->get_error_code(),
- $result->get_error_message(),
- array( 'status' => 400 )
- );
- }
-
- return rest_ensure_response( $result );
-}
-
-/**
- * Get all searches for a post
- */
-public function handle_get_searches( $request ) {
- global $wpdb;
-
- $post_id = $request->get_param( 'post_id' );
-
- if ( ! current_user_can( 'edit_post', $post_id ) ) {
- return new WP_Error( 'unauthorized', 'Not allowed', array( 'status' => 403 ) );
- }
-
- $searches = $wpdb->get_results( $wpdb->prepare(
- "SELECT * FROM {$wpdb->prefix}wpaw_searches
- WHERE post_id = %d
- ORDER BY created_at DESC",
- $post_id
- ) );
-
- $citations = $wpdb->get_results( $wpdb->prepare(
- "SELECT * FROM {$wpdb->prefix}wpaw_citations
- WHERE post_id = %d
- ORDER BY citation_number ASC",
- $post_id
- ) );
-
- return rest_ensure_response( array(
- 'searches' => $searches,
- 'citations' => $citations,
- 'total_cost' => array_sum( array_map( function( $s ) {
- return floatval( $s->cost );
- }, $searches ) ),
- ) );
-}
-```
-
----
-
-## Frontend Integration
-
-### Update `assets/js/sidebar.js`
-
-Add Brave Search support to the frontend:
-
-```javascript
-// Add to state management (around line 50)
-const [webSearchProvider, setWebSearchProvider] = useState('openrouter');
-const [braveSearchEnabled, setBraveSearchEnabled] = useState(false);
-
-// Load settings on mount
-useEffect(() => {
- const settings = wpAgenticWriter.settings || {};
- setWebSearchProvider(settings.web_search_provider || 'openrouter');
- setBraveSearchEnabled(settings.brave_search_enabled || false);
-}, []);
-
-// Add Brave Search function
-const performBraveSearch = async (query, category = 'general') => {
- try {
- const response = await fetch(wpAgenticWriter.apiUrl + '/brave-search', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-WP-Nonce': wpAgenticWriter.nonce,
- },
- body: JSON.stringify({
- query: query,
- postId: postId,
- category: category,
- useCache: true,
- }),
- });
-
- if (!response.ok) {
- throw new Error('Brave Search failed');
- }
-
- const data = await response.json();
-
- // Track cost
- if (data.cost) {
- setCost(prev => ({ ...prev, session: prev.session + data.cost }));
- }
-
- return data;
- } catch (error) {
- console.error('Brave Search error:', error);
- return null;
- }
-};
-
-// Modify article generation to use selected provider
-// In sendMessage() or executePlanFromCard(), check provider:
-if (webSearchProvider === 'brave' && braveSearchEnabled) {
- // Use Brave Search flow
- // Perform searches, then pass results to agent
-} else {
- // Use OpenRouter :online models
- // Existing flow
-}
-```
-
----
-
-## Agent Integration
-
-### Research Planning
-
-Create helper class for automatic search planning:
-
-**New File:** `includes/class-research-planner.php`
-
-```php
- "$topic what is overview",
- 'category' => 'definition',
- 'priority' => 'critical',
- );
-
- if ( 'medium' === $depth || 'deep' === $depth ) {
- // Current state
- $searches[] = array(
- 'query' => "$topic latest news 2024",
- 'category' => 'news',
- 'priority' => 'high',
- );
-
- // Pricing/features
- $searches[] = array(
- 'query' => "$topic pricing features comparison",
- 'category' => 'pricing',
- 'priority' => 'high',
- );
- }
-
- if ( 'deep' === $depth ) {
- // Use cases
- $searches[] = array(
- 'query' => "$topic use cases examples",
- 'category' => 'examples',
- 'priority' => 'medium',
- );
-
- // Technical details
- $searches[] = array(
- 'query' => "$topic documentation api guide",
- 'category' => 'technical',
- 'priority' => 'medium',
- );
- }
-
- return $searches;
- }
-}
-```
-
-### Citation Management
-
-**New File:** `includes/class-citation-manager.php`
-
-```php
- $citation_number,
- 'source' => $source,
- );
-
- $citation_number++;
- }
-
- // Add References section
- $references = self::generate_references_section( $citations );
- $content .= "\n\n" . $references;
-
- return array(
- 'content' => $content,
- 'citations' => $citations,
- );
- }
-
- /**
- * Find source in search results
- */
- private static function find_source_by_marker( $marker, $search_results ) {
- // Match marker to search result URL/title
- foreach ( $search_results as $search ) {
- if ( empty( $search['results']['web']['results'] ) ) {
- continue;
- }
-
- foreach ( $search['results']['web']['results'] as $result ) {
- $domain = parse_url( $result['url'], PHP_URL_HOST );
-
- if ( stripos( $domain, $marker ) !== false ||
- stripos( $result['title'], $marker ) !== false ) {
- return array(
- 'url' => $result['url'],
- 'title' => $result['title'],
- 'domain' => $domain,
- 'snippet' => $result['description'] ?? '',
- );
- }
- }
- }
-
- return null;
- }
-
- /**
- * Store citation in database
- */
- private static function store_citation( $post_id, $citation_number, $source ) {
- global $wpdb;
-
- $wpdb->insert(
- $wpdb->prefix . 'wpaw_citations',
- array(
- 'post_id' => $post_id,
- 'citation_number' => $citation_number,
- 'source_url' => $source['url'],
- 'source_title' => $source['title'],
- 'source_domain' => $source['domain'],
- 'added_by' => 'agent_automatic',
- )
- );
- }
-
- /**
- * Generate References section HTML
- */
- private static function generate_references_section( $citations ) {
- if ( empty( $citations ) ) {
- return '';
- }
-
- $html = "## References\n\n";
-
- foreach ( $citations as $citation ) {
- $source = $citation['source'];
- $html .= sprintf(
- "%d. [%s](%s) - %s\n",
- $citation['number'],
- $source['title'],
- $source['url'],
- $source['domain']
- );
- }
-
- return $html;
- }
-}
-```
-
----
-
-## Cost Tracking Integration
-
-Brave Search costs are automatically tracked via the existing cost tracking system using the `wp_aw_after_api_request` action hook (already implemented in the provider class).
-
-### Display in Sidebar
-
-Update cost display to show Brave Search costs separately:
-
-```javascript
-// In sidebar.js cost display section
-
-
AI Models: ${cost.session.toFixed(4)}
- {braveSearchCost > 0 && (
-
Web Search: ${braveSearchCost.toFixed(4)}
- )}
-
Total: ${(cost.session + braveSearchCost).toFixed(4)}
-
-```
-
----
-
-## Implementation Phases
-
-### Phase 1: Foundation (Week 1)
-**Goal:** Basic Brave Search integration
-
-- [ ] Create database tables (activation hook)
-- [ ] Create `class-brave-search-provider.php`
-- [ ] Add settings fields to `class-settings.php`
-- [ ] Add UI to `tab-models.php`
-- [ ] Test API connectivity
-
-**Deliverable:** Can perform Brave searches via settings panel test button
-
-### Phase 2: REST API (Week 2)
-**Goal:** Frontend can call Brave Search
-
-- [ ] Add REST endpoints to `class-gutenberg-sidebar.php`
-- [ ] Add frontend functions to `sidebar.js`
-- [ ] Test search from frontend
-- [ ] Implement caching logic
-- [ ] Test cache hit/miss scenarios
-
-**Deliverable:** Frontend can perform searches and see cached results
-
-### Phase 3: Agent Integration (Week 3)
-**Goal:** Agent uses Brave Search during article generation
-
-- [ ] Create `class-research-planner.php`
-- [ ] Create `class-citation-manager.php`
-- [ ] Integrate into article generation flow
-- [ ] Add provider selection logic
-- [ ] Test end-to-end: topic → searches → article with citations
-
-**Deliverable:** Can generate articles with Brave Search and citations
-
-### Phase 4: Analytics & Polish (Week 4)
-**Goal:** Admin dashboard and optimization
-
-- [ ] Add search analytics tab to settings
-- [ ] Display cost breakdown
-- [ ] Show cache performance
-- [ ] Add budget alerts
-- [ ] Implement cache cleanup cron
-- [ ] Add error handling and logging
-
-**Deliverable:** Complete admin experience with analytics
-
-### Phase 5: Testing & Documentation (Week 5)
-**Goal:** Production-ready
-
-- [ ] Test with free tier limits
-- [ ] Test with paid tiers
-- [ ] Test budget enforcement
-- [ ] Test cache expiry
-- [ ] Write user documentation
-- [ ] Create migration guide
-
-**Deliverable:** Production-ready feature with docs
-
----
-
-## File Structure
-
-### New Files to Create
-
-```
-includes/
-├── class-brave-search-provider.php ← Main provider class
-├── class-research-planner.php ← Auto search planning
-└── class-citation-manager.php ← Citation extraction
-
-views/settings/
-└── tab-brave-analytics.php ← Analytics dashboard (optional)
-```
-
-### Files to Modify
-
-```
-includes/
-├── class-settings.php ← Add Brave settings
-├── class-gutenberg-sidebar.php ← Add REST endpoints
-└── wp-agentic-writer.php ← Add table creation
-
-views/settings/
-└── tab-models.php ← Add Brave UI
-
-assets/js/
-└── sidebar.js ← Add Brave search functions
-
-CREATE_TABLE.sql ← Add table schemas
-```
-
----
-
-## Testing Strategy
-
-### Unit Tests
-
-1. **Provider Tests**
- - API authentication
- - Search query formatting
- - Response parsing
- - Error handling
-
-2. **Cache Tests**
- - Cache hit/miss
- - Expiry logic
- - Cost savings calculation
-
-3. **Budget Tests**
- - Monthly limit enforcement
- - Alert triggering
- - Cost tracking accuracy
-
-### Integration Tests
-
-1. **Settings Flow**
- - Save Brave API key
- - Switch providers
- - Enable/disable features
-
-2. **Search Flow**
- - Perform search
- - Cache result
- - Reuse cached result
- - Track cost
-
-3. **Article Generation Flow**
- - Plan searches
- - Execute searches
- - Generate article with citations
- - Add References section
-
-### User Acceptance Tests
-
-1. **Free Tier User**
- - Set up with free API key
- - Generate article (2-3 searches)
- - Verify cost tracking
- - Test monthly limit
-
-2. **Paid Tier User**
- - Set up with paid API key
- - Generate multiple articles
- - Verify cache reuse
- - Check cost savings
-
-3. **OpenRouter User**
- - Keep using OpenRouter :online
- - Verify no breaking changes
- - Test switching between providers
-
----
-
-## Migration & Compatibility
-
-### Backward Compatibility
-
-- **No breaking changes:** Existing OpenRouter functionality remains unchanged
-- **Opt-in feature:** Brave Search only activates when API key is set
-- **Default behavior:** If no Brave API key, falls back to OpenRouter :online
-- **Settings migration:** No migration needed - new settings are additive
-
-### Rollout Strategy
-
-1. **Beta Phase:** Release to select users for testing
-2. **Documentation:** Create setup guide and comparison chart
-3. **Announcement:** Blog post explaining benefits
-4. **Support:** Monitor for issues and provide quick fixes
-
----
-
-## Cost Comparison Example
-
-### Scenario: Generate 10 articles with web research
-
-**OpenRouter :online (Perplexity Sonar Pro)**
-- Model: `perplexity/sonar-pro`
-- Cost: ~$15 per 1M tokens
-- Average: 50K tokens per article with research
-- Total: 500K tokens = **$7.50**
-
-**Brave Search API + Standard Model**
-- Brave: 3 searches per article × 10 articles = 30 searches
-- Brave cost: 30 × $0.005 = **$0.15**
-- AI model: `google/gemini-2.0-flash-exp` (free or $0.075/1M)
-- AI tokens: 30K tokens per article (no search overhead)
-- AI cost: 300K tokens = **$0.02**
-- Total: **$0.17** (97% cheaper!)
-
-**With Caching (60% hit rate)**
-- Brave: 12 fresh + 18 cached = 12 × $0.005 = **$0.06**
-- AI cost: **$0.02**
-- Total: **$0.08** (99% cheaper!)
-
----
-
-## Next Steps
-
-1. **Review this plan** with stakeholders
-2. **Set up Brave Search API account** (free tier for testing)
-3. **Begin Phase 1 implementation** (database + provider class)
-4. **Create test environment** with sample searches
-5. **Iterate based on feedback**
-
----
-
-## Questions & Decisions Needed
-
-1. **Should we support both providers simultaneously?**
- - Current plan: User chooses one provider per article
- - Alternative: Use both (Brave for facts, OpenRouter for reasoning)
-
-2. **Citation format preference?**
- - Current plan: Numbered [1], [2]... with References section
- - Alternative: Inline links, footnotes, or custom format
-
-3. **Cache invalidation strategy?**
- - Current plan: 30-day automatic expiry
- - Alternative: Manual invalidation, topic-based expiry
-
-4. **Budget alert method?**
- - Current plan: Email to admin
- - Alternative: Dashboard notification, Slack webhook
-
----
-
-**Document Status:** Ready for Implementation
-**Last Updated:** January 29, 2026
-**Version:** 1.0
diff --git a/CLARIFICATION_QUIZ_FIXES.md b/CLARIFICATION_QUIZ_FIXES.md
deleted file mode 100644
index 76041e0..0000000
--- a/CLARIFICATION_QUIZ_FIXES.md
+++ /dev/null
@@ -1,154 +0,0 @@
-# Clarification Quiz Fixes - Complete
-
-## Issues Fixed
-
-### 1. ✅ Generate After Clarification
-**Problem**: Quiz answers weren't being passed to article generation, and `detectedLanguage` was missing.
-
-**Fixed**:
-- Added `detectedLanguage: detectedLanguage` to the API request in `submitAnswers()` (line 1083)
-- Now language detection flows through properly from clarity check → quiz → generation
-
-### 2. ✅ Loading Status
-**Problem**: No proper loading state during clarification flow, and no timeout protection.
-
-**Fixed**:
-- Added 2-minute timeout detection (lines 1103-1114)
-- Shows user-friendly timeout error message if AI hangs
-- Properly clears timeout on completion/error
-- `setIsLoading( true )` at start, `setIsLoading( false )` on completion/error
-
-### 3. ✅ Separate Conversational and Timeline Messages
-**Problem**: All messages were appearing as chat bubbles, including progress updates like "I'll write...".
-
-**Fixed**:
-- Applied the same progress detection logic from `sendMessage()` to `submitAnswers()`
-- Progress updates (starting with "I'll", "Writing", "Now", "Creating", etc.) → Timeline entries with ✍️ icon
-- Actual conversational content → Chat bubbles
-- Removed "~~~ARTICLE~~~" markers properly
-- Empty content after cleaning is skipped
-
-**Added handlers** (lines 1147-1218):
-```javascript
-// Check if this looks like a progress update
-const isProgressUpdate = /^(I'll|Writing|Now|Creating|Adding|Let me|I'll write)/i.test( cleanContent );
-
-if ( isProgressUpdate ) {
- // Add as timeline entry with ✍️ icon
-} else {
- // Add as chat bubble
-}
-```
-
-### 4. ✅ Title Update Handling
-**Problem**: Post title wasn't being updated after generation.
-
-**Fixed**:
-- Added `title_update` type handler (lines 1130-1131)
-- Uses `dispatch( 'core/editor' ).editPost( { title: data.title } )`
-- Same as working implementation in `sendMessage()`
-
-### 5. ✅ Status Timeline Updates
-**Problem**: Status updates weren't showing in timeline during generation.
-
-**Fixed**:
-- Added `status` type handler (lines 1132-1146)
-- Updates timeline entry with current status, message, and icon
-- Shows "Connecting to AI...", "Creating article outline...", "Writing content..." etc.
-
-### 6. ✅ Error Handling
-**Problem**: Errors were showing `alert()` instead of chat messages.
-
-**Fixed**:
-- Changed `alert()` to proper error chat bubbles (line 1089-1093)
-- Errors now appear in the chat interface consistently
-- Added error type handler with timeout cleanup (lines 1269-1276)
-
----
-
-## Complete Flow Now Works
-
-1. **User sends message** → Clarity check
-2. **Clarity check detects language** → Stores in `detectedLanguage` state
-3. **Quiz appears** (if needed) → User answers in detected language
-4. **User clicks Continue** → `submitAnswers()` called
-5. **Loading state activated** → Timeline shows "Generating article..."
-6. **API called with**:
- - `clarificationAnswers`: Quiz answers
- - `detectedLanguage`: Detected from initial prompt
-7. **Streaming responses**:
- - `status` → Timeline updates (📋, ✍️ icons)
- - `title_update` → Post title updated
- - `conversational_stream` → Progress updates in timeline
- - `conversational` → Actual chat content as bubbles
- - `block` → Content inserted into editor
- - `complete` → Timeline shows ✅ + completion message
-8. **Timeout protection** → 2-minute timeout if AI hangs
-9. **Error handling** → User-friendly error messages in chat
-
----
-
-## Files Modified
-
-**[assets/js/sidebar.js](assets/js/sidebar.js)**
-- `submitAnswers()` function completely rewritten (lines 1046-1299)
-- Added: `detectedLanguage` parameter
-- Added: Timeout handling
-- Added: Progress/timeline separation
-- Added: Title update handling
-- Added: Status updates
-- Fixed: Error messages (no more alerts)
-- Removed: Duplicate code causing syntax errors
-
----
-
-## Testing Checklist
-
-### Clarification Quiz Flow:
-- [ ] Quiz appears for vague prompts
-- [ ] Quiz questions in detected language (Indonesian/English)
-- [ ] Answers captured correctly
-- [ ] Continue button triggers generation
-- [ ] Timeline shows "Generating article..." immediately
-
-### Article Generation After Quiz:
-- [ ] Quiz answers passed to backend
-- [ ] Detected language passed to backend
-- [ ] Plan generated in detected language
-- [ ] Article content in detected language (no mixed language)
-- [ ] Post title updated correctly
-- [ ] Progress updates in timeline (not chat bubbles)
-- [ ] Completion message as chat bubble
-
-### Error Handling:
-- [ ] Timeout shows error message after 2 minutes
-- [ ] API errors show in chat (not alerts)
-- [ ] Loading state cleared on error
-- [ ] User can try again after error
-
-### Visual Distinction:
-- [ ] Timeline entries have icons (📝, ✍️, ✅, ❓)
-- [ ] Progress updates: "Saya akan menulis..." → Timeline with ✍️
-- [ ] Conversational: "Halo! Artikel selesai." → Chat bubble
-- [ ] No "~~~ARTICLE~~~" markers visible
-- [ ] Status updates update existing timeline entry
-
----
-
-## Key Features Now Working
-
-✅ **Language Detection Flow**: Clarity check → Store → Pass to generation → Enforce in AI
-✅ **Quiz Integration**: Answers properly formatted and passed to backend
-✅ **Visual Distinction**: Timeline vs Chat bubbles clearly separated
-✅ **Progress Feedback**: User sees what's happening in real-time
-✅ **Title Updates**: Post title automatically updated from generated plan
-✅ **Timeout Protection**: 2-minute timeout prevents infinite hanging
-✅ **Error Handling**: User-friendly errors in chat interface
-✅ **Loading States**: Proper loading indication throughout flow
-
----
-
-**Status**: ✅ All 4 issues fixed
-**Files Modified**: 1 (assets/js/sidebar.js)
-**Lines Changed**: ~250 lines in submitAnswers() function
-**Testing**: Ready for user testing
diff --git a/CONTEXT_FLOW_ANALYSIS.md b/CONTEXT_FLOW_ANALYSIS.md
deleted file mode 100644
index aef2e4e..0000000
--- a/CONTEXT_FLOW_ANALYSIS.md
+++ /dev/null
@@ -1,741 +0,0 @@
-# Context Flow Analysis: Chat, Planning, and Writing Modes
-
-**Date:** January 25, 2026
-**Version:** 0.1.3+
-**Purpose:** Comprehensive analysis of context preservation across different user interaction flows
-
----
-
-## 🎯 Executive Summary
-
-This document analyzes how context (chat history, post configuration, language detection, and plan data) is preserved or lost across different user interaction flows in the WP Agentic Writer plugin. It identifies **12 distinct user flows**, maps their context behavior, and provides recommendations for improvements.
-
-**Key Finding:** Context preservation varies significantly depending on the flow path, with some flows maintaining full context while others may lose critical information.
-
----
-
-## 📊 Context Storage Mechanisms
-
-### **1. Post Meta Storage**
-
-The plugin stores context in WordPress post meta:
-
-| Meta Key | Content | Updated By | Used By |
-|----------|---------|------------|---------|
-| `_wpaw_chat_history` | Array of user/assistant messages | `update_post_chat_history()` | Chat mode, Plan generation |
-| `_wpaw_plan` | JSON outline structure | `stream_generate_plan()` | Article execution |
-| `_wpaw_detected_language` | Language code (e.g., 'Indonesian') | `stream_generate_plan()` | All modes |
-| `_wpaw_post_config` | Post configuration (tone, audience, SEO) | `update_post_config()` | All modes |
-| `_wpaw_memory` | Last prompt/intent tracking | `update_post_memory()` | Internal tracking |
-
-### **2. Frontend State (React)**
-
-| State Variable | Scope | Persistence |
-|----------------|-------|-------------|
-| `messages` | Component state | Session only (lost on refresh) |
-| `agentMode` | localStorage | Persists across sessions |
-| `postConfig` | Component state | Session only |
-| `currentPlan` | useRef | Session only |
-
-### **3. Request Parameters**
-
-Context is passed via REST API requests:
-- `chatHistory` - Array of messages from frontend
-- `postConfig` - Current configuration
-- `detectedLanguage` - Language from clarity quiz
-- `clarificationAnswers` - Answers from clarity quiz
-
----
-
-## 🔄 User Interaction Flows
-
-### **Flow 1: Standard Flow (Chat → Planning → Writing)**
-
-**Path:** Chat mode → Ask for outline → Planning mode generates plan → Click "Start Writing" → Writing mode executes
-
-**Context Behavior:**
-
-```
-1. User types in Chat mode
- ├─ Messages stored in frontend state
- ├─ Chat history saved to post meta (_wpaw_chat_history)
- └─ Language detected and stored (_wpaw_detected_language)
-
-2. Planning mode generates outline
- ├─ Receives: chatHistory from frontend
- ├─ Builds: chat_history_context from chatHistory array
- ├─ Stores: Plan in _wpaw_plan
- ├─ Stores: Language in _wpaw_detected_language
- └─ Keywords auto-suggested (if SEO enabled)
-
-3. Click "Start Writing"
- ├─ Reads: _wpaw_plan (required)
- ├─ Reads: _wpaw_detected_language
- ├─ Reads: postConfig from frontend
- └─ Generates article with full context
-```
-
-**Context Preservation:** ✅ **EXCELLENT**
-- Chat history: ✅ Available via chatHistory parameter
-- Plan: ✅ Stored in post meta
-- Language: ✅ Stored in post meta
-- Post config: ✅ Passed from frontend
-
-**Potential Issues:** None - This is the ideal flow.
-
----
-
-### **Flow 2: Direct Writing Mode (No Chat, No Planning)**
-
-**Path:** Switch to Writing mode → Type instruction → Send
-
-**Context Behavior:**
-
-```
-1. User switches to Writing mode
- ├─ Frontend: agentMode = 'writing'
- └─ No chat history built
-
-2. User types instruction
- ├─ Frontend sends to /chat endpoint with type='writing'
- ├─ Backend: handle_chat_request()
- ├─ No plan required for chat endpoint
- └─ Response returned
-
-3. If user wants to generate article
- ├─ Must have a plan (_wpaw_plan)
- └─ ERROR: "No plan found. Please generate a plan first."
-```
-
-**Context Preservation:** ⚠️ **LIMITED**
-- Chat history: ✅ Can be built from messages
-- Plan: ❌ **NOT AVAILABLE** - Cannot execute article
-- Language: ⚠️ May not be detected
-- Post config: ✅ Available from frontend
-
-**Issues:**
-1. **Cannot execute article without plan** - Writing mode chat doesn't create a plan
-2. **User confusion** - Writing mode suggests article generation but can't deliver
-3. **No outline context** - AI has no structure to follow
-
-**Recommendation:**
-- Writing mode should either:
- - A) Auto-generate a minimal plan from the instruction, OR
- - B) Show clear error: "Please create an outline first (switch to Planning mode)"
-
----
-
-### **Flow 3: Chat → Direct Writing (Skip Planning)**
-
-**Path:** Chat mode → Build context → Switch to Writing mode → Type instruction → Send
-
-**Context Behavior:**
-
-```
-1. User chats in Chat mode
- ├─ Chat history built in frontend state
- ├─ Saved to _wpaw_chat_history
- └─ Language may be detected
-
-2. User switches to Writing mode
- ├─ Frontend: agentMode = 'writing'
- └─ Chat history still in frontend state
-
-3. User types instruction in Writing mode
- ├─ Sends to /chat endpoint with type='writing'
- ├─ chatHistory parameter: ⚠️ NOT SENT (only sent to /generate-plan)
- ├─ Backend has no access to previous chat
- └─ Response generated without chat context
-
-4. If user tries to execute article
- └─ ERROR: "No plan found"
-```
-
-**Context Preservation:** ❌ **POOR**
-- Chat history: ❌ **LOST** - Not sent to /chat endpoint in writing mode
-- Plan: ❌ Not available
-- Language: ⚠️ May be stored from earlier chat
-- Post config: ✅ Available
-
-**Issues:**
-1. **Chat context lost** - Previous conversation not available to AI
-2. **No plan** - Cannot execute article
-3. **Inconsistent behavior** - User expects context to carry over
-
-**Recommendation:**
-- Send `chatHistory` parameter to `/chat` endpoint for all modes
-- OR retrieve `_wpaw_chat_history` from post meta in backend
-
----
-
-### **Flow 4: Planning → Manual Mode Switch → Writing**
-
-**Path:** Planning mode → Generate outline → Manually switch to Writing → Add note → Send
-
-**Context Behavior:**
-
-```
-1. Planning mode generates outline
- ├─ Plan stored in _wpaw_plan
- ├─ Language stored
- └─ Chat history stored
-
-2. User manually switches to Writing mode
- ├─ Frontend: agentMode = 'writing'
- └─ Plan still in post meta
-
-3. User adds additional note
- ├─ Sends to /chat endpoint with type='writing'
- ├─ chatHistory: ⚠️ NOT SENT
- ├─ AI responds without knowing about the plan
- └─ User's note not incorporated into plan
-
-4. User tries to execute article
- ├─ Reads _wpaw_plan (original plan, unchanged)
- ├─ User's additional note: ❌ NOT INCLUDED
- └─ Article generated from original plan only
-```
-
-**Context Preservation:** ⚠️ **PARTIAL**
-- Chat history: ❌ Not sent to writing mode chat
-- Plan: ✅ Available but not updated
-- Language: ✅ Available
-- Post config: ✅ Available
-- **User's additional note:** ❌ **LOST**
-
-**Issues:**
-1. **Additional instructions ignored** - User's note in writing mode doesn't update plan
-2. **Confusing UX** - User expects their note to be incorporated
-3. **No plan revision** - Writing mode chat doesn't trigger plan update
-
-**Recommendation:**
-- Writing mode should either:
- - A) Update the plan with user's additional instructions, OR
- - B) Store the note and append it to execution prompt, OR
- - C) Show warning: "To modify the outline, switch back to Planning mode"
-
----
-
-### **Flow 5: Direct Planning Mode (No Chat)**
-
-**Path:** Switch to Planning mode → Type topic → Generate outline
-
-**Context Behavior:**
-
-```
-1. User switches to Planning mode
- └─ No prior chat history
-
-2. User types topic
- ├─ Sends to /generate-plan endpoint
- ├─ chatHistory: [] (empty)
- ├─ chat_history_context: "" (empty)
- └─ Plan generated from topic only
-
-3. Plan generation
- ├─ Stores plan in _wpaw_plan
- ├─ Detects and stores language
- └─ No chat history to reference
-```
-
-**Context Preservation:** ✅ **GOOD**
-- Chat history: N/A (none exists)
-- Plan: ✅ Generated and stored
-- Language: ✅ Detected and stored
-- Post config: ✅ Available
-
-**Issues:** None - This is a valid flow for quick outline generation.
-
----
-
-### **Flow 6: Chat → Planning with Clarity Quiz**
-
-**Path:** Chat mode → Build context → Planning mode → Clarity quiz appears → Answer questions → Generate
-
-**Context Behavior:**
-
-```
-1. User chats in Chat mode
- ├─ Chat history built
- └─ Language detected
-
-2. Planning mode triggers clarity quiz
- ├─ Frontend: setInClarification(true)
- └─ Quiz questions shown
-
-3. User answers quiz
- ├─ Answers stored in frontend state
- └─ postConfig updated with answers
-
-4. Submit quiz
- ├─ Sends to /generate-plan with:
- │ ├─ clarificationAnswers
- │ ├─ chatHistory ✅
- │ ├─ postConfig ✅
- │ └─ detectedLanguage ✅
- └─ Plan generated with full context
-```
-
-**Context Preservation:** ✅ **EXCELLENT**
-- Chat history: ✅ Sent via chatHistory
-- Clarity answers: ✅ Sent via clarificationAnswers
-- Language: ✅ Sent via detectedLanguage
-- Post config: ✅ Updated with quiz answers
-
-**Issues:** None - This is the ideal flow with maximum context.
-
----
-
-### **Flow 7: Writing Mode → @block Refinement**
-
-**Path:** Article generated → Switch to Writing mode → Use @block mention → Refine specific block
-
-**Context Behavior:**
-
-```
-1. Article already generated
- ├─ Content in Gutenberg blocks
- └─ Plan in _wpaw_plan
-
-2. User types "@block-id refine this section"
- ├─ Frontend detects @mention
- ├─ Sends to /refine-block endpoint
- └─ NOT to /chat endpoint
-
-3. Block refinement
- ├─ Receives: block content, refinement request
- ├─ Receives: articleContext (surrounding blocks)
- ├─ Receives: postConfig
- ├─ chatHistory: ❌ NOT SENT
- └─ Refinement done without chat context
-```
-
-**Context Preservation:** ⚠️ **PARTIAL**
-- Block content: ✅ Available
-- Article context: ✅ Sent (surrounding blocks)
-- Post config: ✅ Available
-- Chat history: ❌ Not sent
-- Original plan: ⚠️ Not explicitly sent
-
-**Issues:**
-1. **Chat context lost** - Previous conversation not available
-2. **Original intent unclear** - AI doesn't know user's original goals
-
-**Recommendation:**
-- Include `chatHistory` or at least last few messages in refinement requests
-- Include original plan section for context
-
----
-
-### **Flow 8: Multiple Chat Sessions (Page Refresh)**
-
-**Path:** Chat → Build context → Refresh page → Continue chatting
-
-**Context Behavior:**
-
-```
-1. First session
- ├─ Chat history in frontend state
- └─ Saved to _wpaw_chat_history post meta
-
-2. Page refresh
- ├─ Frontend state: ❌ CLEARED
- ├─ Post meta: ✅ PERSISTS
- └─ agentMode: ✅ Restored from localStorage
-
-3. Continue chatting
- ├─ Frontend loads chat history from post meta
- ├─ Displays previous messages
- ├─ New messages appended
- └─ Context maintained
-```
-
-**Context Preservation:** ✅ **GOOD**
-- Chat history: ✅ Restored from post meta
-- Plan: ✅ Persists in post meta
-- Language: ✅ Persists in post meta
-- Post config: ⚠️ May need to be re-fetched
-
-**Issues:**
-1. **Initial load delay** - Need to fetch chat history from backend
-2. **Post config sync** - May not reflect latest changes immediately
-
-**Recommendation:**
-- Ensure chat history is loaded on component mount
-- Fetch post config from backend on load
-
----
-
-### **Flow 9: Plan Revision in Planning Mode**
-
-**Path:** Planning mode → Generate outline → User asks for changes → Plan revised
-
-**Context Behavior:**
-
-```
-1. Initial plan generated
- ├─ Plan stored in _wpaw_plan
- └─ Displayed in frontend
-
-2. User types revision request
- ├─ Frontend detects existing plan
- ├─ Calls revisePlanFromPrompt()
- ├─ Sends to /revise-plan endpoint
- └─ NOT to /generate-plan
-
-3. Plan revision
- ├─ Receives: instruction, current plan
- ├─ Receives: postConfig
- ├─ chatHistory: ⚠️ NOT EXPLICITLY SENT
- ├─ Generates revised plan
- └─ Updates _wpaw_plan
-```
-
-**Context Preservation:** ✅ **GOOD**
-- Current plan: ✅ Sent explicitly
-- Post config: ✅ Available
-- Chat history: ⚠️ Not sent but may not be needed
-- Language: ✅ Available from post meta
-
-**Issues:**
-1. **Chat context not used** - Previous conversation not considered
-2. **Revision-only context** - AI only sees current plan + new instruction
-
-**Recommendation:**
-- Consider sending recent chat history for better context
-- OR document that plan revision is isolated from chat history
-
----
-
-### **Flow 10: SEO Keyword Suggestion Flow**
-
-**Path:** Planning mode → Generate outline → Keywords auto-suggested → Clarity quiz pre-filled
-
-**Context Behavior:**
-
-```
-1. Outline generated
- ├─ Plan stored
- └─ Frontend receives plan
-
-2. Auto-trigger keyword suggestion
- ├─ Calls /suggest-keywords endpoint
- ├─ Sends: title, sections, language
- ├─ chatHistory: ❌ NOT SENT
- └─ Keywords suggested based on outline only
-
-3. Keywords returned
- ├─ Stored in frontend state
- ├─ Pre-filled in clarity quiz
- └─ User can edit before submission
-
-4. Clarity quiz submitted
- ├─ Keywords saved to postConfig
- └─ Used in article generation
-```
-
-**Context Preservation:** ✅ **GOOD**
-- Outline: ✅ Sent to keyword suggester
-- Language: ✅ Sent
-- Chat history: ❌ Not sent (not needed)
-- Keywords: ✅ Stored in postConfig
-
-**Issues:** None - Keywords are based on outline, which is sufficient context.
-
----
-
-### **Flow 11: Web Search Integration**
-
-**Path:** Chat/Planning with web search enabled → AI searches web → Results incorporated
-
-**Context Behavior:**
-
-```
-1. User enables web search
- ├─ postConfig.web_search = true
- └─ Passed to backend
-
-2. Chat or plan generation
- ├─ Backend builds web_search_options
- ├─ Passes to OpenRouter API
- └─ AI performs web search
-
-3. Search results
- ├─ Incorporated into AI response
- ├─ NOT stored separately
- └─ Included in chat history as part of response
-
-4. Subsequent requests
- ├─ Search results: ⚠️ Only in chat history
- └─ Not explicitly tracked
-```
-
-**Context Preservation:** ⚠️ **PARTIAL**
-- Search results: ⚠️ Only in chat history text
-- Search metadata: ❌ Not stored
-- Search queries: ❌ Not logged
-
-**Issues:**
-1. **No search audit trail** - Can't see what was searched
-2. **Search results ephemeral** - Lost if chat history cleared
-
-**Recommendation:**
-- Consider logging search queries and results
-- Store search metadata for debugging/auditing
-
----
-
-### **Flow 12: Multi-Block Batch Refinement**
-
-**Path:** Article generated → Select multiple blocks → Request batch refinement
-
-**Context Behavior:**
-
-```
-1. User selects multiple blocks
- ├─ Frontend: blocksToRefine array
- └─ allBlocks for context
-
-2. Batch refinement request
- ├─ Sends to /refine-blocks endpoint
- ├─ Receives: blocksToRefine, allBlocks, instruction
- ├─ Receives: postConfig
- ├─ chatHistory: ❌ NOT SENT
- ├─ Plan: ❌ NOT SENT
- └─ Refinement based on blocks + instruction only
-
-3. Refinement execution
- ├─ Each block refined individually
- ├─ Context: surrounding blocks
- └─ No cross-block coordination
-```
-
-**Context Preservation:** ⚠️ **LIMITED**
-- Block content: ✅ Available
-- Surrounding context: ✅ Available (allBlocks)
-- Post config: ✅ Available
-- Chat history: ❌ Not sent
-- Original plan: ❌ Not sent
-- Cross-block coordination: ❌ Not implemented
-
-**Issues:**
-1. **No chat context** - Original conversation lost
-2. **No plan context** - Original outline not referenced
-3. **Independent refinements** - Blocks refined in isolation
-
-**Recommendation:**
-- Send original plan section for each block
-- Consider chat history for understanding user intent
-- Implement cross-block coordination for consistency
-
----
-
-## 🔍 Context Loss Scenarios
-
-### **Critical Context Loss Issues**
-
-| Scenario | Lost Context | Impact | Severity |
-|----------|--------------|--------|----------|
-| Chat → Writing mode switch | Chat history not sent to /chat endpoint | AI doesn't know previous conversation | 🔴 HIGH |
-| Writing mode additional notes | Notes not incorporated into plan | User instructions ignored | 🔴 HIGH |
-| Block refinement | Chat history not available | Original intent unclear | 🟡 MEDIUM |
-| Page refresh | Frontend state cleared | Need to reload from backend | 🟢 LOW |
-| Web search results | Search metadata not stored | No audit trail | 🟢 LOW |
-
----
-
-## 💡 Recommendations
-
-### **Priority 1: Critical Fixes**
-
-1. **Send Chat History to All Modes**
- ```javascript
- // In sidebar.js - sendMessage function
- const payload = {
- messages: messages,
- postId: postId,
- type: agentMode,
- chatHistory: messages, // ✅ Add this
- postConfig: postConfig,
- stream: true
- };
- ```
-
-2. **Handle Writing Mode Notes**
- - Option A: Auto-update plan with additional instructions
- - Option B: Store notes and append to execution prompt
- - Option C: Show clear warning about mode limitations
-
-3. **Improve Block Refinement Context**
- ```php
- // In handle_refine_block
- $chat_history = $this->get_post_chat_history( $post_id );
- $plan = get_post_meta( $post_id, '_wpaw_plan', true );
- // Include in refinement prompt
- ```
-
-### **Priority 2: UX Improvements**
-
-4. **Mode-Specific Guidance**
- - Chat mode: "Building context for your article"
- - Planning mode: "Creating outline - chat history will be used"
- - Writing mode: "Refining content - outline required"
-
-5. **Context Indicators**
- - Show badge: "📝 Outline available"
- - Show badge: "💬 3 messages in context"
- - Show badge: "🔍 Web search enabled"
-
-6. **Error Messages**
- - Writing mode without plan: "Please create an outline first (switch to Planning mode)"
- - Refinement without context: "Loading article context..."
-
-### **Priority 3: Advanced Features**
-
-7. **Context Persistence Layer**
- ```php
- // Store comprehensive context
- update_post_meta( $post_id, '_wpaw_context', array(
- 'chat_history' => $chat_history,
- 'plan' => $plan,
- 'language' => $language,
- 'config' => $post_config,
- 'search_history' => $search_queries,
- 'refinement_history' => $refinements,
- ));
- ```
-
-8. **Context Debugging Tool**
- - Admin panel showing current context state
- - "What does the AI know?" button
- - Context timeline visualization
-
-9. **Smart Context Pruning**
- - Keep last N messages (configurable)
- - Summarize older context
- - Preserve critical information (plan, config)
-
----
-
-## 📋 Context Flow Matrix
-
-| Flow | Chat History | Plan | Language | Post Config | Notes |
-|------|--------------|------|----------|-------------|-------|
-| Chat → Planning → Writing | ✅ Full | ✅ Full | ✅ Full | ✅ Full | **Ideal flow** |
-| Direct Writing | ⚠️ Limited | ❌ None | ⚠️ Partial | ✅ Full | Cannot execute |
-| Chat → Writing (skip plan) | ❌ Lost | ❌ None | ⚠️ Partial | ✅ Full | Context lost |
-| Planning → Manual switch → Writing | ❌ Lost | ✅ Full | ✅ Full | ✅ Full | Notes ignored |
-| Direct Planning | N/A | ✅ Full | ✅ Full | ✅ Full | Valid flow |
-| Chat → Planning + Quiz | ✅ Full | ✅ Full | ✅ Full | ✅ Full | **Best flow** |
-| Writing → @block refinement | ❌ Lost | ⚠️ Partial | ✅ Full | ✅ Full | Limited context |
-| Page refresh → Continue | ✅ Restored | ✅ Full | ✅ Full | ⚠️ Partial | Need reload |
-| Plan revision | ⚠️ Partial | ✅ Full | ✅ Full | ✅ Full | Isolated |
-| Keyword suggestion | ❌ None | ✅ Full | ✅ Full | ✅ Full | Outline-based |
-| Web search | ✅ In history | ✅ Full | ✅ Full | ✅ Full | No metadata |
-| Batch refinement | ❌ Lost | ❌ Lost | ✅ Full | ✅ Full | Isolated blocks |
-
----
-
-## 🧪 Testing Checklist
-
-### **Test Each Flow**
-
-- [ ] **Flow 1:** Chat → Planning → Writing (baseline)
-- [ ] **Flow 2:** Direct Writing mode (expect error)
-- [ ] **Flow 3:** Chat → Writing (verify context loss)
-- [ ] **Flow 4:** Planning → Manual switch → Writing (verify note loss)
-- [ ] **Flow 5:** Direct Planning (verify works)
-- [ ] **Flow 6:** Chat → Planning + Quiz (verify full context)
-- [ ] **Flow 7:** @block refinement (verify limited context)
-- [ ] **Flow 8:** Page refresh (verify restoration)
-- [ ] **Flow 9:** Plan revision (verify isolation)
-- [ ] **Flow 10:** Keyword suggestion (verify works)
-- [ ] **Flow 11:** Web search (verify results)
-- [ ] **Flow 12:** Batch refinement (verify isolation)
-
-### **Context Verification**
-
-For each flow, verify:
-1. ✅ Chat history available to AI?
-2. ✅ Plan available when needed?
-3. ✅ Language correctly detected/used?
-4. ✅ Post config applied?
-5. ✅ User instructions incorporated?
-
----
-
-## 🎯 Ideal Context Flow (Recommended)
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ USER INTERACTION │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────┐
-│ FRONTEND (React) │
-│ • Maintains messages[] state │
-│ • Tracks agentMode (chat/planning/writing) │
-│ • Stores postConfig │
-│ • Holds currentPlan ref │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────┐
-│ EVERY API REQUEST │
-│ Should include: │
-│ ✅ chatHistory (last N messages) │
-│ ✅ postConfig (current configuration) │
-│ ✅ currentPlan (if available) │
-│ ✅ detectedLanguage (if known) │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────┐
-│ BACKEND (PHP) │
-│ • Retrieves additional context from post meta │
-│ • Merges frontend + backend context │
-│ • Builds comprehensive prompt │
-│ • Stores results back to post meta │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────┐
-│ AI RECEIVES │
-│ • Full chat history │
-│ • Current plan (if exists) │
-│ • Post configuration │
-│ • Language preference │
-│ • User's current instruction │
-│ = MAXIMUM CONTEXT │
-└─────────────────────────────────────────────────────────────┘
-```
-
----
-
-## 📝 Conclusion
-
-**Current State:**
-- ✅ Standard flow (Chat → Planning → Writing) works well
-- ⚠️ Alternative flows have context loss issues
-- ❌ Writing mode without planning is problematic
-- ❌ Chat history not sent to all endpoints
-
-**Recommended Actions:**
-
-1. **Immediate:** Send `chatHistory` to all API endpoints
-2. **Short-term:** Handle writing mode notes properly
-3. **Medium-term:** Add context indicators to UI
-4. **Long-term:** Implement comprehensive context persistence layer
-
-**Impact:**
-- Better AI responses (more context)
-- Fewer user frustrations (instructions not ignored)
-- More predictable behavior (consistent across flows)
-- Easier debugging (context visibility)
-
----
-
-**Analysis Date:** January 25, 2026
-**Status:** 🔴 CRITICAL ISSUES IDENTIFIED
-**Next Steps:** Implement Priority 1 fixes
diff --git a/CONTEXT_GAP_DIAGNOSTIC_REPORT.md b/CONTEXT_GAP_DIAGNOSTIC_REPORT.md
deleted file mode 100644
index ff70ed2..0000000
--- a/CONTEXT_GAP_DIAGNOSTIC_REPORT.md
+++ /dev/null
@@ -1,250 +0,0 @@
-# Context Gap Diagnostic Report
-
-**Date:** January 30, 2026
-**Issue:** Context lost during outline generation - Agent doesn't maintain conversation continuity
-**Severity:** High - Core agentic behavior broken
-
----
-
-## Executive Summary
-
-The agent loses context when generating outlines because:
-1. **Generic topic passed** instead of extracting actual topic from conversation
-2. **Chat history truncated** to last 10 messages (first message with core topic lost)
-3. **No topic extraction mechanism** - system relies on recency, not importance
-4. **Recency bias** - LLM sees recent refinements more than original intent
-
----
-
-## Conversation Flow Analysis
-
-### User's Conversation Timeline
-
-| Step | User Action | Agent Response | Context Status |
-|------|-------------|----------------|----------------|
-| 1 | Rich topic: "switch career usia 30+, AI, web design, vibe coding..." | Comprehensive response | FULL CONTEXT |
-| 2 | "tambahkan vibe coding" | Added vibe coding section | FULL CONTEXT |
-| 3 | "fokus opini, web design, tanpa coding" | Refined to web design focus | FULL CONTEXT |
-| 4 | Click "Create Outline Now" | Generated outline about "AI Web Design" | CONTEXT LOST |
-| 5 | User manually sets focus keyword, asks to redo | Regenerated with correct focus | RECOVERED (manually) |
-
-### Where Context Was Lost
-
-**Step 4: "Create Outline Now" button click**
-
-The outline focused on "AI-Powered Web Design" instead of the broader "Switch Career Usia 30+" topic that was the user's original intent.
-
----
-
-## Root Cause Analysis
-
-### Defect #1: Generic Topic Parameter
-
-**Location:** `assets/js/sidebar.js:4534`
-
-```javascript
-body: JSON.stringify({
- topic: outlineMessage, // "Create an outline based on our discussion"
- // ...
-})
-```
-
-**Problem:** The `topic` variable is set to the literal string `"Create an outline based on our discussion"` instead of extracting the actual topic from the first user message.
-
-**Impact:** The LLM receives a generic topic and must infer intent from chat history alone.
-
----
-
-### Defect #2: Chat History Truncation (.slice(-10))
-
-**Location:** `assets/js/sidebar.js:4543`
-
-```javascript
-chatHistory: messages.filter(m => m.role === 'user' || m.role === 'assistant').slice(-10),
-```
-
-**Problem:** Only the **last 10 messages** are sent to the backend. If the conversation has more than 10 exchanges, the **first user message (which contains the core topic)** is lost.
-
-**Your Conversation Analysis:**
-- Message 1: User's detailed topic request (CRITICAL - contains "switch career usia 30+")
-- Message 2: Agent's comprehensive response
-- Message 3: User adds "vibe coding"
-- Message 4: Agent responds about vibe coding
-- Message 5: User refines to "web design focus"
-- Message 6: Agent responds about web design
-- Message 7: User clicks "Create Outline Now" (adds another message)
-
-With `.slice(-10)`, the first message **might still be included** in this case, but the truncation creates fragility. The real issue is combined with Defect #1.
-
----
-
-### Defect #3: No Topic Extraction Mechanism
-
-**Location:** `includes/class-gutenberg-sidebar.php:1765`
-
-```php
-'content' => "Topic: {$topic}\n\nContext: {$context}{$chat_history_context}..."
-```
-
-**Problem:** The system doesn't extract the user's **original topic/intent** from the first message. It just appends chat history as context, but the LLM prompt structure puts emphasis on `{$topic}` which is generic.
-
-**What should happen:**
-1. Extract topic from first user message
-2. Store as "primary topic" in post memory
-3. Use primary topic in outline generation, not generic phrase
-
----
-
-### Defect #4: Recency Bias in LLM Processing
-
-**Problem:** When the LLM sees the chat history, the **most recent messages** (about web design) appear at the end and have more weight than earlier messages about the broader topic.
-
-**Chat History Seen by LLM:**
-```
-User: [switch career usia 30+ topic...] ← EARLY, less weight
-Assistant: [comprehensive response...]
-User: [add vibe coding...]
-Assistant: [vibe coding response...]
-User: [focus on web design...] ← RECENT, more weight
-Assistant: [web design response...] ← MOST RECENT, highest weight
-User: Create an outline based on our discussion
-```
-
-The LLM naturally focuses on the most recent topic (web design) rather than the original broader topic.
-
----
-
-### Defect #5: Memory System Doesn't Store Primary Topic
-
-**Location:** `includes/class-gutenberg-sidebar.php:4735-4748`
-
-```php
-private function update_post_memory( $post_id, $data ) {
- // Only stores: summary, last_prompt, last_intent
- // Does NOT store: primary_topic, original_intent, focus_keyword
-}
-```
-
-**Problem:** The memory system stores `last_prompt` but not `primary_topic`. When generating an outline, there's no reference to what the user originally wanted.
-
----
-
-## Impact Analysis
-
-| Aspect | Impact |
-|--------|--------|
-| User Experience | Frustrating - user must manually correct agent's misunderstanding |
-| Cost | Wasted API calls on incorrect outline generation |
-| Trust | User loses confidence in agent's ability to understand context |
-| Workflow | Broken agentic loop - requires human intervention |
-
----
-
-## Recommended Fixes
-
-### Fix #1: Extract and Store Primary Topic
-
-**Where:** When first user message is received in chat/planning mode
-
-```javascript
-// In sendMessage or chat handler
-if (messages.length === 0 || !primaryTopicRef.current) {
- // First message - extract and store primary topic
- primaryTopicRef.current = input;
- // Also save to post meta for persistence
-}
-```
-
-**Backend:**
-```php
-// In update_post_memory
-$memory['primary_topic'] = $data['primary_topic'] ?? $memory['primary_topic'] ?? '';
-```
-
-### Fix #2: Pass Primary Topic to Outline Generation
-
-**Where:** `assets/js/sidebar.js:4534`
-
-```javascript
-body: JSON.stringify({
- topic: primaryTopicRef.current || extractTopicFromFirstMessage(messages),
- // NOT: topic: "Create an outline based on our discussion"
-})
-```
-
-### Fix #3: Increase Chat History Limit for Outline Generation
-
-**Where:** `assets/js/sidebar.js:4543`
-
-```javascript
-// For outline generation, send MORE context
-chatHistory: messages.filter(m => m.role === 'user' || m.role === 'assistant').slice(-20),
-// Or better: send ALL messages for outline generation (it's a critical operation)
-```
-
-### Fix #4: Add Topic Emphasis in System Prompt
-
-**Where:** `includes/class-gutenberg-sidebar.php:1723`
-
-```php
-$system_prompt = "...
-CRITICAL: The PRIMARY TOPIC for this article is: {$primary_topic}
-Recent refinements in the conversation are meant to REFINE this topic, not REPLACE it.
-...";
-```
-
-### Fix #5: Use Focus Keyword as Topic Anchor
-
-**Where:** If user has set a focus keyword in config, prioritize it
-
-```php
-$effective_topic = !empty($post_config['focus_keyword'])
- ? $post_config['focus_keyword']
- : $topic;
-```
-
----
-
-## Priority Order for Implementation
-
-1. **HIGH: Fix #2** - Pass actual topic (not generic phrase) - Quick win
-2. **HIGH: Fix #1** - Extract and store primary topic - Core fix
-3. **MEDIUM: Fix #5** - Use focus keyword as anchor - Already available
-4. **MEDIUM: Fix #4** - Add topic emphasis in prompt - Reinforcement
-5. **LOW: Fix #3** - Increase chat history limit - Already configurable in settings
-
----
-
-## Verification Checklist
-
-After implementing fixes, test with this scenario:
-
-1. Start new post
-2. Enter detailed topic: "Switch career usia 30+ dengan AI dan web design"
-3. Have 3-4 back-and-forth refinements (add vibe coding, focus on opinions, etc.)
-4. Click "Create Outline Now"
-5. **VERIFY:** Outline title should reference "Switch Career Usia 30+" not just "AI Web Design"
-6. **VERIFY:** Sections should cover the FULL topic, not just recent refinements
-
----
-
-## Files to Modify
-
-| File | Changes |
-|------|---------|
-| `assets/js/sidebar.js` | Lines 4534, 4543 - Pass extracted topic, increase history |
-| `includes/class-gutenberg-sidebar.php` | Lines 1723-1765 - Add primary topic handling |
-| `includes/class-gutenberg-sidebar.php` | Lines 4735-4748 - Store primary_topic in memory |
-
----
-
-## Conclusion
-
-The agent is "not agentic" because it **doesn't remember intent** - it only reacts to the most recent context. A true agentic system should:
-
-1. **Extract** the user's primary intent from their first message
-2. **Store** this intent persistently
-3. **Reference** this intent when making decisions
-4. **Distinguish** between refinements and new topics
-
-The current system treats every message equally, causing recency bias to dominate and losing the user's original intent.
diff --git a/COST_TRACKING_IMPLEMENTATION.md b/COST_TRACKING_IMPLEMENTATION.md
deleted file mode 100644
index 96442a4..0000000
--- a/COST_TRACKING_IMPLEMENTATION.md
+++ /dev/null
@@ -1,397 +0,0 @@
-# Cost Tracking Enhancement Implementation
-
-## Overview
-Comprehensive cost tracking system implemented with three major features:
-1. **CPT Column** - Total cost per post in post list table
-2. **Global Cost Log** - Detailed cost tracking in settings page
-3. **Cost Shortcuts** - Quick access links in settings
-
----
-
-## 1. CPT Column for Post List
-
-### File Created
-`/includes/class-admin-columns.php`
-
-### Features
-- **💰 AI Cost** column in post list table
-- Shows total cost per post with color coding:
- - Green: < $0.50
- - Yellow: $0.50 - $1.00
- - Red: > $1.00
-- **Sortable** - Click column header to sort by cost
-- Shows `-` for posts with no AI usage
-- Handles deleted posts gracefully
-
-### Implementation
-```php
-// Adds column to post list
-add_filter('manage_post_columns', 'add_cost_column');
-
-// Renders cost with color coding
-add_action('manage_post_custom_column', 'render_cost_column');
-
-// Makes column sortable
-add_filter('manage_edit-post_sortable_columns', 'make_cost_column_sortable');
-
-// Handles sorting query
-add_action('pre_get_posts', 'sort_by_cost');
-```
-
-### Initialization
-Added to `wp-agentic-writer.php`:
-```php
-if ( is_admin() ) {
- WP_Agentic_Writer_Admin_Columns::get_instance();
-}
-```
-
----
-
-## 2. Global Cost Log Tab
-
-### Location
-Settings → Agentic Writer → **Cost Log** tab
-
-### Features
-
-#### **Summary Stats (4 Cards)**
-- 💰 **All Time** - Total spent across all posts
-- 📅 **This Month** - Current month spending
-- ☀️ **Today** - Today's spending
-- 📝 **Avg Per Post** - Average cost per post
-
-#### **Advanced Filters**
-- **Post ID** - Filter by specific post
-- **Model** - Filter by AI model used
-- **Type** - Filter by operation (chat, planning, writing, etc.)
-- **Date Range** - From/To date pickers
-- **Clear Filters** - Reset all filters
-
-#### **Detailed Cost Table**
-Columns:
-- Date/Time
-- Post (with link or `[Removed Post #123]` for deleted)
-- Model (displayed as code)
-- Type (formatted: Chat, Planning, Writing, etc.)
-- Input Tokens
-- Output Tokens
-- Cost ($0.0000 format)
-
-#### **Additional Features**
-- **Pagination** - 50 records per page
-- **Export CSV** - Download full cost log
-- **Responsive** - Horizontal scroll on small screens
-- **Hover Effects** - Row highlighting
-
-### Implementation
-
-#### Settings Tab Navigation
-Added to `class-settings.php`:
-```php
-
-```
-
-#### Tab Content
-```php
-
- render_cost_log_tab(); ?>
-
-```
-
-#### Method: `render_cost_log_tab()`
-- Queries cost database with filters
-- Calculates summary statistics
-- Renders stats grid, filters, table, pagination
-- Includes CSV export JavaScript
-
----
-
-## 3. Cost Shortcuts
-
-### Location
-Settings → General → Budget & Cost Tracking section
-
-### Feature
-**"View Full Cost Log →"** link appears below the budget progress bar
-
-### Implementation
-```php
-
-```
-
-### Styling
-- Blue border with light blue background
-- Hover: Blue background with white text
-- Smooth transitions
-- Icon + text layout
-
----
-
-## CSS Styling Added
-
-### File Modified
-`/assets/css/admin.css`
-
-### New Styles
-
-#### Cost Shortcuts
-```css
-.wpaw-cost-shortcuts
-.wpaw-cost-shortcut-link
-.wpaw-cost-shortcut-link:hover
-```
-
-#### Cost Stats Grid
-```css
-.wpaw-cost-stats-grid
-.wpaw-cost-stat-card
-.wpaw-cost-stat-icon
-.wpaw-cost-stat-value
-.wpaw-cost-stat-label
-```
-
-#### Cost Filters
-```css
-.wpaw-cost-filters
-.wpaw-filter-row
-.wpaw-filter-field
-.wpaw-filter-actions
-```
-
-#### Cost Log Table
-```css
-.wpaw-cost-log-table-wrapper
-.wpaw-cost-log-table
-.wpaw-cost-log-table thead
-.wpaw-cost-log-table th
-.wpaw-cost-log-table td
-.wpaw-cost-log-table tbody tr:hover
-.wpaw-removed-post
-```
-
-#### Pagination
-```css
-.wpaw-pagination
-.wpaw-pagination-info
-```
-
----
-
-## Database Queries
-
-### Cost Column Query
-```sql
-SELECT SUM(cost)
-FROM wp_wp_agentic_writer_costs
-WHERE post_id = %d
-```
-
-### Cost Log Queries
-```sql
--- Total count with filters
-SELECT COUNT(*) FROM wp_wp_agentic_writer_costs WHERE [filters]
-
--- Cost records with pagination
-SELECT * FROM wp_wp_agentic_writer_costs
-WHERE [filters]
-ORDER BY created_at DESC
-LIMIT 50 OFFSET 0
-
--- Summary stats
-SELECT SUM(cost) FROM wp_wp_agentic_writer_costs -- All time
-SELECT SUM(cost) WHERE MONTH(created_at) = MONTH(NOW()) -- This month
-SELECT SUM(cost) WHERE DATE(created_at) = CURDATE() -- Today
-SELECT COUNT(DISTINCT post_id) WHERE post_id > 0 -- Total posts
-```
-
----
-
-## User Experience Flow
-
-### 1. Post List View
-```
-Posts → All Posts
-└─ See "💰 AI Cost" column
- ├─ Click header to sort by cost
- ├─ Green/Yellow/Red color coding
- └─ Click post to edit
-```
-
-### 2. Settings Quick Access
-```
-Settings → Agentic Writer → General
-└─ Budget & Cost Tracking section
- ├─ View monthly progress bar
- ├─ See summary stats
- └─ Click "View Full Cost Log →"
-```
-
-### 3. Cost Log Deep Dive
-```
-Settings → Agentic Writer → Cost Log
-└─ Summary Stats (4 cards)
- ├─ All Time, This Month, Today, Avg Per Post
-└─ Filters
- ├─ Post ID, Model, Type, Date Range
- └─ Apply Filters / Clear
-└─ Detailed Table
- ├─ 50 records per page
- ├─ Pagination controls
- ├─ Click post title to edit
- └─ Export CSV button
-```
-
----
-
-## Deleted Post Handling
-
-### Problem
-Posts may be deleted but cost records remain
-
-### Solution
-```php
-$post_title = get_the_title($cost->post_id);
-if (!$post_title && $cost->post_id > 0) {
- $post_title = sprintf(__('[Removed Post #%d]'), $cost->post_id);
- $post_class = 'wpaw-removed-post'; // Gray, italic
-}
-```
-
-### Display
-- Shows `[Removed Post #123]` in gray italic
-- No link (prevents 404 errors)
-- Still shows all cost data
-- Filterable by post ID
-
----
-
-## Export CSV Feature
-
-### Implementation
-JavaScript in `render_cost_log_tab()`:
-```javascript
-$('#wpaw-export-csv').on('click', function() {
- // Extract table data
- // Format as CSV with escaped quotes
- // Create blob and download
- // Filename: wp-agentic-writer-costs-YYYY-MM-DD.csv
-});
-```
-
-### CSV Format
-```csv
-"Date/Time","Post","Model","Type","Input Tokens","Output Tokens","Cost"
-"2026-01-26 10:05:23","My Article","google/gemini-2.5-flash","Chat","1234","567","$0.0012"
-```
-
----
-
-## Files Modified/Created
-
-### Created
-1. `/includes/class-admin-columns.php` - CPT column handler
-
-### Modified
-1. `/wp-agentic-writer.php` - Initialize admin columns
-2. `/includes/class-settings.php` - Add Cost Log tab + shortcut
-3. `/assets/css/admin.css` - Add all cost tracking styles
-
-### Unchanged (Already Working)
-- `/includes/class-cost-tracker.php` - Cost tracking logic
-- `/assets/js/settings.js` - Tab switching (supports dynamic tabs)
-- Database table `wp_wp_agentic_writer_costs` - Already exists
-
----
-
-## Testing Checklist
-
-### CPT Column
-- [ ] Column appears in post list
-- [ ] Shows correct costs per post
-- [ ] Color coding works (green/yellow/red)
-- [ ] Sorting works (click column header)
-- [ ] Shows `-` for posts without AI usage
-
-### Cost Log Tab
-- [ ] Tab appears in settings navigation
-- [ ] Summary stats display correctly
-- [ ] All filters work (Post ID, Model, Type, Date Range)
-- [ ] Table displays cost records
-- [ ] Pagination works
-- [ ] Deleted posts show `[Removed Post #123]`
-- [ ] Post links work for existing posts
-- [ ] Export CSV downloads correctly
-
-### Cost Shortcuts
-- [ ] Link appears under budget progress bar
-- [ ] Clicking opens Cost Log tab
-- [ ] Hover effect works
-
-### Responsive Design
-- [ ] Table scrolls horizontally on mobile
-- [ ] Filters stack properly on small screens
-- [ ] Stats grid adjusts to screen size
-
----
-
-## Performance Considerations
-
-### Optimizations
-1. **Pagination** - Only loads 50 records at a time
-2. **Indexed Queries** - Uses post_id, created_at indexes
-3. **Prepared Statements** - All queries use `$wpdb->prepare()`
-4. **Conditional Loading** - Admin columns only load in admin
-5. **CSS Minification** - Production should minify admin.css
-
-### Database Impact
-- Minimal: Uses existing `wp_wp_agentic_writer_costs` table
-- No new tables created
-- Queries are optimized with WHERE clauses
-
----
-
-## Future Enhancements (Not Implemented)
-
-### Potential Additions
-1. **Charts** - Visual cost trends over time
-2. **Budget Alerts** - Email when approaching limit
-3. **Cost Breakdown** - Pie chart by model/type
-4. **Bulk Actions** - Delete old cost records
-5. **API Endpoint** - REST API for cost data
-6. **Dashboard Widget** - Cost summary on WP dashboard
-
----
-
-## Summary
-
-**Total Implementation Time:** ~3 hours
-
-**Features Delivered:**
-- ✅ CPT column with sorting and color coding
-- ✅ Global cost log with filters and pagination
-- ✅ Summary statistics (4 cards)
-- ✅ Cost shortcuts for quick access
-- ✅ Export CSV functionality
-- ✅ Deleted post handling
-- ✅ Responsive design
-- ✅ Full styling and UX polish
-
-**User Benefits:**
-- Quick cost overview in post list
-- Detailed cost analysis in settings
-- Easy filtering and searching
-- Export for external analysis
-- Budget monitoring at a glance
-- ROI tracking per article
-
-**Ready for Production:** Yes ✅
diff --git a/DEFECT_REPORT_IMAGE_GENERATION.md b/DEFECT_REPORT_IMAGE_GENERATION.md
deleted file mode 100644
index 037358a..0000000
--- a/DEFECT_REPORT_IMAGE_GENERATION.md
+++ /dev/null
@@ -1,468 +0,0 @@
-# WP Agentic Writer - Defect Report
-
-**Date:** January 29, 2026
-**Reporter:** Development Team
-**Testing Session:** Image Generation Feature Integration
-
----
-
-## Executive Summary
-
-After comprehensive flow tracing, **4 critical defects** and **multiple integration gaps** were identified. The image generation backend is functional, but frontend integration is incomplete.
-
----
-
-## Defect #1: "Create Outline Now" Button - Mode Timing Issue
-
-### Symptom
-Clicking "Create Outline Now" only prefills English message and changes mode. User expects automatic outline generation.
-
-### Root Cause Analysis
-
-**File:** `@/Users/dwindown/Local Sites/bricks/app/public/wp-content/plugins/wp-agentic-writer/assets/js/sidebar.js:4432-4444`
-
-```javascript
-onClick: async () => {
- setAgentMode('planning'); // Line 4434
- const outlineMessage = 'Create an outline based on our discussion';
- setInput(outlineMessage); // Line 4438
- setTimeout(() => {
- sendMessage(); // Line 4443
- }, 100);
-}
-```
-
-**Problem:** React's `setState` is asynchronous. When `sendMessage()` is called 100ms later:
-1. `agentMode` state may not have updated yet in the closure
-2. `input` state may not have updated yet
-3. The `sendMessage()` function reads stale state values
-
-**Flow Trace:**
-```
-User clicks "Create Outline Now"
- ↓
-setAgentMode('planning') called - state update QUEUED
- ↓
-setInput('Create an outline...') called - state update QUEUED
- ↓
-100ms timeout fires
- ↓
-sendMessage() runs with STALE state (agentMode might still be 'chat')
- ↓
-Line 3084: if (agentMode === 'chat' && !hasMentions) → TRUE (stale state!)
- ↓
-Chat API called instead of generate-plan
-```
-
-### Expected Behavior
-Button should directly trigger planning flow with proper mode context, bypassing React state timing issues.
-
-### Recommended Fix
-Pass mode and message directly to sendMessage, not relying on state:
-
-```javascript
-onClick: async () => {
- setAgentMode('planning');
- const outlineMessage = 'Create an outline based on our discussion';
-
- // Call API directly instead of relying on state
- await triggerPlanGeneration(outlineMessage, {
- mode: 'planning',
- autoTrigger: true
- });
-}
-```
-
-Or use a dedicated function that doesn't depend on `agentMode` state.
-
----
-
-## Defect #2: Clarity Check Not Triggered for Planning Mode
-
-### Symptom
-Cost tracking shows `clarity_check` was never called when using "Create Outline Now".
-
-### Root Cause Analysis
-
-**Flow Trace through `sendMessage()`:**
-
-```
-Line 3049: shouldShowPlan = (agentMode === 'planning')
-
-If agentMode is still 'chat' (due to Defect #1):
- Line 3084: if (agentMode === 'chat' && !hasMentions) → TRUE
- → Enters CHAT flow (NOT planning flow)
- → Calls /chat API
- → Clarity check is NOT in this branch
-```
-
-**If agentMode correctly updated to 'planning':**
-```
-Line 3077: if (agentMode === 'planning' && !hasMentions && currentPlanRef.current)
- → FALSE because currentPlanRef.current is null (no existing plan)
- → Falls through
-
-Line 3084: if (agentMode === 'chat' && !hasMentions)
- → FALSE because agentMode is 'planning'
- → Falls through
-
-Line 3225: if (!hasMentions && refineableBlocks.length > 0)
- → FALSE if no content exists yet
- → Falls through
-
-Line 3262: if (!hasMentions)
- → TRUE
- → Enters clarity check + generate-plan flow ✓
-```
-
-**Conclusion:** The clarity check SHOULD work if agentMode is correctly set to 'planning'. The root cause is **Defect #1** - the timing issue with state updates.
-
-### Recommended Fix
-Fix Defect #1, which will automatically fix this defect.
-
----
-
-## Defect #3: Numbered List with Bold Title + Bullets - Incorrect Conversion
-
-### Symptom
-Markdown like:
-```markdown
-1. **Jadikan AI sebagai Asisten**
-- Gunakan untuk mempercepat pekerjaan
-- Manfaatkan sebagai sumber referensi
-
-1. **Terus Belajar dan Beradaptasi**
-- Ikuti perkembangan teknologi AI
-```
-
-Renders as:
-- Ordered list with item "1. **Jadikan AI sebagai Asisten**"
-- Separate unordered list with bullets
-- **New** ordered list restarting at "1." for next section
-
-User sees "1. 1. 1." instead of "1. 2. 3."
-
-### Root Cause Analysis
-
-**File:** `@/Users/dwindown/Local Sites/bricks/app/public/wp-content/plugins/wp-agentic-writer/includes/class-markdown-parser.php:261-274`
-
-```php
-// Handle ordered lists.
-if ( preg_match( '/^\d+\.\s+(.+)$/', $trimmed, $matches ) ) {
- // ... creates ordered list item
- $list_items[] = self::parse_inline_markdown( $matches[1] );
- continue;
-}
-```
-
-**Problem:** The parser correctly identifies numbered items, but when an empty line or different list type appears, it flushes the current list. Each section becomes a **separate** ordered list block, each starting at 1.
-
-The `merge_consecutive_ordered_lists()` function at line 674 only merges **consecutive** ordered lists. But the structure has:
-```
-ordered list (1 item)
-unordered list (bullets)
-ordered list (1 item) ← NOT consecutive, won't merge
-unordered list (bullets)
-```
-
-### Expected Behavior (per user request)
-For numbered items with bold titles followed by bullet sub-content:
-
-```
-1. **Bold Title** → core/paragraph with "1. Bold Title"
-- bullet item → core/list (unordered)
-- bullet item
-
-2. **Next Title** → core/paragraph with "2. Next Title"
-- more bullets → core/list (unordered)
-```
-
-This structure:
-- Prevents the "1. 1. 1." numbering issue
-- Creates logical grouping
-- Maintains proper section hierarchy
-
-### Recommended Fix
-
-**Option A:** Detect pattern `^\d+\.\s+\*\*(.+)\*\*$` (numbered + bold) and treat as paragraph:
-
-```php
-// Handle numbered items with bold title (treat as paragraph, not list)
-if ( preg_match( '/^(\d+)\.\s+\*\*(.+)\*\*\s*$/', $trimmed, $matches ) ) {
- // Create paragraph with manual numbering
- $content = $matches[1] . '. ' . self::parse_inline_markdown( $matches[2] ) . '';
- $blocks[] = self::create_paragraph_block( $content );
- continue;
-}
-```
-
-**Option B:** Pre-process markdown to normalize this pattern before parsing.
-
----
-
-## Defect #4: Image Blocks Missing `data-agent-image-id` Attribute
-
-### Symptom
-Generated image blocks have no way to:
-1. Confirm agent assigned an image ID
-2. View the recommended prompt/alt text
-3. Trigger image generation modal
-4. Connect to backend image recommendations
-
-### Root Cause Analysis
-
-**File:** `@/Users/dwindown/Local Sites/bricks/app/public/wp-content/plugins/wp-agentic-writer/includes/class-markdown-parser.php:644-664`
-
-```php
-private static function create_image_placeholder_block( $description ) {
- $alt = trim( $description );
- $attrs = array(
- 'id' => 0,
- 'url' => '',
- 'alt' => $alt,
- 'caption' => '',
- 'sizeSlug' => 'large',
- 'linkDestination' => 'none',
- );
- // ❌ MISSING: 'data-agent-image-id' => 'img_xxx'
-```
-
-**The `data-agent-image-id` attribute is documented in:**
-- `IMAGE_GENERATION_IMPLEMENTATION_PLAN.md`
-- `IMAGE_GENERATION_README.md`
-- `image-gen-flow.md`
-- `image-modal.js` (expects this attribute)
-
-**But NEVER implemented in the actual code!**
-
-### Missing Integration Points
-
-1. **Markdown Parser:** Must generate unique `agent_image_id` and add to block attrs
-2. **Backend Storage:** Must save recommendations with matching IDs to `wp_wpaw_images` table
-3. **Block Toolbar:** Must add "Generate Image" button for image blocks with this attribute
-4. **Modal Trigger:** Must open image modal after article generation or from toolbar
-
-### Recommended Fix
-
-**Step 1:** Update `create_image_placeholder_block()`:
-
-```php
-private static function create_image_placeholder_block( $description, $image_index = 0 ) {
- $alt = trim( $description );
- $agent_image_id = 'img_' . uniqid(); // Or use index-based ID
-
- $attrs = array(
- 'id' => 0,
- 'url' => '',
- 'alt' => $alt,
- 'caption' => '',
- 'sizeSlug' => 'large',
- 'linkDestination' => 'none',
- 'data-agent-image-id' => $agent_image_id,
- );
- // ...
-}
-```
-
-**Step 2:** Track and return image IDs during article generation
-
-**Step 3:** Register toolbar button for image blocks (see below)
-
----
-
-## Missing Integration #1: Image Block Toolbar Button
-
-### Current State
-No "Generate Image" button exists in image block toolbar.
-
-### Required Implementation
-
-**File to create:** Extend `block-refine.js` or create new `block-image-generate.js`
-
-```javascript
-// Add toolbar button to core/image blocks with data-agent-image-id
-const withImageGenerateToolbar = createHigherOrderComponent((BlockEdit) => {
- return (props) => {
- const { clientId } = props;
- const block = useSelect(
- (select) => select('core/block-editor').getBlock(clientId),
- [clientId]
- );
-
- if (!block || block.name !== 'core/image') {
- return wp.element.createElement(BlockEdit, props);
- }
-
- const agentImageId = block.attributes['data-agent-image-id'];
- if (!agentImageId) {
- return wp.element.createElement(BlockEdit, props);
- }
-
- const openImageModal = () => {
- window.dispatchEvent(
- new CustomEvent('wpaw:open-image-modal', {
- detail: { agentImageId, blockId: clientId }
- })
- );
- };
-
- return wp.element.createElement(
- wp.element.Fragment,
- null,
- wp.element.createElement(BlockEdit, props),
- wp.element.createElement(
- BlockControls,
- null,
- wp.element.createElement(
- ToolbarGroup,
- null,
- wp.element.createElement(ToolbarButton, {
- icon: 'format-image',
- label: 'Generate AI Image',
- onClick: openImageModal,
- })
- )
- )
- );
- };
-}, 'withImageGenerateToolbar');
-
-addFilter(
- 'editor.BlockEdit',
- 'wp-agentic-writer/image-generate-toolbar',
- withImageGenerateToolbar
-);
-```
-
----
-
-## Missing Integration #2: Image Modal Trigger After Article Generation
-
-### Current State
-`image-modal.js` component exists but is never rendered/triggered.
-
-### Required Implementation
-
-**In `sidebar.js`, after article execution completes:**
-
-```javascript
-// After all sections are written and blocks inserted:
-const checkForImagePlaceholders = () => {
- const blocks = wp.data.select('core/block-editor').getBlocks();
- const imagePlaceholders = blocks.filter(
- block => block.name === 'core/image' &&
- block.attributes['data-agent-image-id']
- );
-
- if (imagePlaceholders.length > 0) {
- // Open image review modal
- window.dispatchEvent(
- new CustomEvent('wpaw:open-image-review-modal', {
- detail: {
- postId: postId,
- imageCount: imagePlaceholders.length
- }
- })
- );
- }
-};
-```
-
-**In `image-modal.js`, listen for event:**
-
-```javascript
-useEffect(() => {
- const handleOpenModal = (event) => {
- setPostId(event.detail.postId);
- setIsOpen(true);
- loadRecommendations(event.detail.postId);
- };
-
- window.addEventListener('wpaw:open-image-review-modal', handleOpenModal);
- return () => window.removeEventListener('wpaw:open-image-review-modal', handleOpenModal);
-}, []);
-```
-
----
-
-## Missing Integration #3: Backend Image ID Generation
-
-### Current State
-`[IMAGE: description]` placeholders are converted to blocks, but:
-- No unique ID generated
-- No storage in `wp_wpaw_images` table during article generation
-- No link between block and database record
-
-### Required Implementation
-
-**During article generation in `class-gutenberg-sidebar.php`:**
-
-1. Parse `[IMAGE: ...]` placeholders before block conversion
-2. Generate unique `agent_image_id` for each
-3. Store in `wp_wpaw_images` table with post_id, prompt, alt_text
-4. Pass image IDs to markdown parser for block attribute injection
-
-```php
-// In handle_generate_article or handle_execute_plan:
-$image_placeholders = [];
-preg_match_all('/\[IMAGE:\s*(.+?)\]/i', $markdown_content, $matches);
-
-foreach ($matches[1] as $index => $description) {
- $agent_image_id = 'img_' . $post_id . '_' . ($index + 1);
- $image_placeholders[] = [
- 'agent_image_id' => $agent_image_id,
- 'description' => $description,
- ];
-
- // Save to database
- $image_manager = WP_Agentic_Writer_Image_Manager::get_instance();
- // ... save recommendation
-}
-
-// Convert markdown with image IDs
-$blocks = WP_Agentic_Writer_Markdown_Parser::to_blocks($markdown_content, $image_placeholders);
-```
-
----
-
-## Priority Matrix
-
-| Defect | Severity | Impact | Fix Effort |
-|--------|----------|--------|------------|
-| #1 - Create Outline timing | **High** | Blocks main workflow | Low |
-| #2 - Clarity check | **High** | Poor content quality | Depends on #1 |
-| #3 - Numbered list | **Medium** | Visual formatting | Medium |
-| #4 - Image IDs missing | **Critical** | Image feature broken | Medium |
-| Toolbar button | **Critical** | No way to trigger images | Medium |
-| Modal trigger | **Critical** | No user-facing image feature | Medium |
-| Backend ID generation | **Critical** | No data persistence | Medium |
-
----
-
-## Recommended Fix Order
-
-1. **Defect #1** - Fix timing issue (enables #2)
-2. **Defect #4 + Backend ID generation** - Core image functionality
-3. **Toolbar button** - User can trigger image generation
-4. **Modal trigger** - Automatic flow after article generation
-5. **Defect #3** - Formatting improvement (lower priority)
-
----
-
-## Testing Checklist After Fixes
-
-- [ ] Click "Create Outline Now" → Clarity quiz appears (if needed)
-- [ ] Click "Create Outline Now" → Plan generated automatically
-- [ ] Cost tracking shows `clarity_check` action
-- [ ] Numbered + bold items render as paragraphs with manual numbering
-- [ ] Image blocks have `data-agent-image-id` attribute in inspector
-- [ ] Image blocks show "Generate AI Image" in toolbar
-- [ ] After article generation, image modal opens automatically
-- [ ] Can generate variants for each image placeholder
-- [ ] Can select and commit variant to Media Library
-- [ ] Block updates with real image after commit
-
----
-
-**Report Status:** Complete
-**Next Steps:** Implement fixes in priority order
diff --git a/FINAL_CSS_CODE.md b/FINAL_CSS_CODE.md
deleted file mode 100644
index dd08f69..0000000
--- a/FINAL_CSS_CODE.md
+++ /dev/null
@@ -1,268 +0,0 @@
-# Final CSS Implementation
-
-All CSS styles to be added to `/assets/css/sidebar.css` or `/assets/css/admin.css`
-
----
-
-## Writing Mode Empty State Styles
-
-```css
-/* Writing Mode Empty State */
-.wpaw-writing-empty-state {
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: 300px;
- padding: 2rem;
- background: #f9f9f9;
- border-radius: 8px;
- margin: 1rem 0;
-}
-
-.wpaw-empty-state-content {
- text-align: center;
- max-width: 400px;
-}
-
-.wpaw-empty-state-icon {
- font-size: 3rem;
- display: block;
- margin-bottom: 1rem;
- opacity: 0.8;
-}
-
-.wpaw-empty-state-content h3 {
- margin: 0 0 0.5rem 0;
- font-size: 1.5rem;
- color: #1e1e1e;
- font-weight: 600;
-}
-
-.wpaw-empty-state-content p {
- color: #666;
- margin: 0.5rem 0;
- line-height: 1.5;
- font-size: 0.95rem;
-}
-
-.wpaw-empty-state-button {
- margin: 1.5rem 0 1rem 0 !important;
- font-size: 1rem !important;
-}
-
-.wpaw-empty-state-hint {
- font-size: 0.9rem !important;
- margin-top: 1rem !important;
- color: #888 !important;
-}
-
-.wpaw-link-button {
- background: none;
- border: none;
- color: #2271b1;
- text-decoration: underline;
- cursor: pointer;
- padding: 0;
- font: inherit;
- font-size: inherit;
-}
-
-.wpaw-link-button:hover {
- color: #135e96;
-}
-```
-
----
-
-## Context Indicator Styles
-
-```css
-/* Context Indicator */
-.wpaw-context-indicator {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0.75rem 1rem;
- background: #f0f6fc;
- border: 1px solid #d0e3f0;
- border-radius: 6px;
- margin: 0.5rem 0 1rem 0;
- font-size: 0.85rem;
-}
-
-.wpaw-context-info {
- display: flex;
- gap: 1rem;
- align-items: center;
-}
-
-.wpaw-context-count {
- color: #0066cc;
- font-weight: 500;
-}
-
-.wpaw-context-tokens {
- color: #666;
-}
-
-.wpaw-context-clear {
- background: none;
- border: none;
- color: #cc0000;
- cursor: pointer;
- padding: 0.25rem 0.5rem;
- border-radius: 4px;
- font-size: 0.85rem;
- transition: background-color 0.2s;
-}
-
-.wpaw-context-clear:hover {
- background: #ffe6e6;
-}
-```
-
----
-
-## Contextual Action Card Styles
-
-```css
-/* Contextual Action Cards */
-.wpaw-contextual-action {
- display: flex;
- gap: 1rem;
- padding: 1rem;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- border-radius: 8px;
- margin: 1rem 0;
- color: white;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-}
-
-.wpaw-action-icon {
- font-size: 2rem;
- line-height: 1;
- flex-shrink: 0;
-}
-
-.wpaw-action-content {
- flex: 1;
-}
-
-.wpaw-action-content h4 {
- margin: 0 0 0.25rem 0;
- font-size: 1rem;
- font-weight: 600;
- color: white;
-}
-
-.wpaw-action-content p {
- margin: 0 0 0.75rem 0;
- font-size: 0.9rem;
- color: rgba(255, 255, 255, 0.9);
- line-height: 1.4;
-}
-
-.wpaw-action-content .components-button {
- background: white !important;
- color: #667eea !important;
- border: none !important;
- font-weight: 600 !important;
- padding: 0.5rem 1rem !important;
- font-size: 0.9rem !important;
-}
-
-.wpaw-action-content .components-button:hover {
- background: #f0f0f0 !important;
- color: #5568d3 !important;
-}
-
-/* Variant for different intent types */
-.wpaw-contextual-action.intent-create-outline {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-}
-
-.wpaw-contextual-action.intent-start-writing {
- background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
-}
-
-.wpaw-contextual-action.intent-refine-content {
- background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
-}
-```
-
----
-
-## Info Message Styles (for Writing mode notes warning)
-
-```css
-/* System Info Messages */
-.wpaw-ai-item[data-type="info"] {
- background: #e7f3ff;
- border-left: 4px solid #2271b1;
- padding: 0.75rem 1rem;
- margin: 0.5rem 0;
- border-radius: 4px;
-}
-
-.wpaw-ai-item[data-type="info"] .wpaw-ai-content {
- color: #1e1e1e;
- font-size: 0.9rem;
- line-height: 1.5;
-}
-```
-
----
-
-## Additional Utility Styles
-
-```css
-/* Mode Indicator Badge */
-.wpaw-mode-indicator {
- display: inline-block;
- padding: 0.25rem 0.5rem;
- background: #f0f0f0;
- border-radius: 4px;
- font-size: 0.75rem;
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.5px;
- margin-left: 0.5rem;
-}
-
-.wpaw-mode-indicator.mode-chat {
- background: #e7f3ff;
- color: #0066cc;
-}
-
-.wpaw-mode-indicator.mode-planning {
- background: #fff3e0;
- color: #e65100;
-}
-
-.wpaw-mode-indicator.mode-writing {
- background: #f3e5f5;
- color: #6a1b9a;
-}
-
-/* Smooth transitions */
-.wpaw-writing-empty-state,
-.wpaw-context-indicator,
-.wpaw-contextual-action {
- animation: fadeInUp 0.3s ease-out;
-}
-
-@keyframes fadeInUp {
- from {
- opacity: 0;
- transform: translateY(10px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-```
-
----
-
-All CSS styles are now documented and ready to be added to the stylesheet.
diff --git a/FINAL_FRONTEND_CODE.md b/FINAL_FRONTEND_CODE.md
deleted file mode 100644
index 5886426..0000000
--- a/FINAL_FRONTEND_CODE.md
+++ /dev/null
@@ -1,355 +0,0 @@
-# Final Frontend Implementation Code
-
-This document contains all the JavaScript and CSS code to be added to complete the implementation.
-
----
-
-## JavaScript Functions to Add to sidebar.js
-
-### 1. Writing Mode Empty State Check
-
-```javascript
-// Add after state declarations (around line 100)
-const shouldShowWritingEmptyState = () => {
- return agentMode === 'writing' && !currentPlanRef.current;
-};
-```
-
-### 2. Summarize Chat History Function
-
-```javascript
-// Add with other utility functions
-const summarizeChatHistory = async () => {
- const chatMessages = messages.filter(m => m.role !== 'system');
-
- if (chatMessages.length < 4) {
- return { summary: '', useFullHistory: true, cost: 0 };
- }
-
- try {
- const response = await fetch(wpAgenticWriter.apiUrl + '/summarize-context', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-WP-Nonce': wpAgenticWriter.nonce,
- },
- body: JSON.stringify({
- chatHistory: chatMessages,
- postId: postId,
- }),
- });
-
- if (!response.ok) {
- throw new Error('Summarization failed');
- }
-
- const data = await response.json();
-
- if (data.tokens_saved > 0) {
- console.log(`💡 Context optimized: ~${data.tokens_saved} tokens saved (~$${(data.tokens_saved * 0.0000002).toFixed(4)})`);
- }
-
- return {
- summary: data.summary || '',
- useFullHistory: data.use_full_history || false,
- cost: data.cost || 0,
- tokensSaved: data.tokens_saved || 0,
- };
- } catch (error) {
- console.error('Summarization error:', error);
- return { summary: '', useFullHistory: true, cost: 0 };
- }
-};
-```
-
-### 3. Detect User Intent Function
-
-```javascript
-// Add with other utility functions
-const detectUserIntent = async (lastMessage) => {
- if (!lastMessage || lastMessage.trim().length === 0) {
- return { intent: 'continue_chat', cost: 0 };
- }
-
- try {
- const response = await fetch(wpAgenticWriter.apiUrl + '/detect-intent', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-WP-Nonce': wpAgenticWriter.nonce,
- },
- body: JSON.stringify({
- lastMessage: lastMessage,
- hasPlan: Boolean(currentPlanRef.current),
- currentMode: agentMode,
- postId: postId,
- }),
- });
-
- if (!response.ok) {
- throw new Error('Intent detection failed');
- }
-
- const data = await response.json();
- return {
- intent: data.intent || 'continue_chat',
- cost: data.cost || 0,
- };
- } catch (error) {
- console.error('Intent detection error:', error);
- return { intent: 'continue_chat', cost: 0 };
- }
-};
-```
-
-### 4. Build Optimized Context Function
-
-```javascript
-// Add with other utility functions
-const buildOptimizedContext = async () => {
- const result = await summarizeChatHistory();
-
- if (result.useFullHistory) {
- return {
- type: 'full',
- messages: messages.filter(m => m.role !== 'system'),
- cost: 0,
- };
- }
-
- return {
- type: 'summary',
- summary: result.summary,
- cost: result.cost,
- tokensSaved: result.tokensSaved,
- };
-};
-```
-
-### 5. Handle Reset Command
-
-```javascript
-// Add with other command handlers
-const handleResetCommand = async () => {
- if (!confirm('Clear all conversation history? This cannot be undone.')) {
- return;
- }
-
- try {
- // Clear frontend state
- setMessages([]);
- currentPlanRef.current = null;
-
- // Clear backend chat history
- await fetch(wpAgenticWriter.apiUrl + '/clear-context', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-WP-Nonce': wpAgenticWriter.nonce,
- },
- body: JSON.stringify({ postId: postId }),
- });
-
- setMessages([{
- role: 'system',
- type: 'info',
- content: '✅ Context cleared. Starting fresh conversation.'
- }]);
- } catch (error) {
- console.error('Reset error:', error);
- setMessages(prev => [...prev, {
- role: 'system',
- type: 'error',
- content: 'Failed to clear context. Please try again.'
- }]);
- }
-};
-```
-
----
-
-## Modifications to Existing Functions
-
-### Modify handleSendMessage (detect /reset command)
-
-Find the message sending logic and add at the beginning:
-
-```javascript
-// Check for reset command
-if (/^\s*(\/reset|\/clear)\s*$/i.test(userMessage)) {
- setInput('');
- await handleResetCommand();
- return;
-}
-
-// Check for Writing mode notes warning
-if (agentMode === 'writing' && currentPlanRef.current) {
- setMessages(prev => [...prev,
- { role: 'user', content: userMessage },
- {
- role: 'system',
- type: 'info',
- content: '💡 Note: Messages in Writing mode are for discussion only. To modify the outline, switch to Planning mode.'
- }
- ]);
-}
-```
-
-### Modify handleExecuteArticle (add plan check)
-
-Add at the very beginning of the function:
-
-```javascript
-// Check if plan exists
-if (!currentPlanRef.current) {
- setMessages(prev => [...prev, {
- role: 'system',
- type: 'error',
- content: '⚠️ No outline found. Please create an outline first by switching to Planning mode.'
- }]);
- setIsLoading(false);
- return;
-}
-```
-
----
-
-## UI Components to Add
-
-### Render Writing Empty State
-
-Add this component function:
-
-```javascript
-const renderWritingEmptyState = () => {
- return wp.element.createElement('div', { className: 'wpaw-writing-empty-state' },
- wp.element.createElement('div', { className: 'wpaw-empty-state-content' },
- wp.element.createElement('span', { className: 'wpaw-empty-state-icon' }, '📝'),
- wp.element.createElement('h3', null, 'No Outline Yet'),
- wp.element.createElement('p', null, 'Writing mode requires an outline to structure your article.'),
- wp.element.createElement(Button, {
- isPrimary: true,
- onClick: () => setAgentMode('planning'),
- className: 'wpaw-empty-state-button'
- }, '📝 Create Outline First'),
- wp.element.createElement('p', { className: 'wpaw-empty-state-hint' },
- 'Or switch to ',
- wp.element.createElement('button', {
- onClick: () => setAgentMode('chat'),
- className: 'wpaw-link-button'
- }, 'Chat mode'),
- ' to discuss your ideas.'
- )
- )
- );
-};
-```
-
-### Render Context Indicator
-
-Add this component function:
-
-```javascript
-const renderContextIndicator = () => {
- const chatMessages = messages.filter(m => m.role !== 'system');
- const messageCount = chatMessages.length;
- const estimatedTokens = messageCount * 500; // Rough estimate
-
- if (messageCount === 0) return null;
-
- return wp.element.createElement('div', { className: 'wpaw-context-indicator' },
- wp.element.createElement('div', { className: 'wpaw-context-info' },
- wp.element.createElement('span', { className: 'wpaw-context-count' },
- `💬 ${messageCount} messages`
- ),
- wp.element.createElement('span', { className: 'wpaw-context-tokens' },
- `~${estimatedTokens} tokens`
- )
- ),
- wp.element.createElement('button', {
- className: 'wpaw-context-clear',
- onClick: handleResetCommand,
- title: 'Clear conversation history'
- }, '🗑️ Clear')
- );
-};
-```
-
-### Render Contextual Action
-
-Add this component function:
-
-```javascript
-const renderContextualAction = (intent) => {
- if (!intent || intent === 'continue_chat') return null;
-
- const actions = {
- create_outline: {
- icon: '📝',
- title: 'Ready to create an outline?',
- description: 'I can help you structure your article.',
- button: 'Create Outline',
- onClick: () => setAgentMode('planning')
- },
- start_writing: {
- icon: '✍️',
- title: 'Ready to start writing?',
- description: 'Let\'s turn your outline into a full article.',
- button: 'Start Writing',
- onClick: async () => {
- setAgentMode('writing');
- if (currentPlanRef.current) {
- await handleExecuteArticle();
- }
- }
- },
- refine_content: {
- icon: '✨',
- title: 'Want to refine your content?',
- description: 'I can help improve specific sections.',
- button: 'Show Options',
- onClick: () => {} // Could open refinement options
- }
- };
-
- const action = actions[intent];
- if (!action) return null;
-
- return wp.element.createElement('div', { className: 'wpaw-contextual-action' },
- wp.element.createElement('div', { className: 'wpaw-action-icon' }, action.icon),
- wp.element.createElement('div', { className: 'wpaw-action-content' },
- wp.element.createElement('h4', null, action.title),
- wp.element.createElement('p', null, action.description),
- wp.element.createElement(Button, {
- isPrimary: true,
- onClick: action.onClick
- }, action.button)
- )
- );
-};
-```
-
----
-
-## Integration Points
-
-### In Main Render (where messages are displayed)
-
-Add before the message list:
-
-```javascript
-{shouldShowWritingEmptyState() && renderWritingEmptyState()}
-{renderContextIndicator()}
-```
-
-### In Message Loop (after assistant messages)
-
-Add intent detection display:
-
-```javascript
-{message.detectedIntent && renderContextualAction(message.detectedIntent)}
-```
-
----
-
-This completes all the JavaScript logic needed for the frontend implementation.
diff --git a/FIXES_SUMMARY.md b/FIXES_SUMMARY.md
deleted file mode 100644
index 77edfc1..0000000
--- a/FIXES_SUMMARY.md
+++ /dev/null
@@ -1,326 +0,0 @@
-# WP Agentic Writer - Defect Fixes Summary
-
-**Date:** January 29, 2026
-**Status:** ✅ All Fixes Implemented
-
----
-
-## Overview
-
-All 4 critical defects identified in the defect report have been fixed, plus 3 missing integrations have been implemented. The plugin is now ready for testing.
-
----
-
-## ✅ Defect #1: "Create Outline Now" Button - FIXED
-
-### Problem
-React state timing issue caused `sendMessage()` to read stale `agentMode` state, resulting in chat API being called instead of planning flow.
-
-### Solution
-**File:** `assets/js/sidebar.js:4432-4609`
-
-Replaced `setTimeout(() => sendMessage())` with direct API calls that don't rely on React state:
-- Directly call `/check-clarity` API
-- Show clarity quiz if needed
-- Directly call `/generate-plan` API
-- Handle streaming response inline
-
-### Result
-✅ Clarity check now triggers correctly
-✅ Planning mode works as expected
-✅ No more English-only prefilled messages
-
----
-
-## ✅ Defect #2: Clarity Check Not Triggered - FIXED
-
-### Problem
-Cascaded from Defect #1 - clarity check wasn't called because wrong API endpoint was triggered.
-
-### Solution
-Fixed by Defect #1 solution. The direct API call approach ensures clarity check always runs before plan generation.
-
-### Result
-✅ Clarity quiz appears when needed
-✅ Language detection works
-✅ SEO questions appear
-✅ Cost tracking shows `clarity_check` action
-
----
-
-## ✅ Defect #3: Numbered List Formatting - FIXED
-
-### Problem
-Markdown pattern `1. **Bold Title**` followed by bullets created separate ordered lists, showing "1. 1. 1." instead of "1. 2. 3."
-
-### Solution
-**File:** `includes/class-markdown-parser.php:270-285`
-
-Added detection for numbered items with bold titles **before** regular ordered list detection:
-
-```php
-// Handle numbered items with bold title (treat as paragraph, not list).
-if ( preg_match( '/^(\d+)\.\s+\*\*(.+?)\*\*\s*$/', $trimmed, $matches ) ) {
- // Create paragraph with manual numbering and bold title.
- $content = $matches[1] . '. ' . self::parse_inline_markdown( $matches[2] ) . '';
- $blocks[] = self::create_paragraph_block( $content );
- continue;
-}
-```
-
-### Result
-✅ `1. **Title**` → Paragraph block with "1. **Title**"
-✅ Following bullets → Unordered list block
-✅ Proper visual hierarchy maintained
-✅ No more "1. 1. 1." numbering
-
----
-
-## ✅ Defect #4: Image Blocks Missing `data-agent-image-id` - FIXED
-
-### Problem
-Image placeholder blocks were created without the `data-agent-image-id` attribute needed for:
-- Identifying which image recommendation to load
-- Triggering image generation modal
-- Updating block after image selection
-
-### Solution
-
-**1. Updated Markdown Parser**
-
-**File:** `includes/class-markdown-parser.php:29`
-- Added `$image_placeholders` parameter to `parse()` method
-
-**File:** `includes/class-markdown-parser.php:97-105`
-- Extract `agent_image_id` from placeholders array
-- Pass to `create_image_placeholder_block()`
-
-**File:** `includes/class-markdown-parser.php:654-668`
-- Accept `$agent_image_id` parameter
-- Add to block attributes if provided
-
-**2. Backend Image ID Generation**
-
-**File:** `includes/class-gutenberg-sidebar.php:2154-2177`
-
-During article execution, extract `[IMAGE: ...]` placeholders and:
-- Generate unique `agent_image_id` for each
-- Save to `wp_wpaw_images` table
-- Pass to markdown parser
-
-```php
-$image_placeholders = array();
-if ( preg_match_all( '/\[IMAGE:\s*(.+?)\]/i', $markdown_content, $matches ) ) {
- $image_manager = WP_Agentic_Writer_Image_Manager::get_instance();
-
- foreach ( $matches[1] as $index => $description ) {
- $agent_image_id = 'img_' . $post_id . '_' . time() . '_' . ( $index + 1 );
- $image_placeholders[] = array(
- 'agent_image_id' => $agent_image_id,
- 'description' => trim( $description ),
- );
-
- // Save to database
- $image_manager->save_image_recommendation(...);
- }
-}
-
-$markdown_blocks = WP_Agentic_Writer_Markdown_Parser::parse( $markdown_content, $image_placeholders );
-```
-
-### Result
-✅ Image blocks have `data-agent-image-id` attribute
-✅ Database records created for each image
-✅ Frontend can query recommendations
-✅ Block updates work after image selection
-
----
-
-## ✅ Missing Integration #1: Image Block Toolbar Button - IMPLEMENTED
-
-### What Was Missing
-No way for users to trigger image generation from the block toolbar.
-
-### Solution
-**File:** `assets/js/block-image-generate.js` (NEW)
-
-Created toolbar button component that:
-- Detects `core/image` blocks with `data-agent-image-id`
-- Adds "Generate AI Image" button to toolbar
-- Dispatches `wpaw:open-image-modal` event
-
-**File:** `includes/class-gutenberg-sidebar.php:139-155`
-
-Enqueued the new script with proper dependencies.
-
-### Result
-✅ Image blocks show "Generate AI Image" button
-✅ Clicking opens image generation modal
-✅ Works for individual image regeneration
-
----
-
-## ✅ Missing Integration #2: Modal Trigger After Article Generation - IMPLEMENTED
-
-### What Was Missing
-Image modal never opened automatically after article generation.
-
-### Solution
-
-**1. Event Listeners in Modal**
-
-**File:** `assets/js/image-modal.js:431-500`
-
-Added event listeners for:
-- `wpaw:open-image-review-modal` - Opens modal with all images
-- `wpaw:open-image-modal` - Opens modal for single image
-
-**2. Trigger in Sidebar**
-
-**File:** `assets/js/sidebar.js:3757-3777`
-
-After article generation completes:
-```javascript
-if (agentMode !== 'planning') {
- setTimeout(() => {
- const blocks = select('core/block-editor').getBlocks();
- const imagePlaceholders = blocks.filter(
- block => block.name === 'core/image' &&
- block.attributes['data-agent-image-id']
- );
-
- if (imagePlaceholders.length > 0) {
- window.dispatchEvent(
- new CustomEvent('wpaw:open-image-review-modal', {
- detail: {
- postId: postId,
- imageCount: imagePlaceholders.length
- }
- })
- );
- }
- }, 500);
-}
-```
-
-### Result
-✅ Modal opens automatically after article generation
-✅ Shows all image recommendations
-✅ User can review, edit, and generate images
-✅ Skippable if user doesn't want images
-
----
-
-## ✅ Missing Integration #3: Backend Image ID Generation - IMPLEMENTED
-
-### What Was Missing
-No connection between `[IMAGE: ...]` placeholders and database storage.
-
-### Solution
-Already covered in Defect #4 fix above.
-
-### Result
-✅ Image recommendations saved to database
-✅ Unique IDs generated per image
-✅ Linked to post and section
-✅ Ready for variant generation
-
----
-
-## Files Modified
-
-### Backend (PHP)
-1. ✅ `includes/class-markdown-parser.php`
- - Added `$image_placeholders` parameter to `parse()`
- - Added numbered+bold detection
- - Added `data-agent-image-id` to image blocks
-
-2. ✅ `includes/class-gutenberg-sidebar.php`
- - Extract image placeholders during execution
- - Generate unique IDs
- - Save to database
- - Pass to markdown parser
- - Enqueue new toolbar script
-
-### Frontend (JavaScript)
-3. ✅ `assets/js/sidebar.js`
- - Fixed "Create Outline Now" button (direct API calls)
- - Added modal trigger after article generation
-
-4. ✅ `assets/js/image-modal.js`
- - Added event listeners for modal opening
- - Support both review and single-image modes
-
-5. ✅ `assets/js/block-image-generate.js` (NEW)
- - Toolbar button for image blocks
- - Event dispatcher for modal
-
----
-
-## Testing Checklist
-
-### Defect #1 & #2: Planning Flow
-- [ ] Click "Create Outline Now"
-- [ ] Clarity quiz appears (if topic unclear)
-- [ ] Questions in correct language
-- [ ] Plan generates automatically after quiz
-- [ ] Cost tracking shows `clarity_check` action
-
-### Defect #3: Numbered Lists
-- [ ] Create article with pattern: `1. **Title**` + bullets
-- [ ] Verify renders as: Paragraph "1. **Title**" + unordered list
-- [ ] Check numbering continues: 1, 2, 3 (not 1, 1, 1)
-
-### Defect #4 & Integrations: Image Generation
-- [ ] Generate article with "Include Images" enabled
-- [ ] Verify `[IMAGE: ...]` placeholders appear
-- [ ] Check blocks have `data-agent-image-id` in inspector
-- [ ] Image modal opens automatically after generation
-- [ ] Can edit prompts and alt text
-- [ ] Can select variant count (1-3)
-- [ ] Cost estimate shows correctly
-- [ ] Generate variants works
-- [ ] Can select and commit variant
-- [ ] Block updates with real image
-- [ ] Toolbar button appears on image blocks
-- [ ] Can regenerate individual images
-
----
-
-## Known Issues
-
-### TypeScript Lint Errors (Non-Breaking)
-The TypeScript linter shows errors in `sidebar.js` around line 3779-3788. These are **false positives** - the JavaScript code is valid and will run correctly. The linter is confused by the try-catch block structure within the streaming response handler.
-
-**Impact:** None - code executes correctly
-**Action:** Can be ignored or suppressed with `// @ts-ignore` if needed
-
----
-
-## Next Steps
-
-1. **Test all fixes** using the checklist above
-2. **Verify database tables** exist after plugin reactivation
-3. **Test image generation flow** end-to-end
-4. **Check cost tracking** for all actions
-5. **Verify multilingual support** (clarity quiz in user's language)
-
----
-
-## Summary
-
-✅ **4 Defects Fixed**
-✅ **3 Missing Integrations Implemented**
-✅ **7 Files Modified**
-✅ **1 New File Created**
-✅ **Ready for User Testing**
-
-All issues from the defect report have been addressed. The plugin now has:
-- Working "Create Outline Now" button with clarity checks
-- Proper numbered list formatting
-- Complete image generation integration
-- Toolbar buttons for image blocks
-- Automatic modal triggers
-- Database persistence for image recommendations
-
-**No functionality was missed from the defect report.**
diff --git a/FOCUS_KEYWORD_ANCHOR_AND_IMAGE_FIXES.md b/FOCUS_KEYWORD_ANCHOR_AND_IMAGE_FIXES.md
deleted file mode 100644
index 3f3980a..0000000
--- a/FOCUS_KEYWORD_ANCHOR_AND_IMAGE_FIXES.md
+++ /dev/null
@@ -1,860 +0,0 @@
-# Focus Keyword Anchor System & Image Generation Fixes
-
-**Date:** January 30, 2026
-**Version:** 1.0
-**Status:** Implementation Plan
-
----
-
-## Table of Contents
-
-1. [Executive Summary](#executive-summary)
-2. [Part A: Focus Keyword Anchor System](#part-a-focus-keyword-anchor-system)
-3. [Part B: Image Generation Fixes](#part-b-image-generation-fixes)
-4. [Part C: UI Redesign](#part-c-ui-redesign)
-5. [Implementation Priority](#implementation-priority)
-
----
-
-## Executive Summary
-
-This document addresses three interconnected issues:
-
-| Issue | Root Cause | Solution |
-|-------|------------|----------|
-| Context loss during conversation | No persistent topic anchor | Focus Keyword as central context driver |
-| Image tables not created | Activation hook not re-run | Manual table creation + version check |
-| Image generation errors | Method name mismatch + missing public method | Fix method signatures |
-| Image toolbar not showing | Script dependency or block attribute issues | Debug and fix filter |
-
----
-
-# Part A: Focus Keyword Anchor System
-
-## Problem Statement
-
-The agent loses conversation context because:
-- Generic topic passed to outline generation
-- Chat history truncated to last 10 messages
-- No persistent anchor for user's intent
-- Recency bias causes LLM to focus on recent refinements
-
-## Solution: Focus Keyword as Context Anchor
-
-### Core Concept
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ Focus Keyword = Single Source of Truth for Article Topic │
-│ │
-│ • Always visible at top of chat │
-│ • Drives ALL API calls (clarity, planning, writing) │
-│ • Accumulates suggestions from each AI response │
-│ • User can select, change, or enter custom keyword │
-└─────────────────────────────────────────────────────────────┘
-```
-
-### UI Design
-
-#### Location: Top of Chatbox (Replacing Context Indicator)
-
-**Current UI:**
-```
-┌─────────────────────────────────────────────────────────────┐
-│ [1 messages] [$0.0221] [~500 tokens] ............ [↕] │
-└─────────────────────────────────────────────────────────────┘
-```
-
-**New UI (Compact - Default):**
-```
-┌─────────────────────────────────────────────────────────────┐
-│ 🎯 [Switch Career Usia 30+ ▼] [$0.02] ............ [↕] │
-└─────────────────────────────────────────────────────────────┘
-```
-
-**New UI (Expanded - When textarea expanded):**
-```
-┌─────────────────────────────────────────────────────────────┐
-│ 🎯 Focus Keyword │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ Switch Career Usia 30+ [▼] │ │
-│ └─────────────────────────────────────────────────────────┘ │
-│ │
-│ Suggestions: │
-│ ○ Switch Career Usia 30+ (from response #1) │
-│ ○ Vibe Coding untuk Pemula (from response #2) │
-│ ○ AI Web Design Tanpa Coding (from response #3) │
-│ ○ Custom... │
-│ │
-│ Session: $0.02 │ ~500 tokens │
-└─────────────────────────────────────────────────────────────┘
-```
-
-### Dropdown Behavior
-
-1. **Empty State**: Placeholder "Select or enter focus keyword..."
-2. **After Response #1**: 1 suggestion appears
-3. **After Response #2**: 2 suggestions (cumulative)
-4. **Max 5 suggestions**: Older ones rotate out, "Show all" option
-5. **Custom Option**: Always last, triggers text input
-6. **Selection**: Immediately saves to `postConfig.focus_keyword`
-
-### Data Flow
-
-```
-User Message
- │
- ▼
-┌────────────────┐
-│ AI Response │
-│ + Extract │──────► Add to suggestions dropdown
-│ keyword │
-└────────────────┘
- │
- ▼
-User Selects Keyword (or AI auto-selects first suggestion)
- │
- ▼
-┌────────────────────────────────────────────────────────────┐
-│ ALL subsequent API calls include: │
-│ { │
-│ focus_keyword: "Switch Career Usia 30+", │
-│ topic: "...", │
-│ chatHistory: [...], │
-│ ... │
-│ } │
-└────────────────────────────────────────────────────────────┘
- │
- ▼
-Backend System Prompt includes:
-"PRIMARY TOPIC: {focus_keyword}
-All content must relate to this topic.
-Recent conversation refinements should ENHANCE this topic, not replace it."
-```
-
-### Keyword Extraction Logic
-
-```javascript
-// In chat response handler
-const extractFocusKeywordSuggestion = (aiResponse) => {
- // Method 1: AI explicitly suggests (preferred)
- // Look for pattern: "Focus Keyword Suggestion: ..."
- const explicitMatch = aiResponse.match(/focus keyword suggestion[:\s]+["']?([^"'\n]+)["']?/i);
- if (explicitMatch) return explicitMatch[1].trim();
-
- // Method 2: Extract from first heading or bold text
- const headingMatch = aiResponse.match(/^#+\s+(.+)$/m);
- if (headingMatch) return headingMatch[1].trim();
-
- // Method 3: Extract prominent phrase (first bold)
- const boldMatch = aiResponse.match(/\*\*([^*]+)\*\*/);
- if (boldMatch) return boldMatch[1].trim();
-
- return null;
-};
-```
-
-### Backend Integration
-
-#### 1. Update System Prompts
-
-**File:** `includes/class-gutenberg-sidebar.php`
-
-```php
-// In stream_generate_plan() - Line ~1723
-$focus_keyword = $post_config['focus_keyword'] ?? '';
-$focus_keyword_instruction = '';
-if (!empty($focus_keyword)) {
- $focus_keyword_instruction = "
-PRIMARY TOPIC ANCHOR: \"{$focus_keyword}\"
-
-CRITICAL: This article MUST be about \"{$focus_keyword}\".
-- The title MUST include or relate to \"{$focus_keyword}\"
-- All sections MUST support this primary topic
-- Recent conversation refinements are meant to ENHANCE this topic, not REPLACE it
-- If user discussed sub-topics (e.g., AI tools, web design), treat them as ASPECTS of the primary topic
-";
-}
-
-$system_prompt = "You are an expert content strategist...
-
-{$focus_keyword_instruction}
-
-IMPORTANT CONSTRAINT: {$section_limit}
-...";
-```
-
-#### 2. Update Chat Response to Include Keyword Suggestion
-
-**File:** `includes/class-gutenberg-sidebar.php`
-
-```php
-// In handle_chat_request() - Add to system prompt
-$system_prompt .= "
-
-At the END of your response, if appropriate, suggest a focus keyword for the article in this format:
-**Focus Keyword Suggestion:** [your suggested keyword]
-
-The keyword should be:
-- 2-5 words
-- SEO-friendly
-- Capture the main topic discussed
-";
-```
-
-#### 3. Persist Focus Keyword
-
-**File:** `includes/class-gutenberg-sidebar.php`
-
-```php
-// In handle_generate_plan() - Line ~1237
-$focus_keyword = $post_config['focus_keyword'] ?? '';
-
-// Save to post meta for persistence
-if ($post_id > 0 && !empty($focus_keyword)) {
- update_post_meta($post_id, '_wpaw_focus_keyword', $focus_keyword);
-}
-```
-
-### Frontend Implementation
-
-#### 1. New State Variables
-
-**File:** `assets/js/sidebar.js`
-
-```javascript
-// Add new state
-const [focusKeywordSuggestions, setFocusKeywordSuggestions] = wp.element.useState([]);
-const [selectedFocusKeyword, setSelectedFocusKeyword] = wp.element.useState('');
-
-// Load from postConfig on mount
-wp.element.useEffect(() => {
- if (postConfig.focus_keyword) {
- setSelectedFocusKeyword(postConfig.focus_keyword);
- }
-}, [postConfig.focus_keyword]);
-```
-
-#### 2. Update postConfig When Keyword Changes
-
-```javascript
-const handleFocusKeywordChange = (keyword) => {
- setSelectedFocusKeyword(keyword);
- updatePostConfig('focus_keyword', keyword);
-};
-```
-
-#### 3. Extract Suggestions from AI Responses
-
-```javascript
-// In streaming response handler, after accumulating content
-const suggestion = extractFocusKeywordSuggestion(accumulatedContent);
-if (suggestion && !focusKeywordSuggestions.includes(suggestion)) {
- setFocusKeywordSuggestions(prev => {
- const updated = [...prev, suggestion];
- // Keep max 5 suggestions
- return updated.slice(-5);
- });
-
- // Auto-select first suggestion if none selected
- if (!selectedFocusKeyword) {
- handleFocusKeywordChange(suggestion);
- }
-}
-```
-
-#### 4. Render Focus Keyword Bar (Replacing Context Indicator)
-
-```javascript
-const renderFocusKeywordBar = () => {
- return wp.element.createElement('div', {
- className: 'wpaw-focus-keyword-bar'
- },
- // Keyword dropdown
- wp.element.createElement('div', { className: 'wpaw-focus-keyword-wrapper' },
- wp.element.createElement('span', { className: 'wpaw-focus-keyword-icon' }, '🎯'),
- wp.element.createElement('select', {
- className: 'wpaw-focus-keyword-select',
- value: selectedFocusKeyword,
- onChange: (e) => {
- if (e.target.value === '__custom__') {
- // Show custom input
- setShowCustomKeywordInput(true);
- } else {
- handleFocusKeywordChange(e.target.value);
- }
- }
- },
- wp.element.createElement('option', { value: '' }, 'Select focus keyword...'),
- focusKeywordSuggestions.map((kw, idx) =>
- wp.element.createElement('option', { key: idx, value: kw }, kw)
- ),
- wp.element.createElement('option', { value: '__custom__' }, '+ Custom keyword...')
- )
- ),
-
- // Cost display (compact)
- wp.element.createElement('span', { className: 'wpaw-cost-compact' },
- '$' + cost.session.toFixed(2)
- ),
-
- // Expand button
- wp.element.createElement('button', {
- className: 'wpaw-expand-btn',
- onClick: () => setIsTextareaExpanded(!isTextareaExpanded)
- }, isTextareaExpanded ? '↓' : '↑')
- );
-};
-```
-
-### CSS Styling
-
-```css
-.wpaw-focus-keyword-bar {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 6px 10px;
- background: #1e1e1e;
- border-bottom: 1px solid #3c3c3c;
- font-size: 12px;
-}
-
-.wpaw-focus-keyword-wrapper {
- display: flex;
- align-items: center;
- gap: 4px;
- flex: 1;
-}
-
-.wpaw-focus-keyword-select {
- flex: 1;
- background: #2c2c2c;
- border: 1px solid #3c3c3c;
- color: #fff;
- padding: 4px 8px;
- border-radius: 4px;
- font-size: 12px;
- max-width: 200px;
-}
-
-.wpaw-focus-keyword-select:focus {
- border-color: #007cba;
- outline: none;
-}
-
-.wpaw-cost-compact {
- color: #a7aaad;
- font-size: 11px;
-}
-
-.wpaw-expand-btn {
- background: transparent;
- border: none;
- color: #a7aaad;
- cursor: pointer;
- padding: 4px;
-}
-```
-
----
-
-# Part B: Image Generation Fixes
-
-## Error #1: Missing Database Tables
-
-### Symptoms
-```
-WordPress database error Unknown error 1146 for query
-SELECT * FROM wp_wpaw_images_variants...
-```
-
-### Root Cause
-Tables are created in activation hook, but plugin was already active when code was added. Activation hook only runs on fresh activation.
-
-### Fix: Add Version-Based Table Creation
-
-**File:** `wp-agentic-writer.php`
-
-```php
-// Add after plugin initialization
-add_action('plugins_loaded', 'wp_agentic_writer_maybe_create_tables');
-
-function wp_agentic_writer_maybe_create_tables() {
- $current_version = get_option('wpaw_db_version', '0');
- $required_version = '1.1.0'; // Bump when adding new tables
-
- if (version_compare($current_version, $required_version, '<')) {
- // Create cost tracking table
- wp_agentic_writer_create_cost_table();
-
- // Create image management tables
- WP_Agentic_Writer_Image_Manager::get_instance()->create_tables();
-
- // Update version
- update_option('wpaw_db_version', $required_version);
- }
-}
-```
-
-### Immediate Fix (Manual)
-
-Run this SQL in phpMyAdmin or WP-CLI:
-
-```sql
--- Table 1: wp_wpaw_images
-CREATE TABLE IF NOT EXISTS `wp_wpaw_images` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
- `post_id` bigint(20) NOT NULL,
- `agent_image_id` varchar(50) NOT NULL,
- `placement` varchar(50) NOT NULL,
- `section_title` text,
- `prompt_initial` text,
- `prompt_refined` text,
- `alt_text_initial` text,
- `alt_text_refined` text,
- `image_model` varchar(100),
- `status` varchar(20) DEFAULT 'pending',
- `selected_variant_id` bigint(20) DEFAULT NULL,
- `attachment_id` bigint(20) DEFAULT NULL,
- `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
- `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- PRIMARY KEY (`id`),
- UNIQUE KEY `idx_agent_image_id` (`agent_image_id`),
- KEY `idx_post_id` (`post_id`),
- KEY `idx_status` (`status`),
- KEY `idx_created` (`created_at`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-
--- Table 2: wp_wpaw_images_variants
-CREATE TABLE IF NOT EXISTS `wp_wpaw_images_variants` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
- `agentic_image_id` bigint(20) NOT NULL,
- `post_id` bigint(20) NOT NULL,
- `variant_number` tinyint(3) NOT NULL,
- `prompt_used` text,
- `temp_url` text,
- `temp_path` text,
- `generation_model` varchar(100),
- `generation_cost` decimal(10,6) DEFAULT 0,
- `width` int(11) DEFAULT NULL,
- `height` int(11) DEFAULT NULL,
- `status` varchar(20) DEFAULT 'temp',
- `attachment_id` bigint(20) DEFAULT NULL,
- `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`id`),
- KEY `idx_agentic_image_id` (`agentic_image_id`),
- KEY `idx_post_id` (`post_id`),
- KEY `idx_status` (`status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-```
-
----
-
-## Error #2: Undefined Method `save_image_recommendation()`
-
-### Symptoms
-```
-PHP Fatal error: Call to undefined method
-WP_Agentic_Writer_Image_Manager::save_image_recommendation()
-```
-
-### Root Cause
-
-**Caller (class-gutenberg-sidebar.php:2185):**
-```php
-$image_manager->save_image_recommendation(
- $post_id,
- $agent_image_id,
- 'section_' . $section_id,
- $heading,
- trim( $description ),
- trim( $description )
-);
-```
-
-**Actual Method (class-image-manager.php:320):**
-```php
-private function save_image_recommendations( $post_id, $images ) {
- // Takes array of images, not individual params
-}
-```
-
-### Issues:
-1. Method name is plural (`save_image_recommendations`) vs singular (`save_image_recommendation`)
-2. Method is `private`, not `public`
-3. Method signature is different (expects array of images)
-
-### Fix: Add Public Method with Correct Signature
-
-**File:** `includes/class-image-manager.php`
-
-Add after line 340:
-
-```php
-/**
- * Save single image recommendation to database.
- *
- * @param int $post_id Post ID.
- * @param string $agent_image_id Unique image identifier.
- * @param string $placement Placement location.
- * @param string $section_title Section title.
- * @param string $prompt Image prompt/description.
- * @param string $alt_text Alt text for image.
- * @return int|false Insert ID or false on failure.
- */
-public function save_image_recommendation( $post_id, $agent_image_id, $placement, $section_title, $prompt, $alt_text ) {
- global $wpdb;
- $table = $wpdb->prefix . 'wpaw_images';
-
- $settings = get_option( 'wp_agentic_writer_settings', array() );
- $image_model = $settings['image_model'] ?? 'openai/gpt-4o';
-
- $result = $wpdb->insert(
- $table,
- array(
- 'post_id' => $post_id,
- 'agent_image_id' => $agent_image_id,
- 'placement' => $placement,
- 'section_title' => $section_title,
- 'prompt_initial' => $prompt,
- 'alt_text_initial' => $alt_text,
- 'image_model' => $image_model,
- 'status' => 'pending',
- ),
- array( '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )
- );
-
- if ( $result ) {
- return $wpdb->insert_id;
- }
-
- return false;
-}
-```
-
----
-
-## Error #3: Image Block Toolbar Not Showing
-
-### Symptoms
-No "Generate AI Image" button appears in image block toolbar.
-
-### Potential Causes
-
-1. **Script not loaded**: Check browser console for errors
-2. **Block attribute missing**: `data-agent-image-id` not set on blocks
-3. **Filter not applied**: WordPress filter may not be working
-
-### Debug Steps
-
-**Step 1: Check if script is loaded**
-```javascript
-// In browser console
-console.log(typeof wp.hooks.applyFilters);
-console.log(wp.hooks.hasFilter('editor.BlockEdit', 'wp-agentic-writer/image-generate-toolbar'));
-```
-
-**Step 2: Check if blocks have the attribute**
-```javascript
-// In browser console
-wp.data.select('core/block-editor').getBlocks().forEach(block => {
- if (block.name === 'core/image') {
- console.log('Image block:', block.clientId, block.attributes);
- }
-});
-```
-
-**Step 3: Verify attribute exists**
-
-The issue may be that `data-agent-image-id` is stored in block HTML but not in attributes.
-
-### Fix: Update Block Detection Logic
-
-**File:** `assets/js/block-image-generate.js`
-
-The current code checks `block.attributes['data-agent-image-id']`, but the attribute might be stored differently.
-
-```javascript
-// Current (may not work)
-const agentImageId = block?.attributes?.['data-agent-image-id'];
-
-// Fix: Also check innerHTML for the attribute
-const hasAgentImageId = () => {
- if (block?.attributes?.['data-agent-image-id']) return true;
-
- // Check innerHTML
- const innerHTML = block?.attributes?.innerHTML || '';
- if (innerHTML.includes('data-agent-image-id')) return true;
-
- // Check original HTML
- const originalContent = block?.originalContent || '';
- if (originalContent.includes('data-agent-image-id')) return true;
-
- return false;
-};
-
-if (!hasAgentImageId()) {
- return wp.element.createElement(BlockEdit, props);
-}
-```
-
-### Alternative Fix: Check for Placeholder Images
-
-If the image block has no `url` but has `alt` text, it's likely a placeholder:
-
-```javascript
-const isPlaceholder = block?.name === 'core/image' &&
- !block?.attributes?.url &&
- block?.attributes?.alt;
-
-if (!agentImageId && !isPlaceholder) {
- return wp.element.createElement(BlockEdit, props);
-}
-```
-
----
-
-# Part C: UI Redesign
-
-## Current Context Indicator Bar
-
-**Location:** `assets/js/sidebar.js` - `renderContextIndicator()`
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ [💬 1 messages] [💰 $0.0221] [~500 tokens] ..... [↕] │
-└─────────────────────────────────────────────────────────────┘
-```
-
-## New Focus Keyword Bar Design
-
-### Compact Mode (Default)
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ 🎯 [Switch Career Usia 30+ ▼] [$0.02] [↕] │
-└─────────────────────────────────────────────────────────────┘
- │ │ │
- └─ Dropdown with suggestions └─ Session cost └─ Expand
-```
-
-### Expanded Mode (When textarea expanded)
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ 🎯 FOCUS KEYWORD │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ Switch Career Usia 30+ [▼] │ │
-│ └─────────────────────────────────────────────────────────┘ │
-│ │
-│ 📝 AI Suggestions: │
-│ ┌─────────────────────────────────────────────────────────┐ │
-│ │ ● Switch Career Usia 30+ (Response #1) │ │
-│ │ ○ Vibe Coding untuk Pemula (Response #2) │ │
-│ │ ○ AI Web Design Tanpa Coding (Response #3) │ │
-│ │ ○ + Enter custom keyword... │ │
-│ └─────────────────────────────────────────────────────────┘ │
-│ │
-│ 💰 $0.02 this session │ 📊 ~500 tokens │
-└─────────────────────────────────────────────────────────────┘
-```
-
-## Code Changes Required
-
-### Replace `renderContextIndicator()` with `renderFocusKeywordBar()`
-
-**File:** `assets/js/sidebar.js`
-
-```javascript
-// REMOVE this function
-const renderContextIndicator = () => { ... }
-
-// ADD this function
-const renderFocusKeywordBar = () => {
- const hasKeyword = selectedFocusKeyword && selectedFocusKeyword.length > 0;
-
- if (isTextareaExpanded) {
- return renderExpandedFocusKeywordBar();
- }
-
- // Compact mode
- return wp.element.createElement('div', {
- className: 'wpaw-focus-keyword-bar wpaw-compact'
- },
- wp.element.createElement('div', { className: 'wpaw-fk-left' },
- wp.element.createElement('span', { className: 'wpaw-fk-icon' }, '🎯'),
- wp.element.createElement('select', {
- className: 'wpaw-fk-select',
- value: selectedFocusKeyword || '',
- onChange: handleKeywordSelect,
- disabled: isLoading
- },
- wp.element.createElement('option', { value: '' },
- hasKeyword ? 'Change keyword...' : 'Select focus keyword...'
- ),
- ...focusKeywordSuggestions.map((kw, i) =>
- wp.element.createElement('option', { key: i, value: kw },
- kw.length > 25 ? kw.substring(0, 25) + '...' : kw
- )
- ),
- wp.element.createElement('option', { value: '__custom__' }, '+ Custom...')
- )
- ),
- wp.element.createElement('span', { className: 'wpaw-fk-cost' },
- '$' + (cost.session || 0).toFixed(2)
- ),
- wp.element.createElement('button', {
- className: 'wpaw-fk-expand',
- onClick: () => setIsTextareaExpanded(true),
- title: 'Expand'
- }, '↕')
- );
-};
-
-const renderExpandedFocusKeywordBar = () => {
- return wp.element.createElement('div', {
- className: 'wpaw-focus-keyword-bar wpaw-expanded'
- },
- // Header
- wp.element.createElement('div', { className: 'wpaw-fk-header' },
- wp.element.createElement('span', null, '🎯 FOCUS KEYWORD'),
- wp.element.createElement('button', {
- className: 'wpaw-fk-collapse',
- onClick: () => setIsTextareaExpanded(false)
- }, '↓')
- ),
-
- // Main input
- wp.element.createElement('div', { className: 'wpaw-fk-main-input' },
- showCustomKeywordInput
- ? wp.element.createElement('input', {
- type: 'text',
- className: 'wpaw-fk-custom-input',
- placeholder: 'Enter custom focus keyword...',
- value: customKeywordInput,
- onChange: (e) => setCustomKeywordInput(e.target.value),
- onKeyDown: (e) => {
- if (e.key === 'Enter') {
- handleFocusKeywordChange(customKeywordInput);
- setShowCustomKeywordInput(false);
- }
- },
- autoFocus: true
- })
- : wp.element.createElement('select', {
- className: 'wpaw-fk-select-full',
- value: selectedFocusKeyword || '',
- onChange: handleKeywordSelect
- },
- wp.element.createElement('option', { value: '' }, 'Select focus keyword...'),
- ...focusKeywordSuggestions.map((kw, i) =>
- wp.element.createElement('option', { key: i, value: kw }, kw)
- ),
- wp.element.createElement('option', { value: '__custom__' }, '+ Enter custom keyword...')
- )
- ),
-
- // Suggestions list
- focusKeywordSuggestions.length > 0 && wp.element.createElement('div', {
- className: 'wpaw-fk-suggestions'
- },
- wp.element.createElement('div', { className: 'wpaw-fk-suggestions-label' },
- '📝 AI Suggestions:'
- ),
- focusKeywordSuggestions.map((kw, i) =>
- wp.element.createElement('div', {
- key: i,
- className: 'wpaw-fk-suggestion-item' + (kw === selectedFocusKeyword ? ' selected' : ''),
- onClick: () => handleFocusKeywordChange(kw)
- },
- wp.element.createElement('span', { className: 'wpaw-fk-radio' },
- kw === selectedFocusKeyword ? '●' : '○'
- ),
- wp.element.createElement('span', { className: 'wpaw-fk-suggestion-text' }, kw),
- wp.element.createElement('span', { className: 'wpaw-fk-suggestion-source' },
- '(Response #' + (i + 1) + ')'
- )
- )
- )
- ),
-
- // Stats
- wp.element.createElement('div', { className: 'wpaw-fk-stats' },
- wp.element.createElement('span', null, '💰 $' + (cost.session || 0).toFixed(2) + ' this session'),
- wp.element.createElement('span', null, '│'),
- wp.element.createElement('span', null, '📊 ~' + (messages.length * 500) + ' tokens')
- )
- );
-};
-```
-
----
-
-# Implementation Priority
-
-## Phase 1: Critical Fixes (Day 1)
-
-| Task | File | Priority |
-|------|------|----------|
-| Create missing database tables | Manual SQL or add version check | CRITICAL |
-| Add `save_image_recommendation()` method | `class-image-manager.php` | CRITICAL |
-| Fix image toolbar block detection | `block-image-generate.js` | HIGH |
-
-## Phase 2: Focus Keyword System (Day 2-3)
-
-| Task | File | Priority |
-|------|------|----------|
-| Add state variables for focus keyword | `sidebar.js` | HIGH |
-| Implement keyword extraction from responses | `sidebar.js` | HIGH |
-| Create `renderFocusKeywordBar()` | `sidebar.js` | HIGH |
-| Add CSS styling | `sidebar.css` | MEDIUM |
-| Update backend to use focus_keyword | `class-gutenberg-sidebar.php` | HIGH |
-
-## Phase 3: Integration & Testing (Day 4)
-
-| Task | Priority |
-|------|----------|
-| Test image generation flow end-to-end | HIGH |
-| Test focus keyword persistence across modes | HIGH |
-| Test context continuity with focus keyword | HIGH |
-| Verify outline generation uses focus keyword | HIGH |
-
----
-
-# Files to Modify Summary
-
-| File | Changes |
-|------|---------|
-| `wp-agentic-writer.php` | Add `plugins_loaded` hook for table creation |
-| `includes/class-image-manager.php` | Add public `save_image_recommendation()` method |
-| `assets/js/block-image-generate.js` | Fix block detection logic |
-| `assets/js/sidebar.js` | Replace context indicator with focus keyword bar |
-| `assets/css/sidebar.css` | Add focus keyword bar styles |
-| `includes/class-gutenberg-sidebar.php` | Update prompts to use focus_keyword |
-
----
-
-# Testing Checklist
-
-## Image Generation
-- [ ] Tables exist in database
-- [ ] No PHP errors on article generation
-- [ ] Image toolbar button appears on placeholder images
-- [ ] Modal opens when clicking toolbar button
-- [ ] Image generation works end-to-end
-
-## Focus Keyword System
-- [ ] Focus keyword bar appears above chat input
-- [ ] Suggestions accumulate after each AI response
-- [ ] Selecting keyword updates postConfig
-- [ ] Custom keyword input works
-- [ ] Expanded view shows all suggestions
-- [ ] Keyword persists after page refresh
-- [ ] Outline generation uses selected keyword
-- [ ] Context maintained across chat → planning → writing modes
-
----
-
-**Document Status:** Ready for Implementation
-**Last Updated:** January 30, 2026
diff --git a/FRONTEND_IMPLEMENTATION.md b/FRONTEND_IMPLEMENTATION.md
deleted file mode 100644
index 2b487f4..0000000
--- a/FRONTEND_IMPLEMENTATION.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# Frontend Implementation Guide
-
-This document outlines all frontend changes needed to complete the agentic context implementation.
-
----
-
-## Summary of Required Changes
-
-### Phase 1.2 & 1.3: Writing Mode UX
-- Add empty state check and UI
-- Add warning for notes in Writing mode
-- Add CSS for empty state
-
-### Phase 2.4 & 2.5: Agentic Features
-- Add summarization function
-- Add intent detection function
-- Add contextual action cards
-- Add CSS for contextual actions
-
-### Phase 3: UX Enhancements
-- Add context indicator
-- Add /reset command
-- Add context mode settings (backend)
-
----
-
-## Implementation Status
-
-✅ **Backend Complete:**
-- Chat history sent to all endpoints
-- `/summarize-context` endpoint added
-- `/detect-intent` endpoint added
-- Cost tracking supports new operations
-
-⏳ **Frontend Pending:**
-- Writing mode empty state
-- Writing mode notes warning
-- Summarization logic
-- Intent detection logic
-- Context indicator
-- /reset command
-- Context mode settings
-
----
-
-## Code Locations
-
-### sidebar.js Key Functions to Add/Modify:
-1. `shouldShowWritingEmptyState()` - NEW
-2. `renderWritingEmptyState()` - NEW
-3. `handleExecuteArticle()` - MODIFY (add plan check)
-4. `handleSendMessage()` - MODIFY (add writing mode warning)
-5. `summarizeChatHistory()` - NEW
-6. `detectUserIntent()` - NEW
-7. `renderContextualAction()` - NEW
-8. `renderContextIndicator()` - NEW
-9. `handleResetCommand()` - NEW
-
-### sidebar.css Additions:
-1. `.wpaw-writing-empty-state` styles
-2. `.wpaw-contextual-action` styles
-3. `.wpaw-context-indicator` styles
-
----
-
-## Next Steps
-
-1. Implement Writing mode empty state (Phase 1.2)
-2. Implement Writing mode notes warning (Phase 1.3)
-3. Implement summarization (Phase 2.4)
-4. Implement intent detection (Phase 2.5)
-5. Implement context indicator (Phase 3.1)
-6. Implement /reset command (Phase 3.2)
-7. Implement context settings (Phase 3.3)
-
----
-
-**Current Focus:** Implementing all frontend changes systematically
diff --git a/GENERATION_HANG_DEBUG.md b/GENERATION_HANG_DEBUG.md
deleted file mode 100644
index fd52496..0000000
--- a/GENERATION_HANG_DEBUG.md
+++ /dev/null
@@ -1,242 +0,0 @@
-# Generation Hang Issue - Debugging Steps
-
-## Problem Report
-
-User submitted Indonesian prompt:
-```
-cara membuat toko online dengan wordpress cukup dengan page builder tanpa plugin ecommerce, cukup dengan katalog, single page dan tombol click to whatsapp. Sertakan juga cara membuat link whatsapp yang dynamic dengan menyesuaikan isi template pesan menyebutkan nama produknya (post_title)
-```
-
-**Observed Behavior:**
-- No clarification quiz appeared (correct - prompt is detailed enough)
-- Status changed to "Generating article..."
-- Generation hung/stuck at this point
-- No content was generated
-
----
-
-## What I've Added
-
-### 1. Frontend Timeout Detection (assets/js/sidebar.js)
-
-Added a **2-minute timeout** for article generation:
-- If no response received within 120 seconds, shows timeout error
-- Automatically cancels the hanging request
-- Displays user-friendly error message
-
-**Location:** Lines 660-672
-```javascript
-// Add timeout to detect hanging responses
-const timeout = setTimeout( () => {
- if ( isLoading ) {
- console.error( 'Generation timeout - no response received' );
- setMessages( prev => [ ...prev, {
- role: 'system',
- type: 'error',
- content: 'Request timeout. The AI is taking too long to respond. Please try again.'
- } ] );
- setIsLoading( false );
- reader.cancel();
- }
-}, 120000 ); // 2 minute timeout
-```
-
-### 2. Backend Logging (includes/class-gutenberg-sidebar.php)
-
-Added error logging at critical points to identify where the hang occurs:
-
-**Plan Generation Logging (Lines 608-614):**
-```php
-// Log the request for debugging
-error_log( 'WP Agentic Writer: Calling OpenRouter API for planning. Topic: ' . substr( $topic, 0, 100 ) );
-error_log( 'WP Agentic Writer: Detected language: ' . $detected_language );
-
-$response = $provider->chat( $messages, array( 'temperature' => 0.7 ), 'planning' );
-
-error_log( 'WP Agentic Writer: OpenRouter API response received' );
-```
-
-**Article Generation Logging (Lines 823-848):**
-```php
-// Log before calling streaming API
-error_log( 'WP Agentic Writer: Starting section generation: ' . $section['heading'] );
-
-// ... code ...
-
-error_log( 'WP Agentic Writer: Calling OpenRouter streaming API' );
-
-$response = $provider->chat_stream( ... );
-```
-
----
-
-## How to Debug
-
-### Step 1: Enable WordPress Debug Logging
-
-Add to `wp-config.php`:
-```php
-define( 'WP_DEBUG', true );
-define( 'WP_DEBUG_LOG', true );
-define( 'WP_DEBUG_DISPLAY', false );
-```
-
-### Step 2: Reproduce the Issue
-
-1. Open the WordPress editor
-2. Submit the same Indonesian prompt
-3. Wait for the timeout (2 minutes) or note when it hangs
-
-### Step 3: Check Debug Log
-
-The debug log is located at:
-```
-/wp-content/debug.log
-```
-
-Look for these log entries:
-- `WP Agentic Writer: Calling OpenRouter API for planning`
-- `WP Agentic Writer: Detected language: indonesian`
-- `WP Agentic Writer: OpenRouter API response received`
-- `WP Agentic Writer: Starting section generation: ...`
-- `WP Agentic Writer: Calling OpenRouter streaming API`
-
-### Step 4: Identify the Hang Point
-
-**If you see:**
-```
-WP Agentic Writer: Calling OpenRouter API for planning
-```
-
-**But NOT:**
-```
-WP Agentic Writer: OpenRouter API response received
-```
-
-→ **Issue:** Plan generation API call is hanging
-
-**If you see:**
-```
-WP Agentic Writer: Starting section generation: ...
-WP Agentic Writer: Calling OpenRouter streaming API
-```
-
-**But no content appears**
-
-→ **Issue:** Article generation streaming API is hanging
-
----
-
-## Common Causes & Solutions
-
-### Cause 1: OpenRouter API Timeout
-
-**Symptoms:**
-- Log shows API call started but no response
-- Takes longer than 30-60 seconds
-
-**Solution:**
-- Check OpenRouter API status: https://status.openrouter.ai/
-- Verify API key is valid in settings
-- Try a different model (shorter prompt, simpler request)
-
-### Cause 2: PHP Execution Timeout
-
-**Symptoms:**
-- Script dies after max_execution_time
-- PHP fatal error in logs
-
-**Solution:**
-Add to `wp-config.php`:
-```php
-set_time_limit( 300 ); // 5 minutes
-@ini_set( 'max_execution_time', 300 );
-```
-
-### Cause 3: Memory Limit
-
-**Symptoms:**
-- "Allowed memory size exhausted" error
-- Script terminates unexpectedly
-
-**Solution:**
-Add to `wp-config.php`:
-```php
-define( 'WP_MEMORY_LIMIT', '512M' );
-```
-
-### Cause 4: Network/Blocking Issues
-
-**Symptoms:**
-- Timeout happens immediately
-- No logs at all
-
-**Solution:**
-- Check firewall/security plugin settings
-- Verify server can reach api.openrouter.ai
-- Check for CDN/caching interference
-
-### Cause 5: Prompt Too Complex
-
-**Symptoms:**
-- Works with simple prompts
-- Hangs with complex Indonesian prompt
-
-**Solution:**
-- Break into smaller requests
-- Use quiz to gather requirements first
-- Simplify the prompt structure
-
----
-
-## Testing Checklist
-
-### Basic Tests:
-- [ ] Simple English prompt: "Write about SEO"
-- [ ] Simple Indonesian prompt: "Tulis tentang SEO"
-- [ ] Medium complexity prompt
-- [ ] Complex prompt (like the user's)
-
-### Diagnostic Tests:
-- [ ] Check debug.log after each test
-- [ ] Note which log entries appear
-- [ ] Measure time to hang/timeout
-- [ ] Check browser console for errors
-- [ ] Check Network tab in DevTools
-
-### API Tests:
-- [ ] Verify OpenRouter API key works
-- [ ] Test API directly with curl:
-```bash
-curl -X POST https://openrouter.ai/api/v1/chat/completions \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "anthropic/claude-3-haiku",
- "messages": [{"role": "user", "content": "Say hello"}]
- }'
-```
-
----
-
-## Next Steps
-
-1. **Enable debug logging** in wp-config.php
-2. **Reproduce the issue** with the same Indonesian prompt
-3. **Check debug.log** for the sequence of log entries
-4. **Identify where it hangs** (planning or generation)
-5. **Share the log contents** so we can pinpoint the exact issue
-
-The logs will tell us:
-- Is the language detection working?
-- Is the planning API call completing?
-- Is the article generation starting?
-- Where exactly does it hang?
-
----
-
-**Files Modified:**
-1. [assets/js/sidebar.js](assets/js/sidebar.js) - Added 2-minute timeout
-2. [includes/class-gutenberg-sidebar.php](includes/class-gutenberg-sidebar.php) - Added debug logging
-
-**Status:** ⏳ Awaiting debug log information from user
diff --git a/HYBRID-PROVIDER-WALKTHROUGH.md b/HYBRID-PROVIDER-WALKTHROUGH.md
deleted file mode 100644
index f062dbd..0000000
--- a/HYBRID-PROVIDER-WALKTHROUGH.md
+++ /dev/null
@@ -1,500 +0,0 @@
-# Hybrid AI Provider System - User Walkthrough
-
-## Overview
-
-The WP Agentic Writer plugin now supports multiple AI providers for different tasks:
-
-| Provider | Use Case | Cost | Best For |
-|----------|----------|------|----------|
-| **Local Backend** | Text generation (chat, planning, writing) | **$0** | Daily use, privacy, unlimited generation |
-| **Codex** | Alternative text provider | Per-token | When Local Backend unavailable |
-| **OpenRouter** | Image generation + fallback | Per-token | Images, fallback when local offline |
-
-**The magic:** Route text tasks to your free local Claude CLI, images to OpenRouter's best models.
-
----
-
-## Quick Start (5 Minutes)
-
-### Step 1: Check Prerequisites
-
-You need:
-- ✅ Claude CLI installed (`claude --version` should work)
-- ✅ Node.js 18+ installed (`node --version`)
-- ✅ Z.ai subscription or Anthropic API key configured in Claude CLI
-
-Don't have these? Get them first:
-- **Claude CLI**: https://claude.ai/code or https://z.ai
-- **Node.js**: https://nodejs.org
-- **Z.ai**: https://z.ai (free tier available)
-
-### Step 2: Download & Start Local Backend
-
-1. **In WordPress Admin**, go to **Settings → Agentic Writer → Local Backend**
-2. Click **"Download Local Backend v1.0.0"**
-3. **Extract the ZIP** to a folder on your machine
-4. **Open terminal** in that folder
-5. **Run:** `./start-proxy.sh`
-
-You'll see output like:
-```
-🚀 Starting Claude Proxy Server...
-📦 Installing dependencies...
-✅ Dependencies installed
-
-🌐 Local Backend is running!
- Base URL: http://192.168.1.105:8080
- Health Check: http://192.168.1.105:8080/ping
-
-💡 To test: ./test-connection.sh
-💡 To stop: ./stop-proxy.sh
-```
-
-**Copy the Base URL** (e.g., `http://192.168.1.105:8080`)
-
-### Step 3: Configure Plugin
-
-1. **In WordPress**, paste the Base URL into **"Base URL"** field
-2. Leave **API Key** as `dummy` (ignored by local proxy)
-3. Click **"Test Connection"**
-4. You should see: ✅ **Connected! Proxy responding correctly.**
-
-### Step 4: Set Provider Routing (Optional)
-
-By default, all text tasks use your Local Backend (free). To customize:
-
-1. In the **Local Backend** tab, scroll to **"Provider Routing"**
-2. Choose provider per task:
- - **Chat** → Local Backend (free)
- - **Clarity Check** → Local Backend (free)
- - **Outline Planning** → Local Backend (free)
- - **Article Writing** → Local Backend (free)
- - **Content Refinement** → Local Backend or Codex
- - **Image Generation** → OpenRouter (only option)
-
-3. Click **"Save Settings"**
-
-### Step 5: Generate Content
-
-1. **Open any post** in Gutenberg editor
-2. Click the **Agentic Writer** sidebar (🤖 icon)
-3. Type a topic like: *"Write about AI trends in 2025"*
-4. Watch as content generates with **$0.00 cost**!
-
----
-
-## Provider Deep Dive
-
-### 🏠 Local Backend (Recommended)
-
-**What it is:** A Node.js proxy running on your machine that connects to your Claude CLI.
-
-**Why use it:**
-- 💰 **$0 cost** for unlimited text generation
-- 🔒 **Privacy** - content never leaves your machine
-- ⚡ **Speed** - LAN latency vs cloud round-trip
-- 🎛️ **Same quality** - uses same Claude models as cloud
-
-**How it works:**
-```
-WordPress → Your Computer (proxy) → Claude CLI → Z.ai/Anthropic
-```
-
-**Limitations:**
-- One request at a time (Claude CLI limitation)
-- Must keep terminal open with proxy running
-- Requires your computer to be on and on same network
-
-**Setup:**
-```bash
-# Terminal 1: Start proxy
-cd agentic-writer-local-backend
-./start-proxy.sh
-
-# Keep this terminal open while using the plugin
-```
-
-### 🔗 Codex (OpenAI)
-
-**What it is:** Direct integration with OpenAI's API.
-
-**Why use it:**
-- ☁️ **Cloud reliability** - works from anywhere
-- 🎯 **High quality** - excellent for technical content
-- 📱 **Mobile friendly** - doesn't require your computer
-
-**How to enable:**
-1. Get OpenAI API key: https://platform.openai.com
-2. Go to **Settings → Agentic Writer → General**
-3. Add **Codex API Key** field (new field in settings)
-4. Set task provider to "Codex"
-
-**Cost:** Per OpenAI pricing (~$0.002-0.03 per 1K tokens)
-
-### ☁️ OpenRouter (Fallback)
-
-**What it is:** The original cloud provider (still works great!).
-
-**Primary use:**
-- 🖼️ **Image generation** (FLUX, Recraft, GPT-4o)
-- 🔄 **Automatic fallback** when Local Backend is offline
-
-**You already have this configured** - it's the original system.
-
----
-
-## Configuration Examples
-
-### Example 1: All Local (Maximum Savings)
-
-**Goal:** Pay $0 for all text generation
-
-**Settings:**
-```
-Provider Routing:
- Chat → Local Backend
- Clarity → Local Backend
- Planning → Local Backend
- Writing → Local Backend
- Refinement → Local Backend
- Image → OpenRouter
-```
-
-**Expected cost:** $0 for text, ~$0.05 per image
-
-### Example 2: Hybrid (Balanced)
-
-**Goal:** Free for most tasks, cloud for refinement
-
-**Settings:**
-```
-Provider Routing:
- Chat → Local Backend
- Clarity → Local Backend
- Planning → Local Backend
- Writing → Local Backend
- Refinement → Codex (cloud quality)
- Image → OpenRouter
-```
-
-**Expected cost:** ~$0.10-0.30 per article (refinement only)
-
-### Example 3: Cloud Production (No Local)
-
-**Goal:** Works from anywhere, no local setup
-
-**Settings:**
-```
-Provider Routing:
- All tasks → OpenRouter
-```
-
-**Expected cost:** ~$0.50-2.00 per article
-
----
-
-## Troubleshooting
-
-### ❌ "Connection failed" when testing
-
-**Symptoms:** Red error message in settings
-
-**Solutions:**
-
-1. **Is proxy running?**
- ```bash
- # Check if Node.js process is running
- ps aux | grep claude-proxy
-
- # If not, start it:
- ./start-proxy.sh
- ```
-
-2. **Wrong IP address?**
- ```bash
- # Find your correct local IP
- ./get-local-ip.sh
-
- # Or manually:
- # macOS: ifconfig | grep "inet "
- # Linux: ip addr show
- # Windows: ipconfig
- ```
-
-3. **Firewall blocking?**
- - **macOS:** System Preferences → Security → Firewall → Allow Node.js
- - **Linux:** `sudo ufw allow 8080`
- - **Windows:** Windows Defender → Allow app → Node.js
-
-### ❌ "Claude CLI not responding"
-
-**Symptoms:** Proxy starts but AI calls fail
-
-**Solutions:**
-
-1. **Test Claude CLI directly:**
- ```bash
- echo "Say hello" | claude
- ```
-
- If this fails, Claude CLI isn't configured properly.
-
-2. **Check Z.ai/Anthropic setup:**
- ```bash
- claude config get apiKey
- ```
-
- Should show your API key. If empty:
- ```bash
- claude config set apiKey YOUR_API_KEY
- ```
-
-3. **Re-authenticate:**
- ```bash
- claude auth login
- ```
-
-### ❌ "Proxy responded but with unexpected format"
-
-**Symptoms:** Ping works but inference fails
-
-**Solutions:**
-
-1. **Check proxy logs:**
- ```bash
- # In proxy folder
- cat proxy.log
- ```
-
-2. **Restart proxy:**
- ```bash
- ./stop-proxy.sh
- ./start-proxy.sh
- ```
-
-3. **Test manually:**
- ```bash
- ./test-connection.sh
- ```
-
-### ❌ Content generates but cost shows in dashboard
-
-**Symptoms:** Expecting $0 but seeing charges
-
-**Check:**
-1. Go to **Settings → Local Backend → Provider Routing**
-2. Verify tasks are set to "Local Backend" not "OpenRouter"
-3. Check that **Local Backend URL** is saved (not empty)
-4. Test connection - should show ✅
-
-**Fallback behavior:** If Local Backend is unreachable, plugin auto-switches to OpenRouter (and charges apply).
-
----
-
-## Advanced Tips
-
-### Tip 1: Running Proxy on a Different Machine
-
-You can run the proxy on a dedicated machine (e.g., home server) and connect WordPress from anywhere:
-
-**On server (192.168.1.50):**
-```bash
-./start-proxy.sh
-# Shows: http://192.168.1.50:8080
-```
-
-**In WordPress:**
-```
-Base URL: http://192.168.1.50:8080
-```
-
-**Requirements:**
-- Both on same network (or VPN)
-- Server has Claude CLI + Z.ai configured
-- Port 8080 open on server firewall
-
-### Tip 2: Using with Cloud-Hosted WordPress
-
-**The challenge:** Your WordPress is on a server, but proxy needs to be on your machine.
-
-**Solutions:**
-
-**Option A: VPN/Network Bridge**
-- Install Tailscale or similar on both machines
-- WordPress connects via Tailscale IP
-
-**Option B: SSH Tunnel**
-```bash
-# From your local machine
-ssh -R 8080:localhost:8080 user@wordpress-server
-```
-
-**Option C: Use Codex/OpenRouter**
-- Skip Local Backend for cloud WordPress
-- Use Codex or OpenRouter (cloud providers)
-
-### Tip 3: Auto-Start Proxy
-
-**macOS (LaunchAgent):**
-```xml
-
-
-
-
-
- Label
- com.agenticwriter.proxy
- ProgramArguments
-
- /path/to/agentic-writer-local-backend/start-proxy.sh
-
- RunAtLoad
-
- KeepAlive
-
-
-
-```
-
-**Linux (systemd):**
-```ini
-# ~/.config/systemd/user/claude-proxy.service
-[Unit]
-Description=Claude Proxy for WP Agentic Writer
-
-[Service]
-Type=simple
-WorkingDirectory=/path/to/agentic-writer-local-backend
-ExecStart=/path/to/agentic-writer-local-backend/start-proxy.sh
-Restart=always
-
-[Install]
-WantedBy=default.target
-```
-
-### Tip 4: Monitoring Proxy
-
-**Check if proxy is running:**
-```bash
-# Quick check
-curl http://192.168.1.105:8080/ping
-# Should return: pong
-```
-
-**Watch logs:**
-```bash
-# In proxy folder
-tail -f proxy.log
-```
-
-**Auto-restart if crashed:**
-```bash
-# Add to crontab
-*/5 * * * * /path/to/agentic-writer-local-backend/start-proxy.sh >/dev/null 2>&1
-```
-
----
-
-## Cost Comparison
-
-| Scenario | Monthly Usage | Old Cost (OpenRouter) | New Cost (Hybrid) | Savings |
-|----------|---------------|----------------------|---------------------|---------|
-| Light blogger | 10 articles | $5-10 | $0-2 | 80% |
-| Content agency | 100 articles | $50-100 | $5-10 | 90% |
-| Heavy user | 500 articles | $250-500 | $20-40 | 92% |
-| Image-heavy | 50 images | $2.50 | $2.50 | 0% |
-
-**Assumptions:**
-- Text tasks use Local Backend (free)
-- Images use OpenRouter ($0.05 each)
-- Occasional Codex refinement ($0.20 per article)
-
----
-
-## FAQ
-
-### Q: Is Local Backend really free?
-
-**A:** Yes! It uses your existing Claude CLI + Z.ai/Anthropic subscription. The proxy just connects WordPress to your local Claude. Your Z.ai subscription covers the usage.
-
-### Q: What if my computer is off?
-
-**A:** The plugin automatically falls back to OpenRouter. You'll see a notice: "Local Backend unavailable, using OpenRouter."
-
-### Q: Can multiple WordPress sites use one proxy?
-
-**A:** Yes! Just point all sites to the same `http://your-ip:8080`. Only one request processes at a time (Claude CLI limitation).
-
-### Q: Is my content private?
-
-**A:** With Local Backend, yes! Content goes:
-- WordPress → Your Computer → Claude CLI → Z.ai
-
-Never passes through our servers or third-party APIs (except Z.ai/Anthropic which you already use).
-
-### Q: Can I use Ollama instead of Claude CLI?
-
-**A:** Not currently. The proxy is designed for Claude CLI. Future versions may support Ollama.
-
-### Q: Why is streaming not working?
-
-**A:** Local Backend currently uses non-streaming (full response). This is a Claude CLI limitation. Codex and OpenRouter support streaming.
-
-### Q: How do I update the proxy?
-
-**A:** Download the latest ZIP from plugin settings and replace your proxy folder. Your configuration (Base URL in WordPress) stays the same.
-
----
-
-## Migration from Old System
-
-**If you were using OpenRouter only:**
-
-1. ✅ **Nothing breaks** - plugin defaults to OpenRouter
-2. ✅ **All settings preserved** - API key, models, etc.
-3. ➕ **New option** - add Local Backend anytime
-
-**To add Local Backend:**
-1. Follow **Quick Start** above
-2. No need to change existing content or settings
-3. Gradually switch tasks to Local Backend
-
----
-
-## Getting Help
-
-### Documentation
-- **This walkthrough** (you're reading it!)
-- **TROUBLESHOOTING.md** (in proxy package)
-- **README.md** (in proxy package)
-
-### Community
-- GitHub Issues: [plugin-repo]/issues
-- Discord: [community-link]
-
-### Debug Info
-When reporting issues, include:
-```
-1. Proxy version: cat package.json | grep version
-2. Claude version: claude --version
-3. Node version: node --version
-4. Connection test result: ./test-connection.sh
-5. WordPress version
-6. Plugin version
-```
-
----
-
-## Next Steps
-
-1. ✅ [Download Local Backend](#step-2-download--start-local-backend)
-2. ✅ [Configure Plugin](#step-3-configure-plugin)
-3. ✅ [Test Generation](#step-5-generate-content)
-4. 📖 [Read Troubleshooting](#troubleshooting) if needed
-5. 🚀 Enjoy unlimited free AI generation!
-
----
-
-*Last updated: 2026-02-27*
-*Plugin version: 0.3.0*
-*Proxy version: 1.0.0*
diff --git a/HYBRID_REFINEMENT_IMPLEMENTATION.md b/HYBRID_REFINEMENT_IMPLEMENTATION.md
deleted file mode 100644
index fc1f511..0000000
--- a/HYBRID_REFINEMENT_IMPLEMENTATION.md
+++ /dev/null
@@ -1,249 +0,0 @@
-# Hybrid Block Refinement - Implementation Complete
-
-## Summary
-
-Successfully implemented a hybrid block refinement system that combines:
-1. **Current workflow**: "AI Refine" button in block toolbar (preserved)
-2. **New workflow**: `@block` mentions in chat (new feature)
-
----
-
-## What Was Implemented
-
-### 1. Backend Changes (includes/class-gutenberg-sidebar.php)
-
-**New REST Endpoint:**
-- `/wp-agentic-writer/v1/refine-from-chat` - Handles chat-based refinement requests
-- Location: Lines 273-282
-
-**New Methods:**
-
-1. **`handle_refine_from_chat()`** (Lines 2009-2026)
- - Validates request and extracts blocks to refine
- - Calls streaming handler
-
-2. **`stream_refinement_from_chat()`** (Lines 2038-2202)
- - Streams refinement responses for multiple blocks
- - Handles cost tracking
- - Supports multi-block refinement in sequence
-
-3. **Helper Methods:**
- - `find_block_by_client_id()` - Locates blocks in parsed content
- - `find_block_index()` - Gets block index for context
- - `extract_block_content()` - Extracts text from block
- - `extract_heading_from_block()` - Gets heading for context
- - `clean_refined_content()` - Removes conversational text
- - `create_block_structure()` - Creates proper Gutenberg block structure
-
----
-
-### 2. Frontend Changes (assets/js/sidebar.js)
-
-**New Functions:**
-
-1. **`resolveBlockMentions()`** (Lines 107-170)
- - Resolves mention syntax to block client IDs
- - Supports: `@this`, `@previous`, `@next`, `@all`, `@paragraph-N`, `@heading-N`, `@list-N`
- - Removes duplicates
-
-2. **`handleChatRefinement()`** (Lines 173-350)
- - Parses mentions from user message
- - Calls backend `/refine-from-chat` endpoint
- - Handles streaming responses
- - Replaces blocks in editor in real-time
- - Updates chat with progress timeline
- - Tracks costs
-
-3. **Modified `sendMessage()`** (Lines 352-368)
- - Detects refinement requests with `@` mentions
- - Checks for keywords: refine, rewrite, edit, improve, change, make
- - Routes to `handleChatRefinement()` or normal article generation
-
----
-
-### 3. Visual Feedback (assets/css/sidebar.css)
-
-**New Styles (Lines 543-601):**
-
-1. **`.wpaw-block-mentioned`** - Blue outline with pulse animation
-2. **`@keyframes wpaw-pulse`** - Pulsing animation effect
-3. **`.wpaw-mention-autocomplete`** - Dropdown styles for future autocomplete UI
-4. **`.wpaw-mention-option`** - Individual mention option styles
-
----
-
-## Supported Mention Syntax
-
-| Syntax | Description | Example |
-|--------|-------------|---------|
-| `@this` | Current selected block | "Refine @this to be more engaging" |
-| `@previous` | Block before current | "Refine @previous to match tone" |
-| `@next` | Block after current | "Refine @next for consistency" |
-| `@all` | All content blocks | "Refine @all to be more concise" |
-| `@paragraph-1` | 1st paragraph | "Refine @paragraph-1 to be more exciting" |
-| `@heading-2` | 2nd heading | "Refine @heading-2 to be more descriptive" |
-| `@list-1` | 1st list | "Refine @list-1 to add more items" |
-
-**Note:** Block numbers are 1-based (more intuitive for users)
-
----
-
-## Usage Examples
-
-### Single Block Refinement
-```
-User: Refine @this to be more concise
-```
-→ Refines currently selected block
-
-### Multi-Block Refinement
-```
-User: Refine @paragraph-1 and @paragraph-2 to be more engaging
-```
-→ Refines both paragraphs sequentially
-
-### Relative Block Refinement
-```
-User: Refine @previous to match the tone of @this
-```
-→ Refines the block before the current selection
-
-### All Content Blocks
-```
-User: Refine @all to use simpler language
-```
-→ Refines all paragraphs, headings, and lists
-
----
-
-## Features
-
-✅ **Hybrid approach** - Toolbar button preserved, chat mentions added
-✅ **Multi-block refinement** - Refine multiple blocks in one request
-✅ **Streaming responses** - Real-time block updates
-✅ **Timeline progress** - Visual feedback in chat
-✅ **Cost tracking** - Integrated with existing cost system
-✅ **Error handling** - Graceful error messages
-✅ **Context awareness** - Uses previous/next block context
-✅ **Conversational filtering** - Removes "Certainly! Here's..." text
-
----
-
-## Technical Details
-
-### Block Resolution Logic
-- Resolves mentions using WordPress `select('core/block-editor').getBlocks()`
-- Handles nested blocks (innerBlocks for lists)
-- Filters by block type (paragraph, heading, list)
-- Removes duplicates with `Set`
-
-### Stream Processing
-- Uses Server-Sent Events (SSE) for streaming
-- JSON format: `data: {type: 'block'|'complete'|'error', ...}`
-- Replaces blocks using `wp.blocks.createBlock()` and `replaceBlocks()`
-
-### Cost Tracking
-- Accumulates costs for all blocks refined
-- Uses existing `wp_aw_after_api_request` action
-- Updates session cost in sidebar
-
----
-
-## Testing Checklist
-
-### Basic Functionality:
-- [ ] `@this` refines selected block
-- [ ] `@previous` refines previous block
-- [ ] `@next` refines next block
-- [ ] `@all` refines all content blocks
-- [ ] `@paragraph-1` refines 1st paragraph
-- [ ] `@heading-2` refines 2nd heading
-- [ ] `@list-1` refines 1st list
-
-### Multi-Block:
-- [ ] Multiple mentions in one message work
-- [ ] Duplicate mentions only refine once
-- [ ] Invalid mentions show error message
-
-### Chat Integration:
-- [ ] Timeline shows progress
-- [ ] Completion message appears
-- [ ] Cost is updated
-- [ ] Errors are handled gracefully
-
-### Toolbar Button:
-- [ ] Original toolbar button still works
-- [ ] Modal opens and closes correctly
-- [ ] Textarea is responsive
-
----
-
-## Files Modified
-
-1. **includes/class-gutenberg-sidebar.php** (+380 lines)
- - Added REST endpoint
- - Added 7 new methods
- - Helper functions for block resolution
-
-2. **assets/js/sidebar.js** (+265 lines)
- - Added mention resolution logic
- - Added chat refinement handler
- - Modified sendMessage() to detect refinement
-
-3. **assets/css/sidebar.css** (+62 lines)
- - Added block mention styles
- - Added pulse animation
- - Added autocomplete dropdown styles
-
----
-
-## Backward Compatibility
-
-✅ **No breaking changes**
-- Toolbar button workflow preserved
-- Existing `/refine-block` endpoint unchanged
-- All existing functionality works as before
-
----
-
-## Future Enhancements (Not Implemented)
-
-### Phase 2 Ideas:
-- **Mention autocomplete** - Show available blocks when typing `@`
-- **Visual highlighting** - Highlight mentioned blocks in editor
-- **Smart suggestions** - "Refine all headings to be more descriptive"
-- **Batch operations** - "Refine all lists to be more concise"
-- **Refinement history** - Undo/redo refinement changes
-
-### Advanced Features:
-- **Content-based references** - "Refine the block about SEO"
-- **Natural language counts** - "Refine the third paragraph"
-- **Style transfer** - "Make @paragraph-1 match the tone of @heading-2"
-- **Refinement templates** - Predefined refinement options
-
----
-
-## Success Metrics
-
-✅ All mention syntaxes work correctly
-✅ Multi-block refinement functional
-✅ Chat integration complete
-✅ Cost tracking working
-✅ No regression in existing features
-✅ Error handling robust
-✅ Code follows WordPress/Gutenberg patterns
-
----
-
-## Notes
-
-- Block numbers are **1-based** (e.g., `@paragraph-1` is the first paragraph)
-- Mention detection is case-insensitive
-- Refinement keywords: refine, rewrite, edit, improve, change, make
-- Both `@this` and `@THIS` work the same
-- Empty mentions or invalid references show helpful error messages
-
----
-
-**Implementation Date:** 2026-01-18
-**Status:** ✅ Complete and ready for testing
diff --git a/IMAGE_GENERATION_IMPLEMENTATION_PLAN.md b/IMAGE_GENERATION_IMPLEMENTATION_PLAN.md
deleted file mode 100644
index 3d2048a..0000000
--- a/IMAGE_GENERATION_IMPLEMENTATION_PLAN.md
+++ /dev/null
@@ -1,1389 +0,0 @@
-# WP Agentic Writer: Image Generation Implementation Plan
-
-**Document Version:** 1.1
-**Date:** January 28, 2026
-**Status:** Ready for Implementation
-**Estimated Time:** 16-20 hours
-
-**Changelog v1.1:**
-- Updated table names to use `wp_wpaw_` prefix (consistent with existing tables)
-- Changed temp folder location to `/wp-content/uploads/wpaw/{post_id}/`
-- Added user-controlled variant count setting (1-3 variants per image)
-
----
-
-## Executive Summary
-
-This document provides a comprehensive implementation plan for adding AI-powered image generation to WP Agentic Writer. The implementation follows **Option A (Cost-Optimized with User Control)** from the recommendations, ensuring maximum cost efficiency and quality control.
-
-### Key Features
-- ✅ **Cost-optimized flow:** Analysis + prompts cost ~$0.002, user controls image generation
-- ✅ **Model-specific prompts:** Tailored for FLUX.2 klein (Budget), Riverflow V2 Max (Balanced), FLUX.2 max (Premium)
-- ✅ **Variant management:** User controls variant count (1-3), selects best one
-- ✅ **WordPress integration:** Direct upload to Media Library with alt text
-- ✅ **Temp file management:** Automatic cleanup of unused variants
-
----
-
-## Table of Contents
-
-1. [Current State Analysis](#current-state-analysis)
-2. [Architecture Overview](#architecture-overview)
-3. [Database Schema](#database-schema)
-4. [Implementation Phases](#implementation-phases)
-5. [Phase 1: Database & Core Infrastructure](#phase-1-database--core-infrastructure)
-6. [Phase 2: Backend Image Generation](#phase-2-backend-image-generation)
-7. [Phase 3: Frontend UI & Modal](#phase-3-frontend-ui--modal)
-8. [Phase 4: Gutenberg Integration](#phase-4-gutenberg-integration)
-9. [Phase 5: Temp File Management](#phase-5-temp-file-management)
-10. [Phase 6: Testing & Polish](#phase-6-testing--polish)
-11. [Configuration & Settings](#configuration--settings)
-12. [Cost Tracking Integration](#cost-tracking-integration)
-13. [Security Considerations](#security-considerations)
-14. [Rollout Strategy](#rollout-strategy)
-
----
-
-## Current State Analysis
-
-### ✅ What We Have
-
-1. **Image Model Configuration**
- - Settings page has image model selector
- - Default: `openai/gpt-4o`
- - Preset support: Budget/Balanced/Premium all use GPT-4o
- - Model stored in `wp_agentic_writer_settings['image_model']`
-
-2. **Image Placeholder Support**
- - Writing agent can suggest images using `[IMAGE: description]` format
- - Markdown parser converts `[IMAGE: ...]` to `core/image` blocks
- - Post config has `include_images` boolean flag
-
-3. **OpenRouter Provider**
- - Has `generate_image()` method (basic implementation)
- - Uses chat completion for images (not optimal)
- - No variant support, no temp file management
-
-4. **Cost Tracking**
- - Existing table: `wp_wpaw_cost_tracking`
- - Tracks model, action, tokens, cost per request
- - Can be extended for image generation costs
-
-### ❌ What We Need
-
-1. **Database Tables**
- - `wp_wpaw_images` - Image recommendations and metadata
- - `wp_wpaw_images_variants` - Generated image variants
-
-2. **Image Generation Flow**
- - Analyze article for placement
- - Generate model-specific prompts
- - Generate image variants via OpenRouter
- - Download and store temp files
- - Upload selected variant to WordPress Media
-
-3. **Frontend UI**
- - Image review modal after article generation
- - Variant selection interface
- - Gutenberg block toolbar integration
- - Progress indicators
-
-4. **File Management**
- - Temp directory: `/wp-content/uploads/wpaw/{post_id}/`
- - Automatic cleanup (7+ days)
- - Cron job for maintenance
-
-5. **User Controls**
- - Variant count selector (1-3 variants per image)
- - Cost preview before generation
- - Per-image generation control
-
-6. **Model-Specific Prompting**
- - FLUX.2 klein: Simple 1-2 sentence prompts
- - Riverflow V2 Max: Detailed 3-4 sentence prompts
- - FLUX.2 max: Complex 4-6 sentence prompts
-
----
-
-## Architecture Overview
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ ARTICLE GENERATION COMPLETE │
-│ (Writing agent finishes, returns markdown with [IMAGE: ...])│
-└────────────────┬────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────┐
-│ AUTOMATIC: Analyze & Generate Prompts │
-│ • analyze_article_for_images() → placement points │
-│ • generate_image_prompts() → 3 image specs │
-│ • Store in wp_wpaw_images table │
-│ Cost: ~$0.002 (uses writing model) │
-└────────────────┬────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────┐
-│ FRONTEND: Image Review Modal │
-│ • Show 3 image recommendations │
-│ • Display prompts (editable) │
-│ • Display alt text (editable) │
-│ • Variant count selector (1-3 per image) │
-│ • Show cost estimate per image × variant count │
-│ • [Generate All] [Generate Selected] [Skip] │
-└────────────────┬────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────┐
-│ USER SELECTS: Generate Image(s) │
-│ • Choose variant count (1-3) per image │
-│ • Click [Generate] on individual image │
-│ • OR click [Generate All] │
-└────────────────┬────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────┐
-│ BACKEND: Generate Variants │
-│ • Call OpenRouter image generation API │
-│ • Generate N variants (user-specified: 1-3) │
-│ • Download to /wp-content/uploads/wpaw/{post_id}/ │
-│ • Store in wp_wpaw_images_variants table │
-│ • Return variant URLs to frontend │
-└────────────────┬────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────┐
-│ FRONTEND: Variant Selection Modal │
-│ • Display all variants in grid │
-│ • Show generation info (cost, time, model) │
-│ • [Select] button per variant │
-│ • [Regenerate] for more variants │
-└────────────────┬────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────┐
-│ BACKEND: Commit to WordPress Media │
-│ • media_handle_sideload() - upload to Media Library │
-│ • Set alt text from recommendation │
-│ • Update wp_wpaw_images: status='committed' │
-│ • Return attachment ID + URL │
-└────────────────┬────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────┐
-│ FRONTEND: Update Gutenberg Block │
-│ • updateBlockAttributes() with attachment ID/URL │
-│ • Remove data-agent-image-id placeholder marker │
-│ • Image now permanent in WordPress │
-└─────────────────────────────────────────────────────────────┘
-```
-
----
-
-## Database Schema
-
-### Table 1: `wp_wpaw_images`
-
-Stores image recommendations from the writing agent.
-
-```sql
-CREATE TABLE IF NOT EXISTS `wp_wpaw_images` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
- `post_id` bigint(20) NOT NULL,
-
- -- Recommendation from agent
- `agent_image_id` varchar(50) NOT NULL, -- e.g., "img_hero_1"
- `placement` varchar(100) DEFAULT NULL, -- "intro_hero", "after_section_2"
- `section_title` varchar(255) DEFAULT NULL, -- "Introduction to n8n"
-
- -- Original recommendation
- `prompt_initial` text NOT NULL, -- Agent's initial prompt
- `alt_text_initial` text DEFAULT NULL, -- Agent's suggested alt
-
- -- User edits (nullable)
- `prompt_edited` text DEFAULT NULL, -- NULL if user didn't edit
- `alt_text_edited` text DEFAULT NULL, -- NULL if user didn't edit
-
- -- Committed image (when user selects a variant)
- `attachment_id` bigint(20) DEFAULT NULL, -- WP attachment ID (null until committed)
- `status` varchar(30) DEFAULT 'pending', -- pending, generating, committed, discarded
-
- -- Cost tracking
- `cost_estimate` decimal(10, 4) DEFAULT NULL, -- Based on image model pricing
- `cost_actual` decimal(10, 4) DEFAULT NULL, -- Updated after generation
- `image_model` varchar(100) DEFAULT NULL, -- Which model was used
-
- -- Metadata
- `created_at` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
-
- PRIMARY KEY (`id`),
- KEY `idx_post` (`post_id`),
- KEY `idx_agent_image_id` (`post_id`, `agent_image_id`),
- KEY `idx_status` (`status`),
- KEY `idx_created` (`created_at`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-```
-
-### Table 2: `wp_wpaw_images_variants`
-
-Tracks all generated variants (temp images) for each agent_image_id.
-
-```sql
-CREATE TABLE IF NOT EXISTS `wp_wpaw_images_variants` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
-
- -- Reference to main image record
- `agentic_image_id` bigint(20) NOT NULL,
- `post_id` bigint(20) NOT NULL,
- `agent_image_id` varchar(50) NOT NULL, -- e.g., "img_hero_1"
-
- -- Variant details
- `variant_number` int(11) DEFAULT 1, -- 1st, 2nd, 3rd generation attempt
- `temp_file_path` varchar(500) NOT NULL, -- /wp-content/uploads/wpaw/{post_id}/xxx.jpg
- `temp_file_url` varchar(500) NOT NULL, -- URL to temp image
- `file_size` int(11) DEFAULT NULL, -- In bytes
-
- -- Generation details
- `prompt_used` text DEFAULT NULL, -- Exact prompt sent to image model
- `image_model_used` varchar(100) DEFAULT NULL, -- Which model generated this
- `generation_time` int(11) DEFAULT NULL, -- Seconds to generate
- `cost` decimal(10, 4) DEFAULT NULL, -- Cost of this generation
-
- -- Selection status
- `is_selected` tinyint(1) DEFAULT 0, -- 1 if user selected this variant
- `selected_at` datetime DEFAULT NULL,
-
- -- Lifecycle
- `status` varchar(30) DEFAULT 'temp', -- temp, selected, discarded, auto_deleted
- `created_at` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- `deleted_at` datetime DEFAULT NULL,
-
- PRIMARY KEY (`id`),
- KEY `idx_agentic_image` (`agentic_image_id`),
- KEY `idx_post` (`post_id`),
- KEY `idx_status` (`status`),
- KEY `idx_created` (`created_at`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-```
-
----
-
-## Implementation Phases
-
-### Phase 1: Database & Core Infrastructure (2-3 hours)
-- Create database tables
-- Create temp directory structure
-- Add activation/deactivation hooks
-
-### Phase 2: Backend Image Generation (4-5 hours)
-- Implement image analysis
-- Implement prompt generation (model-specific)
-- Implement OpenRouter image generation
-- Implement variant management
-- Implement Media Library upload
-
-### Phase 3: Frontend UI & Modal (4-5 hours)
-- Image review modal
-- Variant selection interface
-- Progress indicators
-- Error handling
-
-### Phase 4: Gutenberg Integration (2-3 hours)
-- Block toolbar button
-- Block attribute updates
-- Placeholder management
-
-### Phase 5: Temp File Management (2 hours)
-- Cleanup cron job
-- Admin page for temp images
-- Manual cleanup interface
-
-### Phase 6: Testing & Polish (2-3 hours)
-- End-to-end testing
-- Error scenarios
-- Performance optimization
-- Documentation
-
-**Total Estimated Time:** 16-21 hours
-
----
-
-## Phase 1: Database & Core Infrastructure
-
-### 1.1 Create Database Tables
-
-**File:** `includes/class-image-manager.php` (NEW)
-
-```php
-get_charset_collate();
-
- // Table 1: wp_wpaw_images
- $table_images = $wpdb->prefix . 'wpaw_images';
- $sql_images = "CREATE TABLE IF NOT EXISTS `{$table_images}` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
- `post_id` bigint(20) NOT NULL,
- `agent_image_id` varchar(50) NOT NULL,
- `placement` varchar(100) DEFAULT NULL,
- `section_title` varchar(255) DEFAULT NULL,
- `prompt_initial` text NOT NULL,
- `alt_text_initial` text DEFAULT NULL,
- `prompt_edited` text DEFAULT NULL,
- `alt_text_edited` text DEFAULT NULL,
- `attachment_id` bigint(20) DEFAULT NULL,
- `status` varchar(30) DEFAULT 'pending',
- `cost_estimate` decimal(10, 4) DEFAULT NULL,
- `cost_actual` decimal(10, 4) DEFAULT NULL,
- `image_model` varchar(100) DEFAULT NULL,
- `created_at` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
- PRIMARY KEY (`id`),
- KEY `idx_post` (`post_id`),
- KEY `idx_agent_image_id` (`post_id`, `agent_image_id`),
- KEY `idx_status` (`status`),
- KEY `idx_created` (`created_at`)
- ) {$charset_collate};";
-
- // Table 2: wp_wpaw_images_variants
- $table_variants = $wpdb->prefix . 'wpaw_images_variants';
- $sql_variants = "CREATE TABLE IF NOT EXISTS `{$table_variants}` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
- `agentic_image_id` bigint(20) NOT NULL,
- `post_id` bigint(20) NOT NULL,
- `agent_image_id` varchar(50) NOT NULL,
- `variant_number` int(11) DEFAULT 1,
- `temp_file_path` varchar(500) NOT NULL,
- `temp_file_url` varchar(500) NOT NULL,
- `file_size` int(11) DEFAULT NULL,
- `prompt_used` text DEFAULT NULL,
- `image_model_used` varchar(100) DEFAULT NULL,
- `generation_time` int(11) DEFAULT NULL,
- `cost` decimal(10, 4) DEFAULT NULL,
- `is_selected` tinyint(1) DEFAULT 0,
- `selected_at` datetime DEFAULT NULL,
- `status` varchar(30) DEFAULT 'temp',
- `created_at` datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- `deleted_at` datetime DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `idx_agentic_image` (`agentic_image_id`),
- KEY `idx_post` (`post_id`),
- KEY `idx_status` (`status`),
- KEY `idx_created` (`created_at`)
- ) {$charset_collate};";
-
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
- dbDelta( $sql_images );
- dbDelta( $sql_variants );
-
- // Create temp directory
- $this->create_temp_directory();
- }
-
- /**
- * Create temp directory for image storage.
- */
- private function create_temp_directory() {
- $upload_dir = wp_upload_dir();
- $temp_dir = $upload_dir['basedir'] . '/wpaw';
-
- if ( ! file_exists( $temp_dir ) ) {
- wp_mkdir_p( $temp_dir );
-
- // Add .htaccess to prevent direct access
- $htaccess = $temp_dir . '/.htaccess';
- if ( ! file_exists( $htaccess ) ) {
- file_put_contents( $htaccess, "Options -Indexes\n" );
- }
-
- // Add index.php for security
- $index = $temp_dir . '/index.php';
- if ( ! file_exists( $index ) ) {
- file_put_contents( $index, "create_tables();
-}
-register_activation_hook( __FILE__, 'wp_agentic_writer_activate' );
-```
-
-### 1.3 Update Autoloader
-
-**File:** `includes/class-autoloader.php`
-
-```php
-// Add to class map
-'WP_Agentic_Writer_Image_Manager' => 'class-image-manager.php',
-```
-
----
-
-## Phase 2: Backend Image Generation
-
-### 2.1 Analyze Article for Image Placement
-
-**File:** `includes/class-image-manager.php` (add methods)
-
-```php
-/**
- * Analyze article for optimal image placement.
- *
- * @param string $article_markdown Article content in markdown.
- * @param int $post_id Post ID.
- * @return array|WP_Error Placement data or error.
- */
-public function analyze_article_for_images( $article_markdown, $post_id ) {
- $settings = get_option( 'wp_agentic_writer_settings', array() );
- $writing_model = $settings['writing_model'] ?? 'anthropic/claude-3.5-sonnet';
-
- $system_prompt = "You are an expert content strategist analyzing articles for optimal image placement.
-
-Your task: Identify 2-3 strategic locations where images would enhance understanding and engagement.
-
-RULES:
-1. Prioritize placement after introduction (hero image)
-2. Consider complex sections that need visual aids
-3. Look for opportunities before conclusions
-4. Maximum 3 images per article
-
-Return JSON:
-{
- \"recommended_image_count\": 3,
- \"image_placement_points\": [
- {
- \"agent_image_id\": \"img_hero_1\",
- \"placement\": \"after_introduction\",
- \"section_title\": \"Introduction\",
- \"image_type\": \"hero_dashboard\",
- \"reasoning\": \"Sets visual tone for article\"
- }
- ]
-}";
-
- $messages = array(
- array(
- 'role' => 'user',
- 'content' => "Analyze this article for image placement:\n\n" . $article_markdown,
- ),
- );
-
- $provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
- $response = $provider->chat( $messages, array( 'temperature' => 0.3 ), 'planning' );
-
- if ( is_wp_error( $response ) ) {
- return $response;
- }
-
- // Extract JSON from response
- $json_match = array();
- if ( preg_match( '/\{[\s\S]*\}/m', $response['content'], $json_match ) ) {
- $placement_data = json_decode( $json_match[0], true );
- if ( json_last_error() === JSON_ERROR_NONE ) {
- return $placement_data;
- }
- }
-
- return new WP_Error( 'parse_error', 'Failed to parse placement analysis' );
-}
-```
-
-### 2.2 Generate Model-Specific Prompts
-
-```php
-/**
- * Generate image prompts optimized for specific image model.
- *
- * @param string $article_markdown Article content.
- * @param array $placement_data Placement analysis.
- * @param int $post_id Post ID.
- * @return array|WP_Error Image specifications or error.
- */
-public function generate_image_prompts( $article_markdown, $placement_data, $post_id ) {
- $settings = get_option( 'wp_agentic_writer_settings', array() );
- $writing_model = $settings['writing_model'] ?? 'anthropic/claude-3.5-sonnet';
- $image_model = $settings['image_model'] ?? 'openai/gpt-4o';
-
- // Get model-specific prompt guidance
- $prompt_guidance = $this->get_prompt_guidance_for_model( $image_model );
-
- $system_prompt = "You are an Image Prompt Engineer specializing in {$prompt_guidance['model_name']}.
-
-TARGET MODEL: {$prompt_guidance['model_name']}
-PROMPT LENGTH: {$prompt_guidance['prompt_length']}
-COMPLEXITY: {$prompt_guidance['complexity']}
-
-{$prompt_guidance['guidance']}
-
-TEMPLATE: {$prompt_guidance['template']}
-
-Generate precise, cost-efficient prompts that exploit this model's strengths.
-
-Return JSON:
-{
- \"images\": [
- {
- \"agent_image_id\": \"img_hero_1\",
- \"placement\": \"after_introduction\",
- \"section_title\": \"Introduction\",
- \"prompt\": \"[Model-optimized prompt]\",
- \"alt\": \"Descriptive alt text\",
- \"image_model\": \"{$image_model}\"
- }
- ]
-}";
-
- $user_input = json_encode( array(
- 'article' => $article_markdown,
- 'placement_points' => $placement_data['image_placement_points'],
- 'image_count' => $placement_data['recommended_image_count'],
- 'target_image_model' => $image_model,
- ) );
-
- $messages = array(
- array(
- 'role' => 'user',
- 'content' => "Generate image prompts:\n\n" . $user_input,
- ),
- );
-
- $provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
- $response = $provider->chat( $messages, array( 'temperature' => 0.7 ), 'planning' );
-
- if ( is_wp_error( $response ) ) {
- return $response;
- }
-
- // Extract JSON
- $json_match = array();
- if ( preg_match( '/\{[\s\S]*\}/m', $response['content'], $json_match ) ) {
- $image_specs = json_decode( $json_match[0], true );
- if ( json_last_error() === JSON_ERROR_NONE ) {
- // Save to database
- $this->save_image_recommendations( $post_id, $image_specs['images'] );
- return $image_specs;
- }
- }
-
- return new WP_Error( 'parse_error', 'Failed to parse image prompts' );
-}
-
-/**
- * Get prompt guidance for specific image model.
- */
-private function get_prompt_guidance_for_model( $image_model ) {
- $model_configs = array(
- 'black-forest-labs/flux.2-klein' => array(
- 'model_name' => 'FLUX.2 [klein]',
- 'prompt_length' => '1-2 sentences',
- 'complexity' => 'simple',
- 'guidance' => 'Keep prompts short and simple. Focus on main subject, key details, and style. Avoid complex scenes or technical specifications.',
- 'template' => 'Subject, key elements, style, color palette',
- ),
- 'sourceful/riverflow-v2-max' => array(
- 'model_name' => 'Riverflow V2 Max',
- 'prompt_length' => '3-4 sentences',
- 'complexity' => 'medium-detailed',
- 'guidance' => 'Include context, environment details, lighting style, and photographic specifications. Model excels at photorealism.',
- 'template' => 'Subject + context, environment details, lighting style, photography style, technical specs',
- ),
- 'black-forest-labs/flux.2-max' => array(
- 'model_name' => 'FLUX.2 [max]',
- 'prompt_length' => '4-6 sentences',
- 'complexity' => 'very-detailed-technical',
- 'guidance' => 'Use detailed technical vocabulary. Include exact materials, color codes (HEX), spatial relationships, and specifications.',
- 'template' => 'Technical foundation, main subject + action, environment, lighting + mood, style + aesthetics, technical specifications',
- ),
- );
-
- // Default to Riverflow if model not found
- return $model_configs[ $image_model ] ?? $model_configs['sourceful/riverflow-v2-max'];
-}
-
-/**
- * Save image recommendations to database.
- */
-private function save_image_recommendations( $post_id, $images ) {
- global $wpdb;
- $table = $wpdb->prefix . 'wpaw_images';
-
- foreach ( $images as $image_spec ) {
- $wpdb->insert(
- $table,
- array(
- 'post_id' => $post_id,
- 'agent_image_id' => $image_spec['agent_image_id'],
- 'placement' => $image_spec['placement'],
- 'section_title' => $image_spec['section_title'],
- 'prompt_initial' => $image_spec['prompt'],
- 'alt_text_initial' => $image_spec['alt'],
- 'image_model' => $image_spec['image_model'],
- 'status' => 'pending',
- ),
- array( '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )
- );
- }
-}
-```
-
-### 2.3 Generate Image via OpenRouter
-
-**File:** `includes/class-openrouter-provider.php` (update existing method)
-
-```php
-/**
- * Generate image using OpenRouter image generation API.
- *
- * @param string $prompt Image prompt.
- * @param string $model Image model (optional, uses default if not provided).
- * @param array $options Additional options (size, quality, etc).
- * @return array|WP_Error Response with image URL or error.
- */
-public function generate_image( $prompt, $model = null, $options = array() ) {
- if ( empty( $this->api_key ) ) {
- return new WP_Error( 'no_api_key', 'OpenRouter API key not configured' );
- }
-
- $model = $model ?? $this->image_model;
- $size = $options['size'] ?? '1024x576'; // Default blog size
- $quality = $options['quality'] ?? 'hd';
- $n = $options['n'] ?? 1; // Number of variants
-
- $start_time = microtime( true );
-
- $response = wp_remote_post(
- 'https://openrouter.ai/api/v1/images/generations',
- array(
- 'headers' => array(
- 'Authorization' => 'Bearer ' . $this->api_key,
- 'Content-Type' => 'application/json',
- 'HTTP-Referer' => home_url(),
- 'X-Title' => get_bloginfo( 'name' ),
- ),
- 'body' => wp_json_encode( array(
- 'model' => $model,
- 'prompt' => $prompt,
- 'n' => $n,
- 'size' => $size,
- 'quality' => $quality,
- ) ),
- 'timeout' => 60,
- )
- );
-
- $generation_time = microtime( true ) - $start_time;
-
- if ( is_wp_error( $response ) ) {
- return $response;
- }
-
- $body = json_decode( wp_remote_retrieve_body( $response ), true );
-
- if ( ! isset( $body['data'][0]['url'] ) ) {
- return new WP_Error(
- 'image_generation_failed',
- $body['error']['message'] ?? 'Unknown error'
- );
- }
-
- return array(
- 'url' => $body['data'][0]['url'],
- 'cost' => $body['usage']['cost'] ?? 0.03, // Fallback estimate
- 'generation_time' => $generation_time,
- 'model' => $model,
- );
-}
-```
-
-### 2.4 REST API Endpoints
-
-**File:** `includes/class-gutenberg-sidebar.php` (add to `register_routes()`)
-
-```php
-// Image generation endpoints
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/analyze-images',
- array(
- 'methods' => 'POST',
- 'callback' => array( $this, 'handle_analyze_images' ),
- 'permission_callback' => array( $this, 'check_permissions' ),
- )
-);
-
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/generate-image',
- array(
- 'methods' => 'POST',
- 'callback' => array( $this, 'handle_generate_image' ),
- 'permission_callback' => array( $this, 'check_permissions' ),
- )
-);
-
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/commit-image',
- array(
- 'methods' => 'POST',
- 'callback' => array( $this, 'handle_commit_image' ),
- 'permission_callback' => array( $this, 'check_permissions' ),
- )
-);
-
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/image-recommendations/(?P\d+)',
- array(
- 'methods' => 'GET',
- 'callback' => array( $this, 'handle_get_image_recommendations' ),
- 'permission_callback' => array( $this, 'check_permissions' ),
- )
-);
-```
-
----
-
-## Phase 3: Frontend UI & Modal
-
-### 3.1 Image Review Modal Component
-
-**File:** `assets/js/image-modal.js` (NEW)
-
-```javascript
-/**
- * Image Generation Modal Component
- *
- * Handles image review, generation, variant selection, and commitment.
- */
-
-(function() {
- const { Modal, Button, Spinner, TextControl, TextareaControl } = wp.components;
- const { useState, useEffect } = wp.element;
-
- window.wpAgenticWriter = window.wpAgenticWriter || {};
-
- /**
- * Image Review Modal
- * Shows after article generation with image recommendations
- */
- window.wpAgenticWriter.ImageReviewModal = function({ postId, onClose, onComplete }) {
- const [step, setStep] = useState('loading'); // loading, review, generating, selecting
- const [images, setImages] = useState([]);
- const [selectedImages, setSelectedImages] = useState([]);
- const [variantCounts, setVariantCounts] = useState({}); // Track variant count per image
- const [isGenerating, setIsGenerating] = useState(false);
- const [error, setError] = useState(null);
-
- // Load image recommendations
- useEffect(() => {
- loadImageRecommendations();
- }, []);
-
- const loadImageRecommendations = async () => {
- try {
- const response = await fetch(
- `${wpAgenticWriter.apiUrl}/image-recommendations/${postId}`,
- {
- headers: {
- 'X-WP-Nonce': wpAgenticWriter.nonce,
- },
- }
- );
-
- if (!response.ok) {
- throw new Error('Failed to load image recommendations');
- }
-
- const data = await response.json();
- const imgs = data.images || [];
- setImages(imgs);
-
- // Initialize variant counts to 2 for each image
- const initialCounts = {};
- imgs.forEach(img => {
- initialCounts[img.agent_image_id] = 2; // Default: 2 variants
- });
- setVariantCounts(initialCounts);
-
- setStep('review');
- } catch (err) {
- setError(err.message);
- setStep('review');
- }
- };
-
- const handleEditPrompt = (imageId, newPrompt) => {
- setImages(prev => prev.map(img =>
- img.agent_image_id === imageId
- ? { ...img, prompt_edited: newPrompt }
- : img
- ));
- };
-
- const handleEditAlt = (imageId, newAlt) => {
- setImages(prev => prev.map(img =>
- img.agent_image_id === imageId
- ? { ...img, alt_text_edited: newAlt }
- : img
- ));
- };
-
- const handleVariantCountChange = (imageId, count) => {
- setVariantCounts(prev => ({
- ...prev,
- [imageId]: parseInt(count, 10)
- }));
- };
-
- const calculateTotalCost = () => {
- const settings = wpAgenticWriter.settings || {};
- const imageModel = settings.image_model || 'sourceful/riverflow-v2-max';
-
- // Cost per image by model (estimates)
- const costPerImage = {
- 'black-forest-labs/flux.2-klein': 0.02,
- 'sourceful/riverflow-v2-max': 0.03,
- 'black-forest-labs/flux.2-max': 0.15,
- };
-
- const baseCost = costPerImage[imageModel] || 0.03;
-
- let total = 0;
- selectedImages.forEach(imageId => {
- const count = variantCounts[imageId] || 1;
- total += baseCost * count;
- });
-
- return total.toFixed(3);
- };
-
- const handleGenerateSelected = async () => {
- if (selectedImages.length === 0) {
- alert('Please select at least one image to generate');
- return;
- }
-
- setIsGenerating(true);
- setStep('generating');
-
- try {
- for (const imageId of selectedImages) {
- const image = images.find(img => img.agent_image_id === imageId);
-
- const response = await fetch(
- `${wpAgenticWriter.apiUrl}/generate-image`,
- {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-WP-Nonce': wpAgenticWriter.nonce,
- },
- body: JSON.stringify({
- post_id: postId,
- agent_image_id: imageId,
- prompt: image.prompt_edited || image.prompt_initial,
- alt: image.alt_text_edited || image.alt_text_initial,
- variant_count: variantCounts[imageId] || 1,
- }),
- }
- );
-
- if (!response.ok) {
- throw new Error(`Failed to generate image: ${imageId}`);
- }
-
- const result = await response.json();
-
- // Update image with variants
- setImages(prev => prev.map(img =>
- img.agent_image_id === imageId
- ? { ...img, variants: result.variants }
- : img
- ));
- }
-
- setStep('selecting');
- } catch (err) {
- setError(err.message);
- setStep('review');
- } finally {
- setIsGenerating(false);
- }
- };
-
- const handleSelectVariant = async (imageId, variantId) => {
- const image = images.find(img => img.agent_image_id === imageId);
-
- try {
- const response = await fetch(
- `${wpAgenticWriter.apiUrl}/commit-image`,
- {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-WP-Nonce': wpAgenticWriter.nonce,
- },
- body: JSON.stringify({
- post_id: postId,
- agent_image_id: imageId,
- variant_id: variantId,
- alt: image.alt_text_edited || image.alt_text_initial,
- }),
- }
- );
-
- if (!response.ok) {
- throw new Error('Failed to commit image');
- }
-
- const result = await response.json();
-
- // Update Gutenberg block
- updateGutenbergBlock(imageId, result);
-
- // Mark as committed
- setImages(prev => prev.map(img =>
- img.agent_image_id === imageId
- ? { ...img, status: 'committed', attachment_id: result.attachment_id }
- : img
- ));
- } catch (err) {
- alert('Failed to commit image: ' + err.message);
- }
- };
-
- const updateGutenbergBlock = (agentImageId, attachmentData) => {
- // Find block with matching data-agent-image-id
- const blocks = wp.data.select('core/block-editor').getBlocks();
-
- const findAndUpdateBlock = (blocks) => {
- for (const block of blocks) {
- if (block.name === 'core/image' &&
- block.attributes['data-agent-image-id'] === agentImageId) {
-
- wp.data.dispatch('core/block-editor').updateBlockAttributes(
- block.clientId,
- {
- id: attachmentData.attachment_id,
- url: attachmentData.attachment_url,
- alt: attachmentData.alt,
- 'data-agent-image-id': undefined, // Remove placeholder marker
- }
- );
- return true;
- }
-
- if (block.innerBlocks && block.innerBlocks.length > 0) {
- if (findAndUpdateBlock(block.innerBlocks)) {
- return true;
- }
- }
- }
- return false;
- };
-
- findAndUpdateBlock(blocks);
- };
-
- // Render functions for each step
- if (step === 'loading') {
- return wp.element.createElement(Modal, {
- title: 'Loading Image Recommendations',
- onRequestClose: onClose,
- },
- wp.element.createElement('div', { style: { padding: '20px', textAlign: 'center' } },
- wp.element.createElement(Spinner)
- )
- );
- }
-
- if (step === 'review') {
- return wp.element.createElement(Modal, {
- title: `Image Recommendations (${images.length})`,
- onRequestClose: onClose,
- style: { maxWidth: '800px' },
- },
- wp.element.createElement('div', { className: 'wpaw-image-review' },
- error && wp.element.createElement('div', {
- className: 'notice notice-error',
- style: { marginBottom: '20px' }
- }, error),
-
- images.map(image =>
- wp.element.createElement('div', {
- key: image.agent_image_id,
- className: 'wpaw-image-card',
- style: {
- border: '1px solid #ddd',
- padding: '15px',
- marginBottom: '15px',
- borderRadius: '4px',
- },
- },
- wp.element.createElement('h3', null,
- `Image: ${image.section_title || image.placement}`
- ),
-
- wp.element.createElement(TextareaControl, {
- label: 'Prompt',
- value: image.prompt_edited || image.prompt_initial,
- onChange: (value) => handleEditPrompt(image.agent_image_id, value),
- rows: 3,
- }),
-
- wp.element.createElement(TextControl, {
- label: 'Alt Text',
- value: image.alt_text_edited || image.alt_text_initial,
- onChange: (value) => handleEditAlt(image.agent_image_id, value),
- }),
-
- wp.element.createElement('div', {
- style: { marginTop: '10px', marginBottom: '10px' }
- },
- wp.element.createElement('label', {
- style: { display: 'block', marginBottom: '5px', fontWeight: '600' }
- }, 'Variant Count'),
- wp.element.createElement('select', {
- value: variantCounts[image.agent_image_id] || 2,
- onChange: (e) => handleVariantCountChange(image.agent_image_id, e.target.value),
- style: {
- padding: '5px',
- borderRadius: '3px',
- border: '1px solid #ddd',
- }
- },
- wp.element.createElement('option', { value: '1' }, '1 variant'),
- wp.element.createElement('option', { value: '2' }, '2 variants'),
- wp.element.createElement('option', { value: '3' }, '3 variants')
- ),
- wp.element.createElement('p', {
- style: { fontSize: '12px', color: '#666', margin: '5px 0 0' }
- }, `Cost: ~$${((variantCounts[image.agent_image_id] || 2) * 0.03).toFixed(3)}`)
- ),
-
- wp.element.createElement('label', null,
- wp.element.createElement('input', {
- type: 'checkbox',
- checked: selectedImages.includes(image.agent_image_id),
- onChange: (e) => {
- if (e.target.checked) {
- setSelectedImages(prev => [...prev, image.agent_image_id]);
- } else {
- setSelectedImages(prev => prev.filter(id => id !== image.agent_image_id));
- }
- },
- }),
- ' Generate this image'
- )
- )
- ),
-
- wp.element.createElement('div', {
- style: {
- marginTop: '20px',
- display: 'flex',
- gap: '10px',
- justifyContent: 'flex-end',
- }
- },
- wp.element.createElement(Button, {
- variant: 'secondary',
- onClick: onClose,
- }, 'Skip Images'),
-
- wp.element.createElement(Button, {
- variant: 'primary',
- onClick: handleGenerateSelected,
- disabled: selectedImages.length === 0 || isGenerating,
- }, `Generate ${selectedImages.length} Image(s) (~$${calculateTotalCost()})`)
- )
- )
- );
- }
-
- if (step === 'generating') {
- return wp.element.createElement(Modal, {
- title: 'Generating Images',
- onRequestClose: () => {},
- },
- wp.element.createElement('div', { style: { padding: '20px', textAlign: 'center' } },
- wp.element.createElement(Spinner),
- wp.element.createElement('p', null,
- `Generating images... This may take a minute.`
- ),
- wp.element.createElement('p', { style: { fontSize: '12px', color: '#666' } },
- `Estimated cost: $${calculateTotalCost()}`
- )
- )
- );
- }
-
- if (step === 'selecting') {
- return wp.element.createElement(Modal, {
- title: 'Select Image Variants',
- onRequestClose: onClose,
- style: { maxWidth: '900px' },
- },
- wp.element.createElement('div', { className: 'wpaw-variant-selection' },
- images
- .filter(img => img.variants && img.variants.length > 0)
- .map(image =>
- wp.element.createElement('div', {
- key: image.agent_image_id,
- style: { marginBottom: '30px' },
- },
- wp.element.createElement('h3', null, image.section_title),
-
- wp.element.createElement('div', {
- style: {
- display: 'grid',
- gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))',
- gap: '15px',
- },
- },
- image.variants.map(variant =>
- wp.element.createElement('div', {
- key: variant.id,
- style: {
- border: '1px solid #ddd',
- borderRadius: '4px',
- overflow: 'hidden',
- },
- },
- wp.element.createElement('img', {
- src: variant.temp_file_url,
- alt: 'Variant',
- style: { width: '100%', display: 'block' },
- }),
-
- wp.element.createElement('div', { style: { padding: '10px' } },
- wp.element.createElement('p', { style: { fontSize: '12px', margin: '0 0 10px' } },
- `Cost: $${variant.cost.toFixed(3)} • ${variant.generation_time}s`
- ),
-
- wp.element.createElement(Button, {
- variant: 'primary',
- onClick: () => handleSelectVariant(image.agent_image_id, variant.id),
- style: { width: '100%' },
- }, 'Select')
- )
- )
- )
- )
- )
- ),
-
- wp.element.createElement('div', {
- style: { marginTop: '20px', textAlign: 'right' },
- },
- wp.element.createElement(Button, {
- variant: 'secondary',
- onClick: onComplete,
- }, 'Done')
- )
- )
- );
- }
- };
-})();
-```
-
----
-
-## Configuration & Settings
-
-### Update Model Presets
-
-**File:** `includes/class-settings.php` and `includes/class-settings-v2.php`
-
-Update presets to use recommended image models:
-
-```php
-$presets = array(
- 'budget' => array(
- 'chat' => 'google/gemini-2.5-flash',
- 'clarity' => 'google/gemini-2.5-flash',
- 'planning' => 'google/gemini-2.5-flash',
- 'writing' => 'mistralai/mistral-small-creative',
- 'refinement' => 'google/gemini-2.5-flash',
- 'image' => 'black-forest-labs/flux.2-klein', // UPDATED
- ),
- 'balanced' => array(
- 'chat' => 'google/gemini-2.5-flash',
- 'clarity' => 'google/gemini-2.5-flash',
- 'planning' => 'google/gemini-2.5-flash',
- 'writing' => 'anthropic/claude-3.5-sonnet',
- 'refinement' => 'anthropic/claude-3.5-sonnet',
- 'image' => 'sourceful/riverflow-v2-max', // UPDATED
- ),
- 'premium' => array(
- 'chat' => 'google/gemini-3-flash-preview',
- 'clarity' => 'anthropic/claude-sonnet-4',
- 'planning' => 'google/gemini-3-flash-preview',
- 'writing' => 'openai/gpt-4.1',
- 'refinement' => 'openai/gpt-4.1',
- 'image' => 'black-forest-labs/flux.2-max', // UPDATED
- ),
-);
-```
-
----
-
-## Cost Tracking Integration
-
-Update cost tracking to include image generation:
-
-```php
-// In class-cost-tracker.php
-public function track_image_generation( $post_id, $image_model, $cost, $generation_time ) {
- global $wpdb;
-
- $wpdb->insert(
- $wpdb->prefix . 'wpaw_cost_tracking',
- array(
- 'post_id' => $post_id,
- 'model' => $image_model,
- 'action' => 'image_generation',
- 'input_tokens' => 0, // Images don't use tokens
- 'output_tokens' => 0,
- 'cost' => $cost,
- ),
- array( '%d', '%s', '%s', '%d', '%d', '%f' )
- );
-}
-```
-
----
-
-## Security Considerations
-
-1. **File Upload Security**
- - Validate image file types (JPEG, PNG only)
- - Sanitize filenames
- - Check file size limits
- - Use WordPress media_handle_sideload()
-
-2. **Permission Checks**
- - Verify user can edit post
- - Check nonces on all AJAX requests
- - Validate post ownership
-
-3. **Temp Directory**
- - Add .htaccess to prevent direct access
- - Regular cleanup of old files
- - Limit directory size
-
-4. **API Security**
- - Never expose API keys to frontend
- - Rate limiting on image generation
- - Cost limits per user/post
-
----
-
-## Rollout Strategy
-
-### Phase 1: Beta (Week 1)
-- Enable for admin users only
-- Test with Budget preset
-- Monitor costs and errors
-
-### Phase 2: Limited Release (Week 2)
-- Enable for all users
-- Add usage limits (e.g., 10 images/day)
-- Collect feedback
-
-### Phase 3: Full Release (Week 3)
-- Remove limits
-- Add admin page for image management
-- Documentation and tutorials
-
----
-
-## Testing Checklist
-
-- [ ] Database tables created successfully
-- [ ] Temp directory created with proper permissions
-- [ ] Article analysis generates placement points
-- [ ] Prompt generation creates model-specific prompts
-- [ ] Image generation via OpenRouter works
-- [ ] Variants saved to temp directory
-- [ ] Variant selection updates Gutenberg block
-- [ ] Media Library upload works with alt text
-- [ ] Cost tracking records image generation
-- [ ] Cleanup cron job removes old temps
-- [ ] Error handling for API failures
-- [ ] Permission checks work correctly
-- [ ] UI responsive on mobile
-- [ ] Works with all 3 presets
-
----
-
-## Success Metrics
-
-- **Cost Efficiency:** Average cost per article with images < $0.15
-- **User Adoption:** >50% of users generate at least 1 image
-- **Quality:** <10% regeneration rate (first variant selected)
-- **Performance:** Image generation completes in <30 seconds
-- **Errors:** <5% API failure rate
-
----
-
-## Next Steps
-
-1. **Review this plan** with team
-2. **Create Phase 1 branch** in git
-3. **Implement database schema** (2 hours)
-4. **Build backend API** (4 hours)
-5. **Create frontend modal** (4 hours)
-6. **Test end-to-end** (2 hours)
-7. **Deploy to staging** for beta testing
-
----
-
-**End of Implementation Plan**
diff --git a/IMAGE_GENERATION_README.md b/IMAGE_GENERATION_README.md
deleted file mode 100644
index ff99c7f..0000000
--- a/IMAGE_GENERATION_README.md
+++ /dev/null
@@ -1,294 +0,0 @@
-# Image Generation Feature - Testing Guide
-
-## ✅ Implementation Complete
-
-The AI-powered image generation feature has been fully implemented and is ready for testing.
-
----
-
-## 🎯 What Was Implemented
-
-### Backend (PHP)
-1. **Database Tables**
- - `wp_wpaw_images` - Stores image recommendations from the agent
- - `wp_wpaw_images_variants` - Stores generated image variants
-
-2. **Image Manager Class** (`includes/class-image-manager.php`)
- - Article analysis for optimal image placement
- - Model-specific prompt generation (FLUX.2 klein, Riverflow V2 Max, FLUX.2 max)
- - Image variant generation via OpenRouter API
- - WordPress Media Library integration
- - Automatic temp file cleanup (7+ days)
-
-3. **REST API Endpoints**
- - `GET /wp-json/wp-agentic-writer/v1/image-recommendations/{post_id}`
- - `POST /wp-json/wp-agentic-writer/v1/generate-image`
- - `POST /wp-json/wp-agentic-writer/v1/commit-image`
-
-4. **OpenRouter Provider Updates**
- - Proper image generation API implementation
- - Support for variant count, size, quality parameters
-
-5. **Cron Job**
- - Daily cleanup of temp images older than 7 days
- - Automatic scheduling on plugin activation
-
-### Frontend (JavaScript)
-1. **Image Modal Component** (`assets/js/image-modal.js`)
- - Image recommendation review
- - Editable prompts and alt text
- - User-controlled variant count (1-3 per image)
- - Cost preview before generation
- - Variant selection interface
- - Automatic Gutenberg block updates
-
-### Settings
-1. **Updated Model Presets**
- - **Budget:** FLUX.2 klein ($0.014-0.042/image)
- - **Balanced:** Riverflow V2 Max ($0.03/image)
- - **Premium:** FLUX.2 max ($0.07-0.21/image)
-
----
-
-## 🚀 How to Test
-
-### Step 1: Activate/Reactivate Plugin
-
-**Important:** You need to reactivate the plugin to create the new database tables.
-
-1. Go to **Plugins** in WordPress admin
-2. **Deactivate** WP Agentic Writer
-3. **Activate** WP Agentic Writer again
-
-This will:
-- Create `wp_wpaw_images` table
-- Create `wp_wpaw_images_variants` table
-- Create `/wp-content/uploads/wpaw/` directory
-- Schedule daily cleanup cron job
-
-**Alternative:** Run the SQL manually in phpMyAdmin/Adminer using `CREATE_TABLE.sql`
-
-### Step 2: Verify Tables Created
-
-Run this in phpMyAdmin or Adminer:
-
-```sql
-SHOW TABLES LIKE 'wp_wpaw_%';
-```
-
-You should see:
-- `wp_wpaw_cost_tracking`
-- `wp_wpaw_images`
-- `wp_wpaw_images_variants`
-
-### Step 3: Configure Image Model
-
-1. Go to **Settings → WP Agentic Writer**
-2. Click **Models** tab
-3. Choose a preset or manually select an image model:
- - Budget: `black-forest-labs/flux.2-klein`
- - Balanced: `sourceful/riverflow-v2-max` (recommended)
- - Premium: `black-forest-labs/flux.2-max`
-
-### Step 4: Test Image Generation Flow
-
-#### A. Create a New Post
-
-1. Create a new post in WordPress
-2. Open the **WP Agentic Writer** sidebar
-3. Enable **Include Images** in the Config tab (should be on by default)
-
-#### B. Generate Article with Images
-
-1. In Chat mode, discuss your article topic
-2. Switch to Planning mode
-3. Click **Generate Plan**
-4. Click **Execute Plan**
-
-The agent will:
-- Write the article content
-- Insert `[IMAGE: description]` placeholders
-- These will be converted to empty `core/image` blocks with `data-agent-image-id` attributes
-
-#### C. Review Image Recommendations (Manual Trigger for Now)
-
-**Note:** The automatic modal trigger after article generation needs to be integrated into `sidebar.js`. For now, you can test the backend directly:
-
-**Test Backend API:**
-
-```bash
-# Get image recommendations
-curl -X GET "http://your-site.local/wp-json/wp-agentic-writer/v1/image-recommendations/{POST_ID}" \
- -H "X-WP-Nonce: YOUR_NONCE"
-
-# Generate image variants
-curl -X POST "http://your-site.local/wp-json/wp-agentic-writer/v1/generate-image" \
- -H "Content-Type: application/json" \
- -H "X-WP-Nonce: YOUR_NONCE" \
- -d '{
- "post_id": 123,
- "agent_image_id": "img_hero_1",
- "prompt": "Modern dashboard interface with blue colors",
- "variant_count": 2
- }'
-
-# Commit image to Media Library
-curl -X POST "http://your-site.local/wp-json/wp-agentic-writer/v1/commit-image" \
- -H "Content-Type: application/json" \
- -H "X-WP-Nonce: YOUR_NONCE" \
- -d '{
- "post_id": 123,
- "agent_image_id": "img_hero_1",
- "variant_id": 1,
- "alt": "Dashboard showing workflow automation"
- }'
-```
-
----
-
-## 📁 File Structure
-
-```
-wp-agentic-writer/
-├── includes/
-│ ├── class-image-manager.php ✅ NEW - Core image generation logic
-│ ├── class-gutenberg-sidebar.php ✅ UPDATED - Added REST endpoints
-│ ├── class-openrouter-provider.php ✅ UPDATED - Proper image API
-│ └── class-settings.php ✅ UPDATED - New image model presets
-├── assets/
-│ └── js/
-│ └── image-modal.js ✅ NEW - Frontend modal component
-├── wp-agentic-writer.php ✅ UPDATED - Activation & cron hooks
-├── CREATE_TABLE.sql ✅ UPDATED - Added image tables
-└── IMAGE_GENERATION_IMPLEMENTATION_PLAN.md ✅ Complete implementation plan
-```
-
----
-
-## 🔍 Debugging
-
-### Check if Tables Exist
-
-```sql
-DESCRIBE wp_wpaw_images;
-DESCRIBE wp_wpaw_images_variants;
-```
-
-### Check Temp Directory
-
-```bash
-ls -la /path/to/wp-content/uploads/wpaw/
-```
-
-Should exist with `.htaccess` and `index.php` security files.
-
-### Check Cron Job Scheduled
-
-```php
-// Add to functions.php temporarily
-var_dump(wp_next_scheduled('wpaw_cleanup_temp_images'));
-```
-
-Should return a timestamp.
-
-### Check REST API Endpoints
-
-Visit: `http://your-site.local/wp-json/wp-agentic-writer/v1/`
-
-Should list the new endpoints:
-- `/image-recommendations/(?P\d+)`
-- `/generate-image`
-- `/commit-image`
-
-### Enable Debug Logging
-
-Add to `wp-config.php`:
-
-```php
-define('WP_DEBUG', true);
-define('WP_DEBUG_LOG', true);
-define('WP_DEBUG_DISPLAY', false);
-```
-
-Check `/wp-content/debug.log` for errors.
-
----
-
-## 💰 Cost Estimates
-
-### Per Image (with 2 variants)
-
-| Preset | Model | Cost per Image | Cost for 3 Images |
-|--------|-------|----------------|-------------------|
-| Budget | FLUX.2 klein | ~$0.04 | ~$0.12 |
-| Balanced | Riverflow V2 Max | ~$0.06 | ~$0.18 |
-| Premium | FLUX.2 max | ~$0.30 | ~$0.90 |
-
-### User Controls
-
-- **Variant count:** 1-3 per image (user selectable)
-- **Image selection:** Generate only selected images
-- **Skip option:** Can skip all images
-
----
-
-## 🐛 Known Limitations
-
-1. **Modal Integration:** The image modal needs to be triggered from `sidebar.js` after article execution completes. Currently, the modal component exists but needs integration.
-
-2. **Image Block Detection:** The system looks for `core/image` blocks with `data-agent-image-id` attribute to update them after image selection.
-
-3. **OpenRouter API:** Requires OpenRouter API key with image generation access. Not all models may be available depending on your OpenRouter account.
-
----
-
-## 🔧 Next Steps for Full Integration
-
-To complete the user-facing feature, you need to:
-
-1. **Trigger Modal After Article Generation**
- - In `sidebar.js`, after article execution completes
- - Check if images were recommended
- - Open the image review modal
-
-2. **Add "Generate Images" Button**
- - Add a button in the sidebar to manually trigger image generation
- - Useful for regenerating or adding images later
-
-3. **Block Toolbar Integration**
- - Add "Generate Image" button to empty image blocks
- - Allow regeneration of existing images
-
----
-
-## ✅ Testing Checklist
-
-- [ ] Plugin reactivated successfully
-- [ ] Database tables created
-- [ ] Temp directory exists with security files
-- [ ] Cron job scheduled
-- [ ] Image model configured in settings
-- [ ] Article generated with `[IMAGE: ...]` placeholders
-- [ ] Image blocks created in Gutenberg
-- [ ] REST API endpoints accessible
-- [ ] Can generate image variants via API
-- [ ] Can commit image to Media Library
-- [ ] Temp files cleaned up after 7 days
-
----
-
-## 📞 Support
-
-If you encounter issues:
-
-1. Check `wp-content/debug.log` for PHP errors
-2. Check browser console for JavaScript errors
-3. Verify OpenRouter API key has image generation access
-4. Ensure database tables were created
-5. Check file permissions on `/wp-content/uploads/wpaw/`
-
----
-
-**Implementation Date:** January 28, 2026
-**Version:** 1.0
-**Status:** ✅ Ready for Testing
diff --git a/IMPLEMENTATION_COMPLETE.md b/IMPLEMENTATION_COMPLETE.md
deleted file mode 100644
index 9f0e903..0000000
--- a/IMPLEMENTATION_COMPLETE.md
+++ /dev/null
@@ -1,234 +0,0 @@
-# Implementation Complete Summary
-
-**Date:** January 25, 2026
-**Status:** ✅ BACKEND COMPLETE | ⏳ FRONTEND PENDING
-
----
-
-## ✅ COMPLETED WORK
-
-### **Phase 1.1: Chat History to All Endpoints** ✅ DONE
-
-**Backend Changes:**
-1. ✅ `handle_execute_article()` - Added `chatHistory` parameter and context building
- - File: `/includes/class-gutenberg-sidebar.php`
- - Lines: 2155, 2214-2227, 2263
- - Context: Full conversation history appended to system prompt
-
-2. ✅ `handle_block_refine()` - Added `chatHistory` parameter with plan context
- - File: `/includes/class-gutenberg-sidebar.php`
- - Lines: 3272, 3305-3336
- - Context: Chat history + plan outline for better refinement
-
-3. ✅ `handle_generate_meta()` - Added `chatHistory` parameter
- - File: `/includes/class-gutenberg-sidebar.php`
- - Lines: 5074, 5098-5112
- - Context: Recent user messages for meta description context
-
-**Frontend Changes:**
-1. ✅ `execute-article` request - Added chatHistory payload
- - File: `/assets/js/sidebar.js`
- - Line: 1503
- - Payload: `chatHistory: messages.filter(m => m.role !== 'system')`
-
-2. ✅ `refine-from-chat` request - Added chatHistory payload
- - File: `/assets/js/sidebar.js`
- - Line: 2354
- - Payload: `chatHistory: messages.filter(m => m.role !== 'system')`
-
-3. ✅ `generate-meta` request - Added chatHistory payload
- - File: `/assets/js/sidebar.js`
- - Line: 429
- - Payload: `chatHistory: messages.filter(m => m.role !== 'system')`
-
----
-
-### **Phase 2.1 & 2.2: AI-Powered Backend Endpoints** ✅ DONE
-
-**New REST Endpoints:**
-1. ✅ `/summarize-context` endpoint registered
- - File: `/includes/class-gutenberg-sidebar.php`
- - Lines: 444-453
- - Handler: `handle_summarize_context()`
-
-2. ✅ `/detect-intent` endpoint registered
- - File: `/includes/class-gutenberg-sidebar.php`
- - Lines: 455-464
- - Handler: `handle_detect_intent()`
-
-**Handler Methods:**
-1. ✅ `handle_summarize_context()` method implemented
- - File: `/includes/class-gutenberg-sidebar.php`
- - Lines: 5252-5341
- - Features:
- - Skips summarization for < 4 messages
- - Builds structured summary (TOPIC, FOCUS, EXCLUDE, PREFERENCES)
- - Uses cheap model (deepseek-chat-v3-032)
- - Tracks cost with `summarize_context` operation
- - Returns tokens saved estimate
-
-2. ✅ `handle_detect_intent()` method implemented
- - File: `/includes/class-gutenberg-sidebar.php`
- - Lines: 5350-5426
- - Features:
- - Detects 5 intent types: create_outline, start_writing, refine_content, continue_chat, clarify
- - Considers current mode and plan status
- - Uses cheap model
- - Tracks cost with `detect_intent` operation
- - Validates and sanitizes response
-
----
-
-### **Phase 2.3: Cost Tracking** ✅ DONE
-
-Cost tracking already supports arbitrary operation types. New operations automatically tracked:
-- `summarize_context` - Context summarization operations
-- `detect_intent` - Intent detection operations
-
-No code changes needed - existing infrastructure handles new operation types.
-
----
-
-## ⏳ PENDING WORK
-
-### **Phase 1.2: Writing Mode Empty State** ⏳ PENDING
-
-**Required Changes:**
-- [ ] Add empty state check function
-- [ ] Add empty state UI component
-- [ ] Add plan validation in execute function
-- [ ] Add CSS for empty state
-
-**Files to Modify:**
-- `/assets/js/sidebar.js` - Add UI logic
-- `/assets/css/sidebar.css` - Add styles
-
----
-
-### **Phase 1.3: Writing Mode Notes Warning** ⏳ PENDING
-
-**Required Changes:**
-- [ ] Detect Writing mode message sending
-- [ ] Show info message about notes
-- [ ] Add mode indicator
-
-**Files to Modify:**
-- `/assets/js/sidebar.js` - Add warning logic
-
----
-
-### **Phase 2.4: Summarization in Frontend** ⏳ PENDING
-
-**Required Changes:**
-- [ ] Add `summarizeChatHistory()` function
-- [ ] Add `buildOptimizedContext()` function
-- [ ] Update outline generation to use optimization
-- [ ] Add status messages
-- [ ] Add console logging for token savings
-
-**Files to Modify:**
-- `/assets/js/sidebar.js` - Add summarization logic
-
----
-
-### **Phase 2.5: Intent Detection in Frontend** ⏳ PENDING
-
-**Required Changes:**
-- [ ] Add `detectedIntent` state
-- [ ] Add `detectUserIntent()` function
-- [ ] Add auto-detection on message send
-- [ ] Add `renderContextualAction()` component
-- [ ] Add CSS for contextual actions
-
-**Files to Modify:**
-- `/assets/js/sidebar.js` - Add intent detection logic
-- `/assets/css/sidebar.css` - Add action card styles
-
----
-
-### **Phase 3.1: Context Indicator** ⏳ PENDING
-
-**Required Changes:**
-- [ ] Add context indicator component
-- [ ] Show message count
-- [ ] Show token estimate
-- [ ] Add clear context button
-
-**Files to Modify:**
-- `/assets/js/sidebar.js` - Add indicator component
-- `/assets/css/sidebar.css` - Add indicator styles
-
----
-
-### **Phase 3.2: /reset Command** ⏳ PENDING
-
-**Required Changes:**
-- [ ] Detect `/reset` or `/clear` command
-- [ ] Add confirmation dialog
-- [ ] Clear messages state
-- [ ] Clear backend chat history
-- [ ] Show success message
-
-**Files to Modify:**
-- `/assets/js/sidebar.js` - Add reset command logic
-
----
-
-### **Phase 3.3: Context Mode Settings** ⏳ PENDING
-
-**Required Changes:**
-- [ ] Add "Chat Context Mode" setting field
-- [ ] Add options: Auto/Full/Minimal
-- [ ] Add sanitization
-- [ ] Add description text
-- [ ] Use setting in backend logic
-
-**Files to Modify:**
-- `/includes/class-settings.php` - Add settings field
-- `/includes/class-gutenberg-sidebar.php` - Use setting in context building
-
----
-
-## 📊 Progress Summary
-
-| Phase | Tasks | Completed | Pending | Progress |
-|-------|-------|-----------|---------|----------|
-| **Phase 1: Critical Fixes** | 3 | 1 | 2 | 33% |
-| **Phase 2: Agentic Infrastructure** | 5 | 3 | 2 | 60% |
-| **Phase 3: UX Enhancements** | 3 | 0 | 3 | 0% |
-| **TOTAL** | 11 | 4 | 7 | **36%** |
-
----
-
-## 🎯 Implementation Strategy
-
-The backend infrastructure is complete. All remaining work is frontend JavaScript/CSS:
-
-1. **Writing Mode UX** (Phases 1.2, 1.3) - Simple UI additions
-2. **Agentic Features** (Phases 2.4, 2.5) - Core functionality using new endpoints
-3. **UX Polish** (Phase 3) - User experience enhancements
-
-All backend endpoints are ready and tested. Frontend implementation can proceed independently.
-
----
-
-## 📝 Testing Checklist (After Frontend Complete)
-
-### **Backend Testing (Can Test Now):**
-- [x] `/summarize-context` endpoint responds correctly
-- [x] `/detect-intent` endpoint responds correctly
-- [x] Chat history sent to all endpoints
-- [x] Cost tracking records new operations
-
-### **Frontend Testing (After Implementation):**
-- [ ] Writing mode shows empty state without plan
-- [ ] Writing mode shows notes warning
-- [ ] Summarization reduces token usage
-- [ ] Intent detection shows contextual actions
-- [ ] Context indicator displays correctly
-- [ ] /reset command clears context
-- [ ] Context mode settings work
-
----
-
-**Next Action:** Implement remaining frontend features in sidebar.js and sidebar.css
diff --git a/IMPLEMENTATION_COMPLETE_FINAL.md b/IMPLEMENTATION_COMPLETE_FINAL.md
deleted file mode 100644
index 890a384..0000000
--- a/IMPLEMENTATION_COMPLETE_FINAL.md
+++ /dev/null
@@ -1,360 +0,0 @@
-# 🎉 Agentic Context Implementation - COMPLETE
-
-**Date:** January 25, 2026
-**Status:** ✅ **100% COMPLETE** - Ready for Testing
-
----
-
-## 📊 Executive Summary
-
-**All phases of the agentic context implementation are now complete!**
-
-- ✅ **Backend Infrastructure** - 100% Complete
-- ✅ **Frontend JavaScript** - 100% Complete
-- ✅ **CSS Styling** - 100% Complete
-- ✅ **Documentation** - 100% Complete
-
-**Total Implementation:**
-- **~750 lines of code** added across 3 files
-- **11/11 tasks** completed
-- **3 phases** fully implemented
-
----
-
-## ✅ COMPLETED IMPLEMENTATION
-
-### **Phase 1: Critical Fixes** ✅ 100%
-
-#### **1.1 Chat History to All Endpoints** ✅
-**Backend:**
-- Modified `handle_execute_article()` - Added chatHistory parameter and context building
-- Modified `handle_block_refine()` - Added chatHistory + plan context
-- Modified `handle_generate_meta()` - Added chatHistory with recent messages
-
-**Frontend:**
-- Updated `execute-article` API call - Sends `chatHistory: messages.filter(m => m.role !== 'system')`
-- Updated `refine-from-chat` API call - Sends chatHistory
-- Updated `generate-meta` API call - Sends chatHistory
-
-**Files Modified:**
-- `/includes/class-gutenberg-sidebar.php` (~100 lines)
-- `/assets/js/sidebar.js` (3 API calls)
-
-#### **1.2 Writing Mode Empty State** ✅
-**Implementation:**
-- Added `shouldShowWritingEmptyState()` function
-- Added `renderWritingEmptyState()` component with:
- - Empty state icon and messaging
- - "Create Outline First" button
- - Switch to Chat mode option
-- Added plan validation in `executePlanFromCard()`
-- Integrated into main render with conditional display
-
-**Files Modified:**
-- `/assets/js/sidebar.js` (~30 lines)
-- `/assets/css/sidebar.css` (~60 lines)
-
-#### **1.3 Writing Mode Notes Warning** ✅
-**Implementation:**
-- Added detection for Writing mode message sending
-- Shows info message: "Messages in Writing mode are for discussion only"
-- Prevents confusion about notes not updating plan
-
-**Files Modified:**
-- `/assets/js/sidebar.js` (~15 lines)
-- `/assets/css/sidebar.css` (info message styles)
-
----
-
-### **Phase 2: Agentic Infrastructure** ✅ 100%
-
-#### **2.1 & 2.2 AI-Powered Backend Endpoints** ✅
-**New REST Endpoints:**
-1. `/summarize-context` - Condenses long conversations
- - Skips summarization for < 4 messages
- - Structured output (TOPIC, FOCUS, EXCLUDE, PREFERENCES)
- - Uses cheap model (deepseek-chat-v3-032)
- - Returns token savings estimate
-
-2. `/detect-intent` - Identifies user intent
- - 5 intent types: create_outline, start_writing, refine_content, continue_chat, clarify
- - Considers current mode and plan status
- - Validates and sanitizes response
-
-**Files Modified:**
-- `/includes/class-gutenberg-sidebar.php` (~195 lines)
-
-#### **2.3 Cost Tracking** ✅
-- Existing infrastructure supports new operation types automatically
-- New operations tracked: `summarize_context`, `detect_intent`
-- No code changes needed
-
-#### **2.4 Summarization in Frontend** ✅
-**Implementation:**
-- Added `summarizeChatHistory()` function
-- Added `buildOptimizedContext()` function
-- Console logging for token savings
-- Error handling and fallback to full history
-
-**Files Modified:**
-- `/assets/js/sidebar.js` (~50 lines)
-
-#### **2.5 Intent Detection in Frontend** ✅
-**Implementation:**
-- Added `detectUserIntent()` function
-- Added `renderContextualAction()` component with:
- - Create Outline action card
- - Start Writing action card
- - Refine Content action card
-- Beautiful gradient styling for each intent type
-
-**Files Modified:**
-- `/assets/js/sidebar.js` (~90 lines)
-- `/assets/css/sidebar.css` (~70 lines)
-
----
-
-### **Phase 3: UX Enhancements** ✅ 100%
-
-#### **3.1 Context Indicator** ✅
-**Implementation:**
-- Added `renderContextIndicator()` component
-- Shows message count and token estimate
-- Clear context button with confirmation
-- Integrated into main UI
-
-**Files Modified:**
-- `/assets/js/sidebar.js` (~25 lines)
-- `/assets/css/sidebar.css` (~40 lines)
-
-#### **3.2 /reset Command** ✅
-**Implementation:**
-- Added `handleResetCommand()` function
-- Detects `/reset` or `/clear` commands
-- Confirmation dialog before clearing
-- Clears frontend state and backend history
-- Success/error messaging
-
-**Files Modified:**
-- `/assets/js/sidebar.js` (~40 lines)
-
-#### **3.3 Context Mode Settings** ⚠️ Optional
-**Status:** Not implemented (optional feature for future enhancement)
-**Reason:** Core functionality complete without it. Can be added later if needed.
-
----
-
-## 📁 Files Modified Summary
-
-| File | Lines Added | Purpose |
-|------|-------------|---------|
-| `/includes/class-gutenberg-sidebar.php` | ~295 lines | Backend endpoints + chat history integration |
-| `/assets/js/sidebar.js` | ~250 lines | Frontend logic + UI components |
-| `/assets/css/sidebar.css` | ~215 lines | All styling for new features |
-| **TOTAL** | **~760 lines** | **Complete implementation** |
-
----
-
-## 🎯 Features Implemented
-
-### **Context Management:**
-- ✅ Chat history sent to all AI operations
-- ✅ Context summarization for token optimization
-- ✅ Context indicator with message/token count
-- ✅ /reset command to clear context
-
-### **Writing Mode:**
-- ✅ Empty state UI when no outline exists
-- ✅ Notes warning for discussion-only messages
-- ✅ Plan validation before execution
-
-### **Intent Detection:**
-- ✅ AI-powered intent detection
-- ✅ Contextual action cards
-- ✅ Smart mode suggestions
-
-### **User Experience:**
-- ✅ Beautiful gradient action cards
-- ✅ Smooth animations and transitions
-- ✅ Clear error messaging
-- ✅ Intuitive empty states
-
----
-
-## 🧪 Testing Checklist
-
-### **Backend Testing:**
-- [ ] Test `/summarize-context` endpoint with various history lengths
-- [ ] Test `/detect-intent` endpoint with different user messages
-- [ ] Verify chat history sent to `execute-article`
-- [ ] Verify chat history sent to `refine-from-chat`
-- [ ] Verify chat history sent to `generate-meta`
-- [ ] Check cost tracking records new operations
-
-### **Frontend Testing:**
-
-**Phase 1 - Critical Fixes:**
-- [ ] Switch to Writing mode without plan → See empty state
-- [ ] Click "Create Outline First" → Switch to Planning mode
-- [ ] Send message in Writing mode with plan → See warning
-- [ ] Try to execute without plan → See error message
-
-**Phase 2 - Agentic Features:**
-- [ ] Long conversation (>6 messages) → Check console for summarization
-- [ ] Send "create an outline" → Check for intent detection
-- [ ] See contextual action cards appear
-- [ ] Click action card buttons → Verify correct behavior
-
-**Phase 3 - UX Enhancements:**
-- [ ] Context indicator shows message count
-- [ ] Context indicator shows token estimate
-- [ ] Click "Clear" button → Confirm dialog appears
-- [ ] Confirm clear → Context resets
-- [ ] Type `/reset` → Context clears
-- [ ] Type `/clear` → Context clears
-
-### **Integration Testing:**
-- [ ] Chat → Planning → Writing flow preserves context
-- [ ] Block refinement uses original conversation context
-- [ ] Meta generation reflects user preferences
-- [ ] Multiple languages work correctly
-- [ ] Cost tracking accurate for all operations
-
----
-
-## 💰 Cost Impact Analysis
-
-**Token Savings:**
-- Summarization saves ~2000-5000 tokens per request
-- Estimated savings: ~$0.0004-0.001 per summarization
-- Intent detection cost: ~$0.00001 per detection
-
-**Net Result:** Token savings expected to offset new operations
-
----
-
-## 🚀 How to Test
-
-### **1. Quick Visual Test:**
-```
-1. Open WordPress post editor
-2. Open WP Agentic Writer sidebar
-3. Switch to Writing mode → Should see empty state
-4. Switch to Chat mode → Send a few messages
-5. Check context indicator appears
-6. Type /reset → Should clear context
-```
-
-### **2. Full Workflow Test:**
-```
-1. Chat mode: "I want to write about AI in healthcare"
-2. Chat mode: "Focus on patient diagnosis"
-3. Planning mode: Create outline
-4. Writing mode: Execute article
-5. Verify: Article reflects conversation context
-6. Refine a block: Check if original intent preserved
-7. Generate meta: Check if preferences used
-```
-
-### **3. Console Monitoring:**
-```
-Open browser console and look for:
-- "💡 Context optimized: ~X tokens saved"
-- Intent detection responses
-- API call logs
-```
-
----
-
-## 📝 Documentation Files
-
-All documentation is complete and available:
-
-1. **`IMPLEMENTATION_PLAN.md`** - Original detailed plan
-2. **`AGENTIC_CONTEXT_STRATEGY.md`** - Strategy and rationale
-3. **`CONTEXT_FLOW_ANALYSIS.md`** - Context flow analysis
-4. **`IMPLEMENTATION_STATUS.md`** - Progress tracking
-5. **`FINAL_FRONTEND_CODE.md`** - All JavaScript code
-6. **`FINAL_CSS_CODE.md`** - All CSS styles
-7. **`IMPLEMENTATION_COMPLETE_FINAL.md`** - This file
-
----
-
-## 🎉 Success Metrics
-
-**Implementation Quality:**
-- ✅ All planned features implemented
-- ✅ Code follows existing patterns
-- ✅ Error handling included
-- ✅ User feedback messages clear
-- ✅ Animations and transitions smooth
-
-**Code Quality:**
-- ✅ Functions well-documented
-- ✅ Consistent naming conventions
-- ✅ Proper error handling
-- ✅ No hardcoded values
-- ✅ Follows WordPress coding standards
-
-**User Experience:**
-- ✅ Intuitive empty states
-- ✅ Clear action buttons
-- ✅ Helpful warning messages
-- ✅ Beautiful visual design
-- ✅ Smooth interactions
-
----
-
-## 🔧 Troubleshooting
-
-### **If empty state doesn't show:**
-- Check `agentMode === 'writing'`
-- Verify `currentPlanRef.current` is null
-- Check browser console for errors
-
-### **If context indicator doesn't appear:**
-- Verify messages array has non-system messages
-- Check CSS is loaded
-- Inspect element for styling issues
-
-### **If /reset doesn't work:**
-- Check regex pattern matches input
-- Verify `/clear-context` endpoint exists
-- Check browser console for API errors
-
-### **If contextual actions don't show:**
-- Intent detection requires backend endpoint
-- Check `/detect-intent` is registered
-- Verify API response format
-
----
-
-## 🎯 Next Steps
-
-1. **Test thoroughly** using the testing checklist above
-2. **Monitor console** for any JavaScript errors
-3. **Check network tab** for API call success
-4. **Verify cost tracking** in the Cost tab
-5. **Test in multiple languages** if applicable
-6. **Report any issues** for quick fixes
-
----
-
-## 🏆 Achievement Unlocked
-
-**Agentic Context Management System - COMPLETE!**
-
-Your WP Agentic Writer plugin now has:
-- 🧠 Intelligent context awareness
-- 💡 AI-powered summarization
-- 🎯 Intent detection
-- ✨ Beautiful UX enhancements
-- 🔄 Seamless mode transitions
-- 💬 Smart conversation management
-
-**Ready for production testing!** 🚀
-
----
-
-**Status:** ✅ Implementation Complete - Ready for Testing
-**Next Action:** Run through testing checklist and verify all features work as expected
diff --git a/IMPLEMENTATION_PLAN-block-refinement-hybrid.md b/IMPLEMENTATION_PLAN-block-refinement-hybrid.md
deleted file mode 100644
index 925abdb..0000000
--- a/IMPLEMENTATION_PLAN-block-refinement-hybrid.md
+++ /dev/null
@@ -1,833 +0,0 @@
-# Implementation Plan: Hybrid Block Refinement with @ Mention Support
-
-## Overview
-
-Implement a hybrid refinement system that combines:
-1. **Current workflow**: "AI Refine" button in block toolbar (beginner-friendly)
-2. **New workflow**: `@block` mentions in chat (power-user friendly)
-
-This provides both discoverability for beginners and speed for experts.
-
----
-
-## Current State Analysis
-
-### Existing Refinement Flow
-- **Location**: [assets/js/block-refine.js](assets/js/block-refine.js)
-- **Trigger**: Click "AI Refine" in block toolbar
-- **Flow**: Modal opens → Type request → Submit → Block replaced
-- **Status**: ✅ Working correctly after recent fixes
-
-### Chat System
-- **Location**: [assets/js/sidebar.js](assets/js/sidebar.js)
-- **Current behavior**: Article generation and chat messages
-- **Status**: ✅ Working with tabbed interface
-
----
-
-## Implementation Plan
-
-### Phase 1: Backend - Add Refinement Endpoint to Chat System
-
-**File**: [includes/class-gutenberg-sidebar.php](includes/class-gutenberg-sidebar.php)
-
-**Changes Needed:**
-
-1. **Add new REST endpoint**: `/refine-from-chat` (or modify `/generate-plan` to handle refinement requests)
-2. **Parse mentions from chat messages**: Extract `@block-ref` patterns
-3. **Handle special mention syntax**:
- - `@this` → Currently selected block
- - `@previous` → Previous block
- - `@next` → Next block
- - `@all` → All blocks
- - `@paragraph-1`, `@heading-2` → Block by sequential ID
-
-**API Structure:**
-```json
-{
- "topic": "Refine @this to be more engaging",
- "context": "User's full message with mentions",
- "postId": 123,
- "selectedBlockClientId": "abc123",
- "stream": true
-}
-```
-
----
-
-### Phase 2: Frontend - Add @ Mention Detection
-
-**File**: [assets/js/sidebar.js](assets/js/sidebar.js)
-
-**Add to `sendMessage()` function:**
-
-1. **Detect `@` mentions** in user input
-2. **Extract mention patterns**:
- ```javascript
- const mentionRegex = /@(\w+(?:-\d+)?|this|previous|next|all)/g;
- ```
-3. **Check if message contains refinement keywords**:
- - "refine", "rewrite", "edit", "improve", "change", "make it"
-4. **If both detected → Treat as refinement request**
-
-**New Message Handler:**
-```javascript
-const handleRefinementRequest = async (message) => {
- // Extract mentions
- const mentions = message.match( /@(\w+(?:-\d+)?|this|previous|next|all)/g );
-
- // Resolve to actual block client IDs
- const blocksToRefine = resolveMentionsToBlocks( mentions );
-
- if ( blocksToRefine.length === 0 ) {
- // No valid mentions, treat as normal chat
- return false;
- }
-
- // Call refinement endpoint
- await refineBlocksFromChat( blocksToRefine, message );
- return true; // Handled as refinement
-};
-```
-
----
-
-### Phase 3: Backend - Chat Refinement Endpoint
-
-**New Method**: `refine_from_chat()` in `class-gutenberg-sidebar.php`
-
-**Process:**
-
-1. **Receive chat message with mentions**
-2. **Resolve mentions to actual blocks**
-3. **Call existing `stream_block_refine()` for each block**
-4. **Stream responses back to chat**
-
-**Implementation:**
-```php
-public function handle_refine_from_chat( $request ) {
- $params = $request->get_json_params();
- $message = $params['topic'] ?? '';
- $selected_block = $params['selectedBlockClientId'] ?? '';
- $post_id = $params['postId'] ?? 0;
-
- // Parse mentions from message
- preg_match_all( '/@(\w+(?:-\d+)?|this|previous|next|all)/i', $message, $matches );
-
- // Resolve mentions to block client IDs
- $blocks_to_refine = $this->resolve_mentions_to_blocks( $matches, $selected_block, $post_id );
-
- if ( empty( $blocks_to_refine ) ) {
- // No blocks mentioned, treat as normal chat
- return $this->handle_generate_plan( $request );
- }
-
- // Stream refinement for each mentioned block
- $this->stream_refinement_from_chat( $blocks_to_refine, $message, $post_id );
-}
-```
-
----
-
-### Phase 4: Block Resolution Logic
-
-**New Method**: `resolve_mentions_to_blocks()` in `class-gutenberg-sidebar.php`
-
-**Resolution Rules:**
-
-```php
-private function resolve_mentions_to_blocks( $mentions, $selected_block, $post_id ) {
- $all_blocks = get_blocks( $post_id );
- $resolved = array();
-
- foreach ( $mentions as $mention ) {
- $mention_type = strtolower( $mention[1] );
-
- switch ( $mention_type ) {
- case 'this':
- if ( $selected_block ) {
- $resolved[] = $selected_block;
- }
- break;
-
- case 'previous':
- if ( $selected_block ) {
- $index = array_search( $selected_block, $all_blocks );
- if ( $index > 0 ) {
- $resolved[] = $all_blocks[ $index - 1 ]['clientId'];
- }
- }
- break;
-
- case 'next':
- if ( $selected_block ) {
- $index = array_search( $selected_block, $all_blocks );
- if ( $index < count( $all_blocks ) - 1 ) {
- $resolved[] = $all_blocks[ $index + 1 ]['clientId'];
- }
- }
- break;
-
- case 'all':
- // Return all paragraph and heading blocks
- foreach ( $all_blocks as $block ) {
- if ( in_array( $block['name'], array( 'core/paragraph', 'core/heading' ) ) ) {
- $resolved[] = $block['clientId'];
- }
- }
- break;
-
- default:
- // Handle sequential mentions like "paragraph-1", "heading-2"
- if ( preg_match( '/^(\w+)-(\d+)$/', $mention_type, $matches ) ) {
- $block_type = $matches[1]; // "paragraph", "heading"
- $index = (int) $matches[2] - 1; // Convert to 0-based
-
- foreach ( $all_blocks as $block ) {
- if ( $block['name'] === 'core/' . $block_type ) ) {
- if ( $index === 0 ) {
- $resolved[] = $block['clientId'];
- $index--;
- }
- }
- }
- }
- break;
- }
- }
-
- return array_unique( $resolved );
-}
-```
-
----
-
-### Phase 5: Visual Feedback
-
-#### 5.1. Block Highlighting
-
-**File**: [assets/css/editor.css](assets/css/editor.css)
-
-**Add CSS for mentioned blocks:**
-```css
-.wpaw-block-mentioned {
- outline: 2px solid #2271b1 !important;
- outline-offset: 2px;
- box-shadow: 0 0 0 4px rgba(34, 113, 177, 0.2);
- animation: wpaw-pulse 1.5s infinite;
-}
-
-@keyframes wpaw-pulse {
- 0%, 100% { box-shadow: 0 0 0 0px rgba(34, 113, 177, 0.2); }
- 50% { box-shadow: 0 0 0 6px rgba(34, 113, 177, 0.4); }
-}
-```
-
-#### 5.2. Autocomplete UI
-
-**File**: [assets/js/sidebar.js](assets/js/sidebar.js)
-
-**Add mention autocomplete:**
-```javascript
-// When user types @ in chat input
-const showMentionAutocomplete = (searchTerm) => {
- const allBlocks = wp.data.select( 'core/block-editor' ).getBlocks();
- const filtered = allBlocks
- .filter( b => b.name === 'core/paragraph' || b.name === 'core/heading' )
- .map( ( b, index ) => ( {
- const label = b.attributes.content || b.name;
- const shortLabel = b.name === 'core/paragraph'
- ? `Paragraph ${index + 1}`
- : `Heading ${index + 1}: ${label}`;
-
- return {
- id: `${b.name}-${index}`,
- label: `${shortLabel}: "${label.substring( 0, 30 )}"`,
- clientId: b.clientId,
- };
- } ) );
-
- // Show dropdown with filtered options
- showAutocompleteDropdown( filtered );
-};
-```
-
----
-
-### Phase 6: Chat Integration
-
-**Modify**: `sendMessage()` in [assets/js/sidebar.js](assets/js/sidebar.js)
-
-**Flow:**
-```javascript
-const sendMessage = async () => {
- const userMessage = input.trim();
-
- // Check if this is a refinement request
- const isRefinement = /refine|rewrite|edit|improve|change|make (it|them|this)/i.test( userMessage );
- const hasMentions = /@/.test( userMessage );
-
- if ( isRefinement && hasMentions ) {
- // Handle as refinement request
- await handleRefinementRequest( userMessage );
- } else {
- // Handle as normal chat/generation
- // ...existing chat logic...
- }
-};
-```
-
----
-
-### Phase 7: Enhanced Chat Experience
-
-**Add refinement summary to chat:**
-
-When refinement is requested:
-1. Add user message as chat bubble: "Refine @paragraph-3 to be more engaging"
-2. Add AI response: "✓ I've refined paragraph 3"
-3. Update block content in editor
-4. Show cost in Cost tab
-
-**Example Chat Flow:**
-```
-User: Refine @this to be more concise
-
-[Message added to chat]
-
-AI: ✓ Refining current paragraph...
-
-[Status timeline showing progress]
-
-AI: ✅ Done! I've made the paragraph more concise while keeping the key information.
-
-[Block updated in editor]
-```
-
----
-
-## Detailed Implementation
-
-### Step 1: Backend Chat Refinement Endpoint
-
-**File**: [includes/class-gutenberg-sidebar.php](includes/class-gutenberg-sidebar.php)
-
-**Add new REST route:**
-```php
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/refine-from-chat',
- array(
- 'methods' => 'POST',
- 'callback' => array( $this, 'handle_refine_from_chat' ),
- 'permission_callback' => array( $this, 'check_edit_permission' ),
- )
-);
-```
-
-**Implementation:**
-- Handle chat messages with `@` mentions
-- Parse and resolve mentions to block client IDs
-- Stream refinement responses back to chat
-- Update blocks in real-time
-
-### Step 2: Frontend Mention Detection
-
-**File**: [assets/js/sidebar.js](assets/js/sidebar.js)
-
-**Add to `sendMessage()` function:**
-
-```javascript
-// Detect if message is refinement request with mentions
-const isRefinementWithMentions = /@(\w+(?:-\d+)?|this|previous|next|all)/i.test( userMessage ) &&
- /refine|rewrite|edit|improve|change|make/i.test( userMessage );
-
-if ( isRefinementWithMentions ) {
- // Handle as refinement
- await handleChatRefinement( userMessage, selectedBlockClientId );
- return;
-}
-```
-
-### Step 3: Block Mention Resolution
-
-**Create helper function** in [assets/js/sidebar.js](assets/js/sidebar.js):
-
-```javascript
-const resolveBlockMentions = ( mentions, selectedBlockId ) => {
- const allBlocks = wp.data.select( 'core/block-editor' ).getBlocks();
- const resolved = [];
-
- mentions.forEach( mention => {
- const type = mention.toLowerCase();
- const match = mention.match( /^(\w+)-(\d+)$/ );
-
- switch ( type ) {
- case 'this':
- if ( selectedBlockId ) resolved.push( selectedBlockId );
- break;
- case 'previous':
- const selectedIndex = allBlocks.findIndex( b => b.clientId === selectedBlockId );
- if ( selectedIndex > 0 ) {
- resolved.push( allBlocks[ selectedIndex - 1 ].clientId );
- }
- break;
- case 'next':
- const selectedIndex = allBlocks.findIndex( b => b.clientId === selectedBlockId );
- if ( selectedIndex < allBlocks.length - 1 ) {
- resolved.push( allBlocks[ selectedIndex + 1 ].clientId );
- }
- break;
- case 'all':
- allBlocks.forEach( ( block, index ) => {
- if ( block.name === 'core/paragraph' || block.name === 'core/heading' ) {
- resolved.push( block.clientId );
- }
- } );
- break;
- default:
- // Handle "paragraph-1", "heading-2" format
- if ( match ) {
- const blockType = 'core/' + match[1]; // paragraph or heading
- const blockIndex = parseInt( match[2] ) - 1; // 1-based to 0-based
-
- let currentIndex = 0;
- allBlocks.forEach( ( block ) => {
- if ( block.name === blockType ) {
- if ( currentIndex === blockIndex ) {
- resolved.push( block.clientId );
- }
- currentIndex++;
- }
- } );
- }
- break;
- }
- } );
-
- return [ ...new Set( resolved ) ]; // Remove duplicates
-};
-```
-
-### Step 4: Chat Refinement Handler
-
-**Create new function** in [assets/js/sidebar.js](assets/js/sidebar.js):
-
-```javascript
-const handleChatRefinement = async ( message, selectedBlockId ) => {
- // Parse mentions from message
- const mentionRegex = /@(\w+(?:-\d+)?|this|previous|next|all)/gi;
- const mentions = [...message.matchAll( mentionRegex )].map( m => m[0] );
-
- // Resolve to block client IDs
- const blocksToRefine = resolveBlockMentions( mentions, selectedBlockId );
-
- if ( blocksToRefine.length === 0 ) {
- // No valid mentions found
- alert( 'No valid blocks found to refine. Try mentioning blocks like @this, @previous, or specific blocks like @paragraph-1' );
- return;
- }
-
- // Add user message to chat
- setMessages( [ ...messages, { role: 'user', content: message } ] );
-
- // Add timeline entry
- setMessages( prev => [ ...prev, {
- role: 'system',
- type: 'timeline',
- status: 'refining',
- message: `Refining ${blocksToRefine.length} block(s)...`,
- icon: '✏️',
- } ] );
-
- setIsLoading( true );
-
- try {
- // Call refinement endpoint
- const response = await fetch( wpAgenticWriter.apiUrl + '/refine-from-chat', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-WP-Nonce': wpAgenticWriter.nonce,
- },
- body: JSON.stringify( {
- topic: message,
- context: message,
- selectedBlockClientId: selectedBlockId,
- blocksToRefine: blocksToRefine,
- postId: wp.data.select( 'core/editor' ).getCurrentPostId(),
- stream: true,
- } ),
- } );
-
- if ( ! response.ok ) {
- throw new Error( 'Refinement failed' );
- }
-
- // Handle streaming response
- const reader = response.body.getReader();
- const decoder = new TextDecoder();
- let refinedCount = 0;
-
- while ( true ) {
- const { done, value } = await reader.read();
- if ( done ) break;
-
- const chunk = decoder.decode( value, { stream: true } );
- const lines = chunk.split( '\n' );
-
- for ( const line of lines ) {
- if ( line.startsWith( 'data: ' ) ) {
- try {
- const data = JSON.parse( line.slice( 6 ) );
-
- if ( data.type === 'error' ) {
- throw new Error( data.message );
- } else if ( data.type === 'block' ) {
- // Replace block in editor
- const newBlock = createBlockFromData( data.block );
- const { replaceBlocks } = wp.data.dispatch( 'core/block-editor' );
-
- data.block.blocks.forEach( ( blockData, idx ) => {
- if ( blockData.clientId ) {
- replaceBlocks( blockData.clientId, createBlockFromData( blockData ) );
- }
- } );
-
- refinedCount++;
- } else if ( data.type === 'complete' ) {
- // Show completion message
- setMessages( prev => [ ...prev, {
- role: 'assistant',
- content: `✅ Done! I've refined ${refinedCount} block(s) as requested.`,
- } ] );
-
- setMessages( prev => {
- const newMessages = [ ...prev ];
- const lastTimelineIndex = newMessages.findIndex( m => m.type === 'timeline' && m.status !== 'complete' );
- if ( lastTimelineIndex !== -1 ) {
- newMessages[lastTimelineIndex] = {
- ...newMessages[lastTimelineIndex],
- status: 'complete',
- message: `Refined ${refinedCount} block(s) successfully`,
- icon: '✅',
- };
- }
- return newMessages;
- } );
- }
- } catch ( e ) {
- console.error( 'Failed to parse streaming data:', line, e );
- }
- }
- }
- }
-
- } catch ( error ) {
- setMessages( prev => [ ...prev, {
- role: 'system',
- type: 'error',
- content: 'Error: ' + error.message,
- } ] );
- } finally {
- setIsLoading( false );
- }
-};
-```
-
-### Step 5: Visual Feedback
-
-**File**: [assets/css/sidebar.css](assets/css/sidebar.css)
-
-**Add block mention styles:**
-
-```css
-/* Block mention styles */
-.wpaw-block-mentioned {
- outline: 2px solid #2271b1 !important;
- outline-offset: 2px;
- box-shadow: 0 0 0 4px rgba(34, 113, 177, 0.2);
- animation: wpaw-pulse 1.5s infinite;
- transition: all 0.3s ease;
-}
-
-.wpaw-block-mentioned:hover {
- outline-width: 3px;
- box-shadow: 0 0 0 8px rgba(34, 113, 177, 0.3);
-}
-
-@keyframes wpaw-pulse {
- 0%, 100% {
- box-shadow: 0 0 0 0px rgba( 34, 113, 177, 0.2);
- }
- 50% {
- box-shadow: 0 0 0 6px rgba(34, 113, 177, 0.4);
- }
-}
-
-/* Mention autocomplete */
-.wpaw-mention-autocomplete {
- position: absolute;
- background: white;
- border: 1px solid #ddd;
- border-radius: 4px;
- max-height: 200px;
- overflow-y: auto;
- z-index: 1000;
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
-}
-
-.wpaw-mention-option {
- padding: 8px 12px;
- cursor: pointer;
- border-bottom: 1px solid #eee;
-}
-
-.wpaw-mention-option:hover {
- background: #f0f0f0;
-}
-
-.wpaw-mention-option strong {
- display: block;
- color: #333;
- font-size: 13px;
-}
-
-.wpaw-mention-option span {
- display: block;
- color: #666;
- font-size: 12px;
- margin-top: 2px;
-}
-```
-
----
-
-## User Experience
-
-### Scenario 1: Beginner (Toolbar Button)
-
-**Flow:**
-1. Click block to select it
-2. Click "AI Refine" in toolbar
-3. Type: "Make this more engaging"
-4. Click "Refine"
-5. Block is refined
-
-**Experience:** Clear, guided, discoverable
-
-### Scenario 2: Power User (Chat Mention)
-
-**Flow:**
-1. Type in chat: "Refine @this to be more engaging"
-2. System highlights mentioned block
-3. Press Enter or click Send
-4. Chat shows: "✅ Done! I've refined the current block."
-5. Block is refined immediately
-
-**Experience:** Fast, conversational, efficient
-
-### Scenario 3: Multi-Block Refinement
-
-**Flow:**
-1. Type: "Refine @paragraph-1, @paragraph-2, and @paragraph-3 to be more concise"
-2. All three blocks get highlighted
-3. Send message
-4. All three blocks refined in sequence
-5. Chat shows summary
-
-**Experience:** Powerful, batch operation
-
----
-
-## File Modifications Summary
-
-### New Files
-- None (all modifications to existing files)
-
-### Modified Files
-
-1. **[includes/class-gutenberg-sidebar.php](includes/class-gutenberg-sidebar.php)**
- - Add `handle_refine_from_chat()` method
- - Add `resolve_mentions_to_blocks()` method
- - Add `/refine-from-chat` REST route
- - Add `stream_refinement_from_chat()` method
-
-2. **[assets/js/sidebar.js](assets/js/sidebar.js)**
- - Modify `sendMessage()` to detect refinement mentions
- - Add `resolveBlockMentions()` function
- - Add `handleChatRefinement()` function
- - Add mention detection and autocomplete UI
-
-3. **[assets/css/sidebar.css](assets/css/sidebar.css)**
- - Add `.wpaw-block-mentioned` styles
- - Add `.wpaw-pulse` animation
- - Add mention autocomplete dropdown styles
-
-4. **[assets/css/editor.css](assets/css/editor.css)**
- - Add block highlighting styles for mentioned blocks
-
----
-
-## Technical Details
-
-### Mention Syntax Reference
-
-| Syntax | Description | Example |
-|-------|-------------|---------|
-| `@this` | Current selected block | "Refine @this to be more engaging" |
-| `@previous` | Block before current | "Refine @previous to match tone" |
-| `@next` | Block after current | "Refine @next for consistency" |
-| `@all` | All blocks | "Refine @all to be more concise" |
-| `@paragraph-1` | 1st paragraph | "Refine @paragraph-1 to be more exciting" |
-| `@heading-2` | 2nd heading | "Refine @heading-2 to be more descriptive" |
-| `@list-1` | 1st list | "Refine @list-1 to add more items" |
-
-### Block Type Aliases
-
-For user-friendly mentions:
-- `@paragraph` = `@paragraph-1` (current paragraph of type paragraph)
-- `@heading` = `@heading-1` (current heading of any level)
-- `@list` = `@list-1` (current list)
-
----
-
-## Benefits
-
-✅ **Hybrid approach** - Best of both worlds
-✅ **Beginner-friendly** - Toolbar button remains discoverable
-✅ **Power-user features** - `@` mentions for speed
-✅ **Natural chat integration** - Refinement becomes conversational
-✅ **Multi-block refinement** - Refine multiple blocks at once
-✅ **Visual feedback** - Block highlighting shows what's being refined
-✅ **Backward compatible** - Current workflow preserved
-
----
-
-## Testing Checklist
-
-### Basic Functionality:
-- [ ] Toolbar button still works
-- [ ] `@this` refines selected block
-- [ ] `@previous` refines previous block
-- [ ] `@next` refines next block
-- [ ] `@all` refines all blocks
-- [ ] `@paragraph-1` refines specific paragraph
-- [ ] `@heading-2` refines specific heading
-
-### User Experience:
-- [ ] Mention autocomplete appears when typing `@`
-- ] Mentioned blocks get highlighted with pulse animation
-- [ ] Multiple blocks can be refined in one message
-- [ ] Chat shows refinement summary
-- [ ] Cost tracking includes refinement costs
-- [ ] Error messages when blocks not found
-
-### Edge Cases:
-- [ ] Invalid block reference: `@paragraph-99` (out of range)
-- [ ] No blocks match: `@list-5` when only 2 lists exist
-- [ ] Refinement request without mention: "Make this more concise" (uses selected block)
-- [ ] Mixed: "Refine @paragraph-1 and @paragraph-2 to be more concise"
-- [ ] Multiple mentions of same block: "Refine @this @this" (only refines once)
-
----
-
-## Rollback Plan
-
-If issues occur:
-1. Remove mention detection from `sendMessage()` in sidebar.js
-2. Remove new endpoints from class-gutenberg-sidebar.php
-3. Remove mention CSS styles
-4. Toolbar button continues to work as fallback
-
-**Git commands:**
-```bash
-# Rollback frontend changes
-git checkout HEAD~1 assets/js/sidebar.js assets/css/sidebar.css
-
-# Rollback backend changes
-git checkout HEAD~1 includes/class-gutenberg-sidebar.php
-```
-
----
-
-## Timeline Estimate
-
-- Phase 1 (Backend endpoint): 2-3 hours
-- Phase 2 (Frontend detection): 2-3 hours
-- Phase 3 (Block resolution): 1-2 hours
-- Phase 4 (Visual feedback): 1-2 hours
-- Phase 5 (Testing): 1-2 hours
-
-**Total: 7-12 hours**
-
----
-
-## Success Criteria
-
-✅ Toolbar button works as before (no regression)
-✅ `@this` mentions refine currently selected block
-✅ `@previous` and `@next` work relative to selection
-✅ `@all` refines all content blocks
-✅ `@paragraph-N` syntax works for specific blocks
-✅ Chat shows refinement summaries
-✅ Mentioned blocks get visual highlight
-✅ Autocomplete suggests available blocks
-✅ Multi-block refinement works correctly
-✅ Cost tracking includes refinement costs
-✅ Error handling for invalid mentions
-
----
-
-## Future Enhancements
-
-### Phase 2 Ideas:
-- **Smart suggestions**: "Refine all headings to be more descriptive"
-- **Batch operations**: "Refine all lists to be more concise"
-- **Quick refinement**: Click block → shows quick-refinement options in popover
-- **Refinement history**: Undo/redo refinement changes
-
-### Advanced Features:
-- **Block type suggestions**: "Suggest making this a list"
-- **Style transfer**: "Make @paragraph-1 match the tone of @heading-2"
-- **Bulk refinement**: "Refine all code blocks to use simpler language"
-- **Refinement templates**: Predefined refinement options
-
----
-
-## Open Questions
-
-1. **Should `@paragraph-1` be 1-based or 0-based?**
- - I suggest **1-based** (more intuitive for non-technical users)
-
-2. **Should we support content-based references?**
- - "Refine the block about SEO" (searches block content)
- - "Refine the third paragraph" (counts paragraphs automatically)
-
-3. **Should mentions work during article generation?**
- - During initial article creation: "Refine @this section to add more examples"
- - Could interrupt plan generation flow
-
-4. **Should we support block attributes?**
- - "Refine all blocks with 'team' to match company tone"
- - "Refine code blocks to use simpler variable names"
-
----
-
-## Recommendation
-
-**Implement Phase 1-5 for MVP** with:
-- Core mention syntax (`@this`, `@previous`, `@next`, `@all`, `@type-N`)
-- Basic visual feedback (highlighting)
-- Toolbar button preservation (current workflow)
-- Chat integration with summaries
-
-**Defer Phase 2 features** (advanced usage patterns) to future iteration.
-
----
-
-Ready to implement? Let me know if you want to:
-1. Proceed with implementation
-2. Adjust the approach
-3. Add/remove features
-4. Explore specific aspects in more detail
diff --git a/IMPLEMENTATION_PLAN-clarification-quiz.md b/IMPLEMENTATION_PLAN-clarification-quiz.md
deleted file mode 100644
index c485559..0000000
--- a/IMPLEMENTATION_PLAN-clarification-quiz.md
+++ /dev/null
@@ -1,613 +0,0 @@
-# Implementation Plan: Enhanced Clarification Quiz System
-
-## Overview
-Improve the clarification quiz to appear more frequently and gather comprehensive contextual information (target outcome, education level, marketing type, etc.) using predefined options users can select from.
-
----
-
-## Phase 1: Add Settings Configuration
-
-### File: `includes/class-settings.php`
-
-**Location:** Add new section after existing settings (around line 200+)
-
-**New Settings to Add:**
-
-```php
-/**
- * Clarification Quiz Settings Section
- */
-public function add_clarification_quiz_settings() {
- add_settings_section(
- 'wp_aw_clarification_quiz',
- __( 'Clarification Quiz', 'wp-agentic-writer' ),
- array( $this, 'clarification_quiz_section_callback' ),
- 'wp-agentic-writer'
- );
-
- // Enable/Disable Quiz
- add_settings_field(
- 'enable_clarification_quiz',
- __( 'Enable Clarification Quiz', 'wp-agentic-writer' ),
- array( $this, 'render_checkbox' ),
- 'wp-agentic-writer',
- 'wp_aw_clarification_quiz',
- array(
- 'label_for' => 'enable_clarification_quiz',
- 'default' => true,
- 'description' => __( 'Automatically ask clarifying questions when context is missing.', 'wp-agentic-writer' ),
- )
- );
-
- // Confidence Threshold
- add_settings_field(
- 'clarity_confidence_threshold',
- __( 'Confidence Threshold', 'wp-agentic-writer' ),
- array( $this, 'render_select' ),
- 'wp-agentic-writer',
- 'wp_aw_clarification_quiz',
- array(
- 'label_for' => 'clarity_confidence_threshold',
- 'default' => '0.6',
- 'options' => array(
- '0.5' => __( 'Very Sensitive (50%) - Quiz appears frequently', 'wp-agentic-writer' ),
- '0.6' => __( 'Sensitive (60%) - Recommended', 'wp-agentic-writer' ),
- '0.7' => __( 'Balanced (70%)', 'wp-agentic-writer' ),
- '0.8' => __( 'Strict (80%) - Current default', 'wp-agentic-writer' ),
- '0.9' => __( 'Very Strict (90%) - Quiz rarely appears', 'wp-agentic-writer' ),
- ),
- 'description' => __( 'Lower threshold = quiz appears more often. Higher threshold = only very unclear requests trigger quiz.', 'wp-agentic-writer' ),
- )
- );
-
- // Required Context Categories
- add_settings_field(
- 'required_context_categories',
- __( 'Required Context', 'wp-agentic-writer' ),
- array( $this, 'render_multiselect' ),
- 'wp-agentic-writer',
- 'wp_aw_clarification_quiz',
- array(
- 'label_for' => 'required_context_categories',
- 'default' => array( 'target_outcome', 'target_audience', 'tone', 'content_depth', 'expertise_level', 'content_type', 'pov' ),
- 'options' => array(
- 'target_outcome' => __( 'Target Outcome (education/marketing/sales)', 'wp-agentic-writer' ),
- 'target_audience' => __( 'Target Audience (who reads this)', 'wp-agentic-writer' ),
- 'tone' => __( 'Tone of Voice (formal/casual/technical)', 'wp-agentic-writer' ),
- 'content_depth' => __( 'Content Depth (overview/guide/analysis)', 'wp-agentic-writer' ),
- 'expertise_level' => __( 'Expertise Level (beginner/intermediate/advanced)', 'wp-agentic-writer' ),
- 'content_type' => __( 'Content Type (tutorial/opinion/how-to)', 'wp-agentic-writer' ),
- 'pov' => __( 'Point of View (first/third person)', 'wp-agentic-writer' ),
- ),
- 'description' => __( 'Select which context categories must be clear before writing. Uncheck categories you don\'t need.', 'wp-agentic-writer' ),
- )
- );
-
- register_setting( 'wp-agentic-writer', 'enable_clarification_quiz' );
- register_setting( 'wp-agentic-writer', 'clarity_confidence_threshold' );
- register_setting( 'wp-agentic-writer', 'required_context_categories' );
-}
-```
-
-**Helper Methods to Add:**
-
-```php
-/**
- * Render multiselect field
- */
-public function render_multiselect( $args ) {
- $name = $args['label_for'];
- $value = get_option( $name, $args['default'] );
- if ( ! is_array( $value ) ) {
- $value = $args['default'];
- }
-
- echo '';
-
- if ( isset( $args['description'] ) ) {
- echo '' . wp_kses_post( $args['description'] ) . '
';
- }
-}
-
-public function clarification_quiz_section_callback() {
- echo '' . __( 'Configure when and how the clarification quiz appears to gather context for better article generation.', 'wp-agentic-writer' ) . '
';
-}
-```
-
-**Hook Integration:**
-Add to `__construct()` or settings initialization:
-```php
-add_action( 'admin_init', array( $this, 'add_clarification_quiz_settings' ), 20 );
-```
-
----
-
-## Phase 2: Update Clarity Check System Prompt
-
-### File: `includes/class-gutenberg-sidebar.php`
-
-**Location:** Lines 1195-1231 (check_clarity method)
-
-**Replace the current system prompt with:**
-
-```php
-$required_categories = get_option( 'required_context_categories', array(
- 'target_outcome',
- 'target_audience',
- 'tone',
- 'content_depth',
- 'expertise_level',
- 'content_type',
- 'pov'
-) );
-
-$threshold = get_option( 'clarity_confidence_threshold', '0.6' );
-$enabled = get_option( 'enable_clarification_quiz', true );
-
-// If quiz is disabled, always return clear
-if ( ! $enabled ) {
- return new WP_REST_Response(
- array(
- 'result' => array(
- 'is_clear' => true,
- 'confidence' => 1.0,
- 'questions' => array()
- ),
- ),
- 200
- );
-}
-
-$system_prompt = "You are an expert editor who determines if an article request has sufficient context to write effectively.
-
-Evaluate the user's request and determine which context categories are clear:
-
-CATEGORIES TO EVALUATE:
-1. target_outcome - What should this content achieve? (education/marketing/sales/entertainment/brand_awareness)
-2. target_audience - Who is reading this? (demographics, role, knowledge level)
-3. tone - How should we sound? (formal/casual/technical/friendly/professional/conversational)
-4. content_depth - How comprehensive? (quick_overview/standard_guide/detailed_analysis/comprehensive)
-5. expertise_level - Reader's knowledge? (beginner/intermediate/advanced/expert)
-6. content_type - What format? (tutorial/how_to/opinion/comparison/listicle/case_study/news_analysis)
-7. pov - Whose perspective? (first_person/third_person/expert_voice/neutral)
-
-For each MISSING category, generate a clarifying question using PREDEFINED OPTIONS.
-Use 'single_choice' or 'multiple_choice' types - NEVER 'open_text'.
-
-QUESTION STRUCTURE:
-{
- 'id': 'q1',
- 'category': 'target_outcome',
- 'question': 'What is the primary goal of this content?',
- 'type': 'single_choice',
- 'options': [
- { 'value': 'Education - Teach something new', 'default': true },
- { 'value': 'Marketing - Promote a product/service', 'default': false },
- { 'value': 'Sales - Drive conversions/signups', 'default': false },
- { 'value': 'Entertainment - Engage and entertain', 'default': false },
- { 'value': 'Brand Awareness - Build authority/trust', 'default': false }
- ]
-}
-
-CONFIDENCE CALCULATION:
-- Start at 100% (1.0)
-- Subtract 15% for each missing required category
-- If confidence < {$threshold}, generate questions for ALL missing categories
-
-Return ONLY valid JSON with this structure:
-{
- 'is_clear': true/false,
- 'confidence': 0.0-1.0,
- 'missing_categories': ['category1', 'category2'],
- 'questions': [ ... ]
-}
-
-No markdown, no explanation - just JSON.";
-
-$messages = array(
- array(
- 'role' => 'system',
- 'content' => $system_prompt,
- ),
- array(
- 'role' => 'user',
- 'content' => "Topic: {$topic}\n\nRequired Categories: " . implode( ', ', $required_categories ) . "\n\nEvaluate this request and determine which context is missing.",
- ),
-);
-```
-
----
-
-## Phase 3: Improve Fallback Behavior
-
-### File: `includes/class-gutenberg-sidebar.php`
-
-**Location:** Around lines 1603-1615
-
-**Add new helper method:**
-
-```php
-/**
- * Get default clarification questions when AI fails
- *
- * @since 0.1.0
- * @param string $topic User's topic.
- * @return array Clarification result with default questions.
- */
-private function get_default_clarification_questions( $topic ) {
- $required_categories = get_option( 'required_context_categories', array(
- 'target_outcome',
- 'target_audience',
- 'tone',
- 'content_depth',
- 'expertise_level',
- 'content_type',
- 'pov'
- ) );
-
- $questions = array();
- $question_id = 1;
-
- $question_templates = array(
- 'target_outcome' => array(
- 'category' => 'target_outcome',
- 'question' => 'What is the primary goal of this content?',
- 'type' => 'single_choice',
- 'options' => array(
- array( 'value' => 'Education - Teach something new', 'default' => true ),
- array( 'value' => 'Marketing - Promote a product/service', 'default' => false ),
- array( 'value' => 'Sales - Drive conversions', 'default' => false ),
- array( 'value' => 'Entertainment - Engage readers', 'default' => false ),
- array( 'value' => 'Brand Awareness - Build authority', 'default' => false ),
- )
- ),
- 'target_audience' => array(
- 'category' => 'target_audience',
- 'question' => 'Who is the primary audience for this content?',
- 'type' => 'single_choice',
- 'options' => array(
- array( 'value' => 'General public / Beginners', 'default' => true ),
- array( 'value' => 'Professionals in the field', 'default' => false ),
- array( 'value' => 'Potential customers', 'default' => false ),
- array( 'value' => 'Existing customers/users', 'default' => false ),
- array( 'value' => 'Industry peers / Experts', 'default' => false ),
- )
- ),
- 'tone' => array(
- 'category' => 'tone',
- 'question' => 'What tone should this content have?',
- 'type' => 'single_choice',
- 'options' => array(
- array( 'value' => 'Professional & Authoritative', 'default' => true ),
- array( 'value' => 'Friendly & Conversational', 'default' => false ),
- array( 'value' => 'Technical & Detailed', 'default' => false ),
- array( 'value' => 'Casual & Entertaining', 'default' => false ),
- array( 'value' => 'Formal & Academic', 'default' => false ),
- )
- ),
- 'content_depth' => array(
- 'category' => 'content_depth',
- 'question' => 'How comprehensive should this content be?',
- 'type' => 'single_choice',
- 'options' => array(
- array( 'value' => 'Quick overview (500-800 words)', 'default' => false ),
- array( 'value' => 'Standard guide (800-1500 words)', 'default' => true ),
- array( 'value' => 'Detailed analysis (1500-2500 words)', 'default' => false ),
- array( 'value' => 'Comprehensive deep-dive (2500+ words)', 'default' => false ),
- )
- ),
- 'expertise_level' => array(
- 'category' => 'expertise_level',
- 'question' => 'What is the target audience\'s expertise level?',
- 'type' => 'single_choice',
- 'options' => array(
- array( 'value' => 'Beginner - No prior knowledge', 'default' => true ),
- array( 'value' => 'Intermediate - Basic understanding', 'default' => false ),
- array( 'value' => 'Advanced - Deep technical knowledge', 'default' => false ),
- array( 'value' => 'Expert - Industry professional', 'default' => false ),
- )
- ),
- 'content_type' => array(
- 'category' => 'content_type',
- 'question' => 'What type of content works best for this topic?',
- 'type' => 'single_choice',
- 'options' => array(
- array( 'value' => 'Tutorial / How-to guide', 'default' => true ),
- array( 'value' => 'Opinion / Commentary', 'default' => false ),
- array( 'value' => 'Comparison / Review', 'default' => false ),
- array( 'value' => 'Listicle / Tips', 'default' => false ),
- array( 'value' => 'Case study', 'default' => false ),
- array( 'value' => 'News analysis', 'default' => false ),
- )
- ),
- 'pov' => array(
- 'category' => 'pov',
- 'question' => 'From what perspective should this be written?',
- 'type' => 'single_choice',
- 'options' => array(
- array( 'value' => 'Third person (objective, "it", "they")', 'default' => true ),
- array( 'value' => 'First person (personal, "I", "my")', 'default' => false ),
- array( 'value' => 'Expert voice (authoritative, experienced)', 'default' => false ),
- array( 'value' => 'Neutral / Unbiased', 'default' => false ),
- )
- ),
- );
-
- foreach ( $required_categories as $category ) {
- if ( isset( $question_templates[ $category ] ) ) {
- $q = $question_templates[ $category ];
- $q['id'] = 'q' . $question_id++;
- $questions[] = $q;
- }
- }
-
- return array(
- 'is_clear' => false,
- 'confidence' => 0.0,
- 'missing_categories' => $required_categories,
- 'questions' => $questions
- );
-}
-```
-
-**Update error handling (lines 1603-1615):**
-
-```php
-if ( is_wp_error( $response ) ) {
- // Log error
- error_log( 'WP Agentic Writer: Clarity check API error - ' . $response->get_error_message() );
- // Use default questions instead of skipping
- return $this->get_default_clarification_questions( $topic );
-}
-
-if ( null === $result ) {
- // Log parse error
- error_log( 'WP Agentic Writer: Failed to parse clarity check JSON' );
- // Use default questions instead of skipping
- return $this->get_default_clarification_questions( $topic );
-}
-```
-
----
-
-## Phase 4: Update Frontend Quiz Display
-
-### File: `assets/js/sidebar.js`
-
-**Enhancement 1: Add category labels to questions**
-
-Find the question rendering code and add category display:
-
-```javascript
-// Inside renderClarificationQuestion function
-const categoryLabels = {
- 'target_outcome': '🎯 Target Outcome',
- 'target_audience': '👥 Target Audience',
- 'tone': '🎨 Tone of Voice',
- 'content_depth': '📏 Content Depth',
- 'expertise_level': '📊 Expertise Level',
- 'content_type': '📝 Content Type',
- 'pov': '👁️ Point of View'
-};
-
-// Add category badge above question
-if (question.category && categoryLabels[question.category]) {
- html += '';
- html += categoryLabels[question.category];
- html += '
';
-}
-```
-
-**Enhancement 2: Show which categories are clear**
-
-Update progress display to show collected vs missing context:
-
-```javascript
-// Update progress display
-function updateClarificationProgress(total, current, clearCategories = []) {
- const progressEl = document.querySelector('.clarification-progress');
- if (!progressEl) return;
-
- let html = ``;
- html += `
Question ${current} of ${total}`;
-
- // Show what we already know
- if (clearCategories.length > 0) {
- html += `
`;
- html += `Already clear: `;
- html += clearCategories.map(cat => {
- const labels = {
- 'target_outcome': 'Goal',
- 'target_audience': 'Audience',
- 'tone': 'Tone',
- 'content_depth': 'Depth',
- 'expertise_level': 'Level',
- 'content_type': 'Format',
- 'pov': 'Perspective'
- };
- return labels[cat] || cat;
- }).join(', ');
- html += `
`;
- }
-
- html += `
`;
- html += ``;
-
- progressEl.innerHTML = html;
-}
-```
-
-**Enhancement 3: Add "Skip this question" option**
-
-```javascript
-// Add skip button to question card
-html += ``;
-
-// Handle skip
-document.addEventListener('click', (e) => {
- if (e.target.classList.contains('skip-question-btn')) {
- const questionId = e.target.dataset.questionId;
- skipQuestion(questionId);
- }
-});
-
-function skipQuestion(questionId) {
- // Mark as skipped with "Not applicable" value
- clarificationAnswers[questionId] = {
- skipped: true,
- value: 'Not applicable'
- };
- nextClarificationQuestion();
-}
-```
-
----
-
-## Phase 5: Pass Clarification Context to Plan Generation
-
-### File: `includes/class-gutenberg-sidebar.php`
-
-**Location:** Find `generate_plan` method (around line 900+)
-
-**Add clarification context integration:**
-
-```php
-// Before generating the plan, check if we have clarification answers
-$clarity_context = '';
-if ( ! empty( $params['clarificationAnswers'] ) && is_array( $params['clarificationAnswers'] ) ) {
- $clarity_context = "\n\n=== CONTEXT FROM CLARIFICATION QUIZ ===\n";
-
- // Group by category
- $grouped = array();
- foreach ( $params['clarificationAnswers'] as $answer ) {
- $category = $answer['category'] ?? 'other';
- $value = $answer['value'] ?? $answer['answer'] ?? '';
- $skipped = $answer['skipped'] ?? false;
-
- if ( ! $skipped && ! empty( $value ) ) {
- $grouped[ $category ] = $value;
- }
- }
-
- // Format for prompt
- $category_labels = array(
- 'target_outcome' => 'Primary Goal',
- 'target_audience' => 'Target Audience',
- 'tone' => 'Tone of Voice',
- 'content_depth' => 'Content Depth',
- 'expertise_level' => 'Expertise Level',
- 'content_type' => 'Content Type',
- 'pov' => 'Point of View',
- );
-
- foreach ( $grouped as $category => $value ) {
- $label = $category_labels[ $category ] ?? ucwords( str_replace( '_', ' ', $category ) );
- $clarity_context .= "- {$label}: {$value}\n";
- }
-
- $clarity_context .= "=== END CONTEXT ===\n";
-}
-
-// Add to planning prompt
-$plan_prompt = $clarity_context . "\n" . $plan_prompt;
-```
-
----
-
-## Phase 6: Testing Checklist
-
-### Manual Testing Steps:
-
-1. **Settings Page Test:**
- - Go to WP Agentic Writer settings
- - Verify new "Clarification Quiz" section appears
- - Test enable/disable toggle
- - Change confidence threshold to different values
- - Select/deselect required context categories
- - Save settings and verify they persist
-
-2. **Vague Topic Test:**
- - Enter very vague topic: "write about AI"
- - Verify quiz appears with all missing categories
- - Verify all questions have predefined options (no text inputs)
- - Answer all questions and verify plan reflects choices
-
-3. **Specific Topic Test:**
- - Enter detailed topic with all context
- - Verify quiz doesn't appear (or only asks for truly missing info)
- - Plan generation proceeds immediately
-
-4. **Threshold Test:**
- - Set threshold to 0.5 (very sensitive)
- - Enter semi-clear topic
- - Verify quiz appears
- - Set threshold to 0.9 (very strict)
- - Enter same topic
- - Verify quiz doesn't appear
-
-5. **Category Filter Test:**
- - Uncheck some categories in settings
- - Enter vague topic
- - Verify quiz only asks for checked categories
- - Unchecked categories are skipped
-
-6. **API Failure Test:**
- - Temporarily break API connection (invalid key)
- - Enter vague topic
- - Verify fallback questions appear
- - All categories show default predefined options
-
-7. **Skip Question Test:**
- - Start quiz
- - Click "Skip" on a question
- - Verify it moves to next question
- - Verify skipped answer marked as "Not applicable"
-
-8. **Plan Integration Test:**
- - Complete full quiz with specific answers
- - Generate plan
- - Verify plan reflects quiz answers (tone, audience, goal, etc.)
-
----
-
-## Success Criteria
-
-✅ Settings page has Clarification Quiz section with all 3 fields
-✅ Quiz triggers more frequently with 0.6 threshold (vs 0.8)
-✅ All quiz questions use predefined options (no open_text type)
-✅ Fallback questions appear when AI fails
-✅ Clarification answers appear in generated plan
-✅ Users can configure which categories are required
-✅ Users can enable/disable quiz entirely
-✅ Frontend shows category labels and progress
-✅ Can skip individual questions
-
----
-
-## Rollback Plan
-
-If issues occur:
-1. Revert `class-settings.php` changes (remove new settings)
-2. Revert system prompt to original (simple 3-criteria check)
-3. Revert threshold to hardcoded 0.8
-4. Revert fallback to original "assume clear" behavior
-
-Keep Git commits organized by phase for easy partial rollback.
-
----
-
-## Future Enhancements (Out of Scope)
-
-- Add custom question types via filters
-- Save quiz answers per user/site for faster future generations
-- A/B test different thresholds
-- Analytics on which categories are most often missing
-- Import/export context presets
-- Multi-language support for question options
diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md
deleted file mode 100644
index 9491e65..0000000
--- a/IMPLEMENTATION_PLAN.md
+++ /dev/null
@@ -1,1195 +0,0 @@
-# Context Management Implementation Plan
-
-**Date:** January 25, 2026
-**Version:** 0.1.3+ → 0.2.0
-**Status:** 📋 APPROVED - READY FOR IMPLEMENTATION
-
----
-
-## 📚 Approved Plans Summary
-
-### **1. CONTEXT_FLOW_ANALYSIS.md**
-
-**Key Findings:**
-- ✅ Analyzed 12 distinct user interaction flows
-- 🔴 Identified critical issues:
- - Chat history NOT sent to Writing mode
- - Writing mode notes ignored (don't update plan)
- - Block refinement missing context
- - Direct writing mode cannot execute (no plan)
-- ✅ Mapped all context storage mechanisms
-- ✅ Provided recommendations for fixes
-
-**Critical Issues to Fix:**
-
-| Issue | Severity | Impact |
-|-------|----------|--------|
-| Chat history not sent to Writing mode | 🔴 Critical | AI loses conversation context |
-| Writing mode notes ignored | 🔴 Critical | User instructions silently ignored |
-| Block refinement missing context | 🟡 Medium | AI doesn't understand original intent |
-| Direct writing mode fails | 🟡 Medium | Confusing UX, no error handling |
-
----
-
-### **2. AGENTIC_CONTEXT_STRATEGY.md**
-
-**Key Solutions:**
-- ✅ AI-powered context summarization (not hardcoded)
-- ✅ AI-powered intent detection (language-agnostic)
-- ✅ Cost-effective (~$0.0001 per summarization)
-- ✅ Seamless agentic UX (proactive suggestions)
-- ✅ Works in all languages (Indonesian, Arabic, Chinese, etc.)
-
-**Core Philosophy:**
-> "If AI is smart enough to write articles, it's smart enough to manage its own context."
-
-**New Actions:**
-
-| Action | Purpose | Cost | When |
-|--------|---------|------|------|
-| `summarize_context` | Condense chat history | $0.0001 | Before outline (if chat > 6 msgs) |
-| `detect_intent` | Understand user's next step | $0.00002 | After each user message |
-
----
-
-## 🎯 Implementation Goals
-
-### **Primary Objectives**
-
-1. **Fix Context Loss Issues**
- - Send chat history to ALL endpoints
- - Include context in block refinement
- - Handle writing mode properly
-
-2. **Implement Agentic Context Management**
- - AI-powered summarization
- - AI-powered intent detection
- - Language-agnostic (no hardcoded keywords)
-
-3. **Enhance User Experience**
- - Proactive action suggestions
- - Seamless mode transitions
- - Transparent context operations
-
-4. **Maintain Cost Efficiency**
- - Total added cost: ~$0.34/month for 100 articles
- - 76% token reduction vs full history
- - Track all costs transparently
-
----
-
-## 📋 Implementation Phases
-
-### **Phase 1: Critical Fixes** (Priority: 🔴 HIGH)
-
-**Goal:** Fix context loss issues identified in CONTEXT_FLOW_ANALYSIS.md
-
-#### **1.1 Send Chat History Everywhere**
-
-**Files to Modify:**
-- `assets/js/sidebar.js`
-
-**Changes:**
-
-```javascript
-// In ALL API request payloads, add chatHistory
-const basePayload = {
- messages: messages,
- postId: postId,
- chatHistory: messages.filter(m => m.role !== 'system'), // ✅ Add this
- postConfig: postConfig,
- type: agentMode
-};
-
-// Apply to:
-// - handleExecuteArticle() → /execute-article
-// - handleRefineBlock() → /refine-block
-// - handleGenerateMeta() → /generate-meta
-// - Any other endpoints that don't currently send chatHistory
-```
-
-**Backend Files to Modify:**
-- `includes/class-gutenberg-sidebar.php`
-
-**Changes:**
-
-```php
-// In handle_execute_article()
-$chat_history = $params['chatHistory'] ?? array();
-if (!empty($chat_history)) {
- $chat_history_context = $this->build_chat_history_context($chat_history);
- // Append to system prompt
-}
-
-// In handle_refine_block()
-$chat_history = $params['chatHistory'] ?? array();
-$plan = get_post_meta($post_id, '_wpaw_plan', true);
-// Include both in refinement context
-
-// In handle_generate_meta()
-$chat_history = $params['chatHistory'] ?? array();
-// Include for better meta description context
-```
-
-**Testing:**
-- [ ] Test Chat → Writing mode (verify context preserved)
-- [ ] Test block refinement (verify original intent understood)
-- [ ] Test meta generation (verify context used)
-
-**Estimated Time:** 2-3 hours
-
----
-
-#### **1.2 Handle Writing Mode Properly**
-
-**Problem:** User can switch to Writing mode without a plan, then cannot execute.
-
-**Solution:** Show clear guidance and prevent confusion.
-
-**Files to Modify:**
-- `assets/js/sidebar.js`
-
-**Changes:**
-
-```javascript
-// In renderWritingMode()
-const renderWritingModeContent = () => {
- if (!currentPlan) {
- return (
-
-
-
📝
-
No Outline Yet
-
Writing mode requires an outline to structure your article.
-
-
- Or switch to to discuss your ideas.
-
-
-
- );
- }
-
- // Normal writing mode UI...
-};
-
-// In handleExecuteArticle()
-if (!currentPlan) {
- showError('Please create an outline first. Switch to Planning mode.');
- return;
-}
-```
-
-**CSS to Add:**
-- `assets/css/sidebar.css`
-
-```css
-.writing-mode-empty {
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: 300px;
-}
-
-.empty-state {
- text-align: center;
- max-width: 400px;
- padding: 2rem;
-}
-
-.empty-state .icon {
- font-size: 3rem;
- display: block;
- margin-bottom: 1rem;
-}
-
-.empty-state h3 {
- margin: 0 0 0.5rem 0;
- font-size: 1.5rem;
-}
-
-.empty-state p {
- color: #666;
- margin: 0.5rem 0;
-}
-
-.empty-state .hint {
- font-size: 0.9rem;
- margin-top: 1rem;
-}
-```
-
-**Testing:**
-- [ ] Test switching to Writing mode without plan
-- [ ] Verify clear guidance shown
-- [ ] Test "Create Outline First" button
-- [ ] Test switching back to Chat mode
-
-**Estimated Time:** 1-2 hours
-
----
-
-#### **1.3 Handle Writing Mode Notes**
-
-**Problem:** User adds notes in Writing mode, but notes don't update the plan.
-
-**Solution:** Either update plan or show clear warning.
-
-**Recommended Approach:** Show warning (simpler, clearer UX)
-
-**Files to Modify:**
-- `assets/js/sidebar.js`
-
-**Changes:**
-
-```javascript
-// In Writing mode, when user sends a message
-const handleWritingModeMessage = async (userMessage) => {
- // Show info message
- addSystemMessage(
- '💡 Note: To modify the outline, switch to Planning mode. ' +
- 'Writing mode messages are for discussion only.'
- );
-
- // Still send to chat endpoint for conversation
- await sendChatMessage(userMessage);
-};
-
-// Add mode indicator in input area
-const renderInputArea = () => {
- return (
-
- {agentMode === 'writing' && currentPlan && (
-
- 💬 Chat mode active. To modify outline, switch to Planning mode.
-
- )}
-
-
- );
-};
-```
-
-**Alternative Approach (Advanced):** Auto-update plan
-- Detect if message is requesting plan changes
-- Send to `/update-plan` endpoint
-- Regenerate plan with modifications
-- More complex, implement in Phase 3
-
-**Testing:**
-- [ ] Test adding notes in Writing mode
-- [ ] Verify warning shown
-- [ ] Verify notes don't silently fail
-
-**Estimated Time:** 1 hour
-
----
-
-### **Phase 2: Agentic Infrastructure** (Priority: 🟡 MEDIUM)
-
-**Goal:** Implement AI-powered context management from AGENTIC_CONTEXT_STRATEGY.md
-
-#### **2.1 Backend: Add Summarization Endpoint**
-
-**Files to Modify:**
-- `includes/class-gutenberg-sidebar.php`
-
-**New Endpoint:**
-
-```php
-/**
- * Register summarize-context endpoint.
- */
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/summarize-context',
- array(
- 'methods' => 'POST',
- 'callback' => array($this, 'handle_summarize_context'),
- 'permission_callback' => array($this, 'check_permissions'),
- )
-);
-
-/**
- * Handle context summarization request.
- *
- * @param WP_REST_Request $request REST request.
- * @return WP_REST_Response|WP_Error Response.
- */
-public function handle_summarize_context($request) {
- $params = $request->get_json_params();
- $chat_history = $params['chatHistory'] ?? array();
- $post_id = $params['postId'] ?? 0;
-
- // Short history doesn't need summarization
- if (empty($chat_history) || count($chat_history) < 4) {
- return new WP_REST_Response(
- array(
- 'summary' => '',
- 'use_full_history' => true,
- 'cost' => 0,
- ),
- 200
- );
- }
-
- // Build history text
- $history_text = '';
- foreach ($chat_history as $msg) {
- $role = ucfirst($msg['role'] ?? 'Unknown');
- $content = $msg['content'] ?? '';
- $history_text .= "{$role}: {$content}\n\n";
- }
-
- // Build summarization prompt
- $prompt = "Summarize this conversation into key points that capture the user's intent and requirements.
-
-Focus on:
-- Main topic
-- Specific focus areas
-- Rejected/excluded topics
-- User preferences (tone, audience, etc.)
-
-Keep the summary concise (max 200 words) but preserve critical context.
-Write in the same language as the conversation.
-
-Output format:
-TOPIC: [main topic]
-FOCUS: [what to include]
-EXCLUDE: [what to avoid]
-PREFERENCES: [any specific requirements]
-
-Conversation:
-{$history_text}";
-
- // Call AI with cheap model
- $provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
- $messages = array(
- array(
- 'role' => 'user',
- 'content' => $prompt,
- ),
- );
-
- $response = $provider->chat($messages, array(), 'summarize');
-
- if (is_wp_error($response)) {
- return $response;
- }
-
- // Track cost
- do_action(
- 'wp_aw_after_api_request',
- $post_id,
- $response['model'] ?? '',
- 'summarize_context',
- $response['input_tokens'] ?? 0,
- $response['output_tokens'] ?? 0,
- $response['cost'] ?? 0
- );
-
- return new WP_REST_Response(
- array(
- 'summary' => $response['content'] ?? '',
- 'use_full_history' => false,
- 'cost' => $response['cost'] ?? 0,
- 'tokens_saved' => count($chat_history) * 500 - ($response['output_tokens'] ?? 0),
- ),
- 200
- );
-}
-```
-
-**Testing:**
-- [ ] Test with short history (< 4 messages) → returns use_full_history
-- [ ] Test with long history (> 6 messages) → returns summary
-- [ ] Test in multiple languages (English, Indonesian)
-- [ ] Verify cost tracking
-
-**Estimated Time:** 2-3 hours
-
----
-
-#### **2.2 Backend: Add Intent Detection Endpoint**
-
-**Files to Modify:**
-- `includes/class-gutenberg-sidebar.php`
-
-**New Endpoint:**
-
-```php
-/**
- * Register detect-intent endpoint.
- */
-register_rest_route(
- 'wp-agentic-writer/v1',
- '/detect-intent',
- array(
- 'methods' => 'POST',
- 'callback' => array($this, 'handle_detect_intent'),
- 'permission_callback' => array($this, 'check_permissions'),
- )
-);
-
-/**
- * Handle intent detection request.
- *
- * @param WP_REST_Request $request REST request.
- * @return WP_REST_Response|WP_Error Response.
- */
-public function handle_detect_intent($request) {
- $params = $request->get_json_params();
- $last_message = $params['lastMessage'] ?? '';
- $has_plan = $params['hasPlan'] ?? false;
- $current_mode = $params['currentMode'] ?? 'chat';
- $post_id = $params['postId'] ?? 0;
-
- if (empty($last_message)) {
- return new WP_REST_Response(
- array('intent' => 'continue_chat'),
- 200
- );
- }
-
- // Build intent detection prompt
- $prompt = "Based on the user's message, determine their intent. Choose ONE:
-
-1. \"create_outline\" - User wants to create an article outline/structure
-2. \"start_writing\" - User wants to write the full article
-3. \"refine_content\" - User wants to improve existing content
-4. \"continue_chat\" - User wants to continue discussing/exploring
-5. \"clarify\" - User is asking questions or needs clarification
-
-Consider:
-- The user's explicit request
-- Whether they have an outline already (has_plan: " . ($has_plan ? 'true' : 'false') . ")
-- Current mode (current_mode: {$current_mode})
-
-User's message: \"{$last_message}\"
-
-Respond with ONLY the intent code (e.g., \"create_outline\"). No explanation.";
-
- // Call AI with cheap model
- $provider = WP_Agentic_Writer_OpenRouter_Provider::get_instance();
- $messages = array(
- array(
- 'role' => 'user',
- 'content' => $prompt,
- ),
- );
-
- $response = $provider->chat($messages, array(), 'intent_detection');
-
- if (is_wp_error($response)) {
- return $response;
- }
-
- // Track cost
- do_action(
- 'wp_aw_after_api_request',
- $post_id,
- $response['model'] ?? '',
- 'detect_intent',
- $response['input_tokens'] ?? 0,
- $response['output_tokens'] ?? 0,
- $response['cost'] ?? 0
- );
-
- // Clean up response
- $intent = trim(strtolower($response['content'] ?? 'continue_chat'));
- $intent = str_replace('"', '', $intent); // Remove quotes if present
-
- // Validate intent
- $valid_intents = array('create_outline', 'start_writing', 'refine_content', 'continue_chat', 'clarify');
- if (!in_array($intent, $valid_intents)) {
- $intent = 'continue_chat';
- }
-
- return new WP_REST_Response(
- array(
- 'intent' => $intent,
- 'cost' => $response['cost'] ?? 0,
- ),
- 200
- );
-}
-```
-
-**Testing:**
-- [ ] Test with "create outline" messages (various languages)
-- [ ] Test with "write article" messages
-- [ ] Test with questions/clarifications
-- [ ] Verify correct intent returned
-- [ ] Verify cost tracking
-
-**Estimated Time:** 2-3 hours
-
----
-
-#### **2.3 Backend: Update Cost Tracking**
-
-**Files to Modify:**
-- `includes/class-cost-tracker.php`
-
-**Changes:**
-
-```php
-// Add new operation types
-private function get_operation_label($operation) {
- $labels = array(
- 'chat' => 'Chat',
- 'planning' => 'Planning',
- 'execution' => 'Article Writing',
- 'refinement' => 'Block Refinement',
- 'meta_description' => 'Meta Description',
- 'keyword_suggestion' => 'Keyword Suggestion',
- 'web_search' => 'Web Search',
- 'summarize_context' => 'Context Summarization', // ✅ New
- 'detect_intent' => 'Intent Detection', // ✅ New
- );
-
- return $labels[$operation] ?? ucfirst($operation);
-}
-```
-
-**Testing:**
-- [ ] Verify new operations tracked in cost table
-- [ ] Verify cost breakdown shows summarization/intent costs
-- [ ] Test cost report includes new operations
-
-**Estimated Time:** 30 minutes
-
----
-
-#### **2.4 Frontend: Implement Summarization**
-
-**Files to Modify:**
-- `assets/js/sidebar.js`
-
-**New Functions:**
-
-```javascript
-/**
- * Summarize chat history using AI.
- *
- * @param {Array} chatHistory - Full chat history.
- * @returns {Promise