'POST', 'callback' => [ __CLASS__, 'invoke' ], 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, 'args' => [ 'surface' => [ 'type' => 'string', 'required' => false ], 'ref' => [ 'type' => 'string', 'required' => false ], 'page' => [ 'type' => 'string', 'required' => false ], 'prompt' => [ 'type' => 'string', 'required' => true ], 'history' => [ 'type' => 'array', 'required' => false ], 'asterion_file' => [ 'type' => 'string', 'required' => false ], // Board #28 ], ] ); } public static function invoke( WP_REST_Request $request ) { $surface = sanitize_text_field( (string) $request->get_param( 'surface' ) ); $ref = sanitize_text_field( (string) $request->get_param( 'ref' ) ); $page = sanitize_text_field( (string) $request->get_param( 'page' ) ); $prompt = (string) $request->get_param( 'prompt' ); $asterion_file = sanitize_text_field( (string) $request->get_param( 'asterion_file' ) ); $history = $request->get_param( 'history' ); if ( ! is_array( $history ) ) { $history = []; } if ( trim( $prompt ) === '' ) { return new WP_REST_Response( [ 'error' => 'empty_prompt', 'message' => 'prompt is required', ], 400 ); } $context = [ 'surface' => $surface !== '' ? $surface : null, 'ref' => $ref !== '' ? $ref : null, ]; $result = SA_Orch_Sara_Service::invoke( $context, $prompt, $history, $page, $asterion_file ); if ( is_wp_error( $result ) ) { return new WP_REST_Response( [ 'error' => $result->get_error_code(), 'message' => $result->get_error_message(), ], 502 ); } // Service now returns a wrapping shape: { response, usage, log_id }. // Pass the structured response through as-is for backward-compat with // the existing JS contract; surface usage + log_id alongside for Board #16. return new WP_REST_Response( [ 'response' => $result['response'], 'usage' => $result['usage'] ?? null, 'log_id' => $result['log_id'] ?? null, 'context' => $context, 'page' => $page !== '' ? $page : null, 'turn' => count( $history ) / 2 + 1, // 1-indexed turn number for UI feedback ], 200 ); } }