# WP Agentic Writer – Fix Summary: Chat & Frontend Build

**Date**: 2026-06-16 (original) / 2026-06-17 (updates)
**Status**: 🟢 RESOLVED

This document serves as a hands-off record of the debugging steps, root causes, and fixes applied to resolve the "empty chat response" issue and establish a proper frontend build pipeline.

---

## Updates (2026-06-17)

### Additional Backend Improvements

1. **Connection Test Caching** - Already existed in `class-provider-manager.php` (5-min TTL via transients)
2. **Cache Auto-Clear on Settings Save** - Added to `class-settings-v2.php`
   - Hooks to `updated_option` action
   - Clears connection test cache when local backend settings change
3. **Reasoning Content Parsing** - Added to `class-local-backend-provider.php`
   - Captures `reasoning_content` from thinking models
   - Debug logging included

### Build Validation ✅

| Check | Result |
|-------|--------|
| `npm run build` | ✅ Passes |
| PHP syntax (all files) | ✅ Passes |
| Build output | `dist/sidebar.js` (169 KB) |

### Important: Two sidebar.js Files

| File | Loaded by PHP? |
|------|----------------|
| `assets/js/sidebar.js` (438 KB) | ❌ Legacy, NOT loaded |
| `assets/js/dist/sidebar.js` (169 KB) | ✅ Current, loaded |

---

## Original Fixes (2026-06-16)

---

## 1. Frontend Build Pipeline Established

**Problem**: 
The PHP plugin explicitly loads `assets/js/dist/sidebar.js`. However, ongoing refactoring work was occurring in `assets/js/src/index.jsx`. Because there was no active build process, changes made in `index.jsx` were not reflecting in the application.

**Solution**:
*   Created `package.json` with `esbuild` to handle fast JSX compilation.
*   Added `scripts/build.js` configured specifically for WordPress Gutenberg (using `wp.element.createElement` and `wp.element.Fragment`).
*   **Critical Fix**: Ensured the esbuild configuration wraps the output in an anonymous IIFE (`format: "iife"`) *without* defining a `globalName: "wp"`. A named global would have caused the compiled script to overwrite WordPress's native `window.wp` object with `undefined`, breaking the editor.

**Usage**:
*   Run `npm run build` to compile `src/index.jsx` -> `dist/sidebar.js`.
*   Run `npm run build:watch` during active development.

---

## 2. Backend Fix: PHP Fatal Error on Connection Test

**Problem**: 
When the local backend provider received an HTTP 4xx/5xx error (e.g., when trying to test a connection to a rate-limited or failing model), the entire REST request crashed, resulting in a 500 server error and breaking the chat flow entirely.

**Root Cause**:
In `includes/class-local-backend-provider.php` (line 882), a double-quoted string was used for a `sprintf` format:
`__("API Error (HTTP %1$d): %2$s", "wp-agentic-writer")`
Because it was double-quoted, PHP attempted to interpolate `$d` and `$s` as variables, resolving them to empty strings. The resulting string `API Error (HTTP %1): %2` caused `sprintf` to throw a fatal `ValueError: Unknown format specifier ")"`.

**Fix**:
Changed the double quotes to single quotes to prevent PHP variable interpolation, preserving the intended positional specifiers:
`__('API Error (HTTP %1$d): %2$s', "wp-agentic-writer")`
*Scanned the rest of the codebase and confirmed this dangerous pattern does not exist anywhere else.*

---

## 3. Backend Fix: Agentic Models Returning "Empty Responses"

**Problem**:
The user experienced intermittent "empty chat response" errors even when the API connection was successful (HTTP 200). 

**Root Cause**:
The configured models (e.g., `dough/kr/claude-sonnet-4.5-thinking` and `ag/gemini-3-flash-agent`) are **agentic/tool-calling** models. When fed a large WordPress system prompt asking for plain prose, these models burned all their tokens on internal "reasoning", attempted to emit a function/tool call, failed (`finish_reason: "malformed_function_call"`), and returned **zero text content**.
Because the streaming buffer received no content, it fell back to non-streaming, which also yielded zero content, triggering a generic "empty response" error.

**Fix**:
1.  **Better Error Surfacing**: Updated the streaming and fallback logic in `class-local-backend-provider.php` to actively capture the `finish_reason` payload.
2.  If the provider returns empty content but has a finish reason of `malformed_function_call`, `tool_calls`, or `function_call`, the backend now intercepts this and throws a highly specific, actionable error:
    > *"The selected model [Model Name] returned no text (finish reason: tool/function call). This usually means an agentic/coding model is being used for prose. Choose a standard chat model (without an -agent or -agentic suffix) in Settings."*
3.  **Config Alignment**: Used WP-CLI to update the WordPress options table, switching the local backend models from the agentic variants to the standard `gemini/gemini-3-flash-preview` for all prose tasks (`chat`, `writing`, `planning`, etc.).

---

## Summary of Touched Files
*   `package.json` (New)
*   `scripts/build.js` (New)
*   `assets/js/dist/sidebar.js` (Rebuilt)
*   `includes/class-local-backend-provider.php` (Fixed string interpolation, added `finish_reason` edge-case handling, added error payload parsing).

The chat functionality is now robust, gracefully handles agentic model failures, and the React frontend can be reliably compiled from `index.jsx`.

---

## 4. Next Recommendations

With the frontend build pipeline established and the critical backend crashes resolved, the foundation is stable. Here are the recommended next steps:

1. **Complete the React File Splitting (Refactor Phase 2)** ⚠️ IN PROGRESS
   * Now that `index.jsx` compiles successfully to `dist/sidebar.js`, the massive 11,000+ line `index.jsx` should be split into modular React components.
   * **See `FRONTEND-REFACTOR-PHASE2.md` for the detailed modularization plan.**
   * The new `esbuild` setup natively supports resolving local imports, meaning you can safely extract components into a `src/components/` directory and import them into `index.jsx` without changing the PHP backend.
   * **Key clarification**: The source is `src/index.jsx`, which compiles to `dist/sidebar.js`. We are NOT creating a new `sidebar.jsx` source file - we are modularizing the existing `index.jsx`.

2. **Optimize `test_connection()` in the Provider Manager** ✅ COMPLETED
   * Implemented connection test caching using WordPress transients with 5-minute TTL in `class-provider-manager.php`.
   * Added automatic cache clearing in `class-settings-v2.php` when local backend settings are saved (URL, API key, model changes).
   * This eliminates redundant connection tests on every chat request, significantly reducing latency.

3. **Handle Reasoning Tokens for Thinking Models** ✅ COMPLETED
   * Added `reasoning_content` parsing to `chat_stream()` method in `class-local-backend-provider.php`.
   * The streaming parser now captures `chunk["choices"][0]["delta"]["reasoning_content"]` from thinking models like Claude extended thinking.
   * Reasoning content is passed through the callback so the frontend can optionally display it in a collapsible section.
   * Debug logging added to help identify when reasoning chunks are received.