fix: tolerate markdown-fenced JSON from LLM responses (v0.4.3)

Models like GPT 5.1 Nano ignore response_format: json_object and wrap
their JSON in ```json fences or add preamble text. New Json_Extractor
utility tries: (1) direct decode, (2) strip markdown fences, (3) find
outermost { ... } substring. Applied to analyzer and chief editor
parsers. Raw response logged on parse failure for debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
peptiderepo
2026-04-19 15:40:37 +07:00
parent 3e1e5efe09
commit 65560ea0b5
5 changed files with 78 additions and 4 deletions

View File

@@ -12,6 +12,7 @@ declare(strict_types=1);
* Dependencies: LLM_Provider_Interface, Cost_Tracker.
*
* @see core/class-content-generator.php — Produces the content we review.
* @see core/class-json-extractor.php — Tolerant JSON parsing for LLM output.
* @see core/class-publisher.php — Publishes approved content.
* @see ARCHITECTURE.md — Data flow step 5.
*/
@@ -145,10 +146,11 @@ class PRAutoBlogger_Chief_Editor {
* @return PRAutoBlogger_Editorial_Review
*/
private function parse_review_response( string $content ): PRAutoBlogger_Editorial_Review {
$data = json_decode( $content, true );
$data = PRAutoBlogger_Json_Extractor::decode( $content );
if ( ! is_array( $data ) || ! isset( $data['verdict'] ) ) {
PRAutoBlogger_Logger::instance()->error( 'Chief editor response was not valid JSON. Defaulting to rejected.', 'editor' );
PRAutoBlogger_Logger::instance()->debug( 'Raw editor response: ' . mb_substr( $content, 0, 500 ), 'editor' );
return new PRAutoBlogger_Editorial_Review( [
'verdict' => 'rejected',
'notes' => 'Editor response could not be parsed.',