prefix . SA_ORCH_DB_PREFIX . 'token_log'; } /** * Record one LLM invocation. Returns the new row id, or 0 on failure. * * @param string $provider e.g. 'openai' * @param string $model e.g. 'gpt-4o-mini' * @param array $usage [ prompt_tokens, completion_tokens, total_tokens ] * @param int $user_id the WP user_id who triggered the call (or 0) */ public static function record( string $provider, string $model, array $usage, int $user_id = 0 ): int { if ( $provider === '' ) return 0; global $wpdb; $ok = $wpdb->insert( self::table(), [ 'user_id' => $user_id > 0 ? $user_id : null, 'provider' => $provider, 'model' => $model, 'prompt_tokens' => isset( $usage['prompt_tokens'] ) ? (int) $usage['prompt_tokens'] : 0, 'completion_tokens' => isset( $usage['completion_tokens'] ) ? (int) $usage['completion_tokens'] : 0, 'total_tokens' => isset( $usage['total_tokens'] ) ? (int) $usage['total_tokens'] : 0, 'comment_kind' => null, 'comment_id' => null, 'invoked_at' => current_time( 'mysql', true ), ] ); return $ok !== false ? (int) $wpdb->insert_id : 0; } /** * Link a previously-recorded token row to the comment it produced. * Called by the future invocation surface when an actor-attributed * comment is committed from a Sara draft. * * Idempotent on the row's identity — re-linking just updates the row. */ public static function link_to_comment( int $log_id, string $kind, int $comment_id ): bool { if ( $log_id <= 0 || $comment_id <= 0 ) return false; $kind = sanitize_key( $kind ); if ( $kind === '' ) return false; global $wpdb; $ok = $wpdb->update( self::table(), [ 'comment_kind' => $kind, 'comment_id' => $comment_id, ], [ 'id' => $log_id ] ); return $ok !== false; } /** * Filter callback for Board #23's 'sa_orch_handoff_has_llm_token'. * Returns true if at least one token row is linked to (kind, comment_id), * false otherwise. Always deterministic — no nulls. */ public static function has_token_for_comment( string $kind, int $comment_id ): bool { if ( $comment_id <= 0 ) return false; $kind = sanitize_key( $kind ); if ( $kind === '' ) return false; global $wpdb; $count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM " . self::table() . " WHERE comment_kind = %s AND comment_id = %d", $kind, $comment_id ) ); return $count > 0; } /** * Bridge to the Board #23 hook. Hooked at plugin load via add_filter. * Replaces the default 'unknown' (null) with a deterministic boolean. * * @param mixed $default The default value (typically null). * @param string $kind Comment kind constant. * @param int $comment_id Comment id. * @return bool */ public static function answer_handoff_filter( $default, string $kind, int $comment_id ): bool { return self::has_token_for_comment( $kind, $comment_id ); } }