Files
wp-agentic-writer/REMAINING_IMPLEMENTATION.md
2026-01-28 00:26:00 +07:00

10 KiB

Remaining Implementation Code

This document contains all code snippets that need to be implemented for Phases 1.2, 1.3, 2, and 3.


Phase 1.2: Writing Mode Empty State (Frontend - sidebar.js)

Location: Add before the main render return statement

// Check if Writing mode needs empty state
const shouldShowWritingEmptyState = () => {
    return agentMode === 'writing' && !currentPlanRef.current;
};

// Render Writing mode empty state
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.'
            )
        )
    );
};

Location: In handleExecuteArticle function, add at the beginning:

// Check if plan exists
if (!currentPlanRef.current) {
    setMessages(prev => [...prev, {
        role: 'system',
        type: 'error',
        content: 'Please create an outline first. Switch to Planning mode to get started.'
    }]);
    setIsLoading(false);
    return;
}

Phase 1.2: CSS for Empty State (sidebar.css)

.wpaw-writing-empty-state {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 300px;
    padding: 2rem;
}

.wpaw-empty-state-content {
    text-align: center;
    max-width: 400px;
}

.wpaw-empty-state-icon {
    font-size: 3rem;
    display: block;
    margin-bottom: 1rem;
}

.wpaw-empty-state-content h3 {
    margin: 0 0 0.5rem 0;
    font-size: 1.5rem;
    color: #1e1e1e;
}

.wpaw-empty-state-content p {
    color: #666;
    margin: 0.5rem 0;
    line-height: 1.5;
}

.wpaw-empty-state-button {
    margin: 1.5rem 0 1rem 0 !important;
}

.wpaw-empty-state-hint {
    font-size: 0.9rem;
    margin-top: 1rem !important;
}

.wpaw-link-button {
    background: none;
    border: none;
    color: #2271b1;
    text-decoration: underline;
    cursor: pointer;
    padding: 0;
    font: inherit;
}

.wpaw-link-button:hover {
    color: #135e96;
}

Phase 1.3: Writing Mode Notes Warning (sidebar.js)

Location: In the message sending logic, add check for Writing mode:

// Add this check before sending message
if (agentMode === 'writing' && currentPlanRef.current) {
    // Show info about notes in writing mode
    setMessages(prev => [...prev, 
        { role: 'user', content: userMessage },
        {
            role: 'system',
            type: 'info',
            content: '💡 Note: To modify the outline, switch to Planning mode. Writing mode messages are for discussion only.'
        }
    ]);
}

Phase 2.1: Summarize-Context Endpoint (class-gutenberg-sidebar.php)

Location: In register_routes() method, add:

register_rest_route(
    'wp-agentic-writer/v1',
    '/summarize-context',
    array(
        'methods' => 'POST',
        'callback' => array( $this, 'handle_summarize_context' ),
        'permission_callback' => array( $this, 'check_permissions' ),
    )
);

Location: Add new method:

/**
 * 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,
                'tokens_saved' => 0,
            ),
            200
        );
    }
    
    // Build history text
    $history_text = '';
    foreach ( $chat_history as $msg ) {
        $role = ucfirst( $msg['role'] ?? 'Unknown' );
        $content = $msg['content'] ?? '';
        if ( ! empty( $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;
    }
    
    // Calculate tokens saved
    $original_tokens = count( $chat_history ) * 500; // Rough estimate
    $summary_tokens = $response['output_tokens'] ?? 100;
    $tokens_saved = $original_tokens - $summary_tokens;
    
    // 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' => $tokens_saved,
        ),
        200
    );
}

Phase 2.2: Detect-Intent Endpoint (class-gutenberg-sidebar.php)

Location: In register_routes() method, add:

register_rest_route(
    'wp-agentic-writer/v1',
    '/detect-intent',
    array(
        'methods' => 'POST',
        'callback' => array( $this, 'handle_detect_intent' ),
        'permission_callback' => array( $this, 'check_permissions' ),
    )
);

Location: Add new method:

/**
 * 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 );
    
    // 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
    );
}

Phase 2.3: Update Cost Tracking (class-cost-tracker.php)

Location: In get_operation_label() method, update the labels array:

$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
);

This document contains the core implementation code. The actual integration requires careful placement in the existing codebase structure.