Files
wp-agentic-writer/FRONTEND_AND_CHAT_FIX_SUMMARY.md
Dwindi Ramadhana d3f142222c feat: Add connection test caching and reasoning content support
Backend improvements:
- Add cache auto-clear on settings save (class-settings-v2.php)
  - Hooks updated_option action
  - Clears connection test transients when local backend settings change
- Add reasoning_content streaming support (class-local-backend-provider.php)
  - Handles thinking models like Claude extended thinking
  - Captures chunk['choices'][0]['delta']['reasoning_content']

Documentation:
- Add FRONTEND_AND_CHAT_FIX_SUMMARY.md with all fixes
- Add FRONTEND-REFACTOR-PHASE2.md with modularization plan

Note: Splitting effort deferred - will continue iterating on monolith
Next: Fix session history not appearing bug
2026-06-17 05:26:12 +07:00

122 lines
7.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.