diff --git a/plugins/speculation-rules/hooks.php b/plugins/speculation-rules/hooks.php
index fa478b9843..43bf5f1b9b 100644
--- a/plugins/speculation-rules/hooks.php
+++ b/plugins/speculation-rules/hooks.php
@@ -38,3 +38,21 @@ function plsr_render_generator_meta_tag(): void {
echo '' . "\n";
}
add_action( 'wp_head', 'plsr_render_generator_meta_tag' );
+
+/**
+ * Load the predict.js script which will uses on-device AI to predict links users are most likely to visit for prerendering.
+ *
+ * @since n.e.x.t
+ */
+function plsr_load_predict_script(): void {
+ wp_enqueue_script(
+ 'plsr-predict',
+ plugin_dir_url( __FILE__ ) . 'predict.js', // @todo switch to build version.
+ array(),
+ SPECULATION_RULES_VERSION,
+ array(
+ 'strategy' => 'defer',
+ )
+ );
+}
+add_action( 'wp_enqueue_scripts', 'plsr_load_predict_script' );
diff --git a/plugins/speculation-rules/predict.js b/plugins/speculation-rules/predict.js
new file mode 100644
index 0000000000..3e1306032a
--- /dev/null
+++ b/plugins/speculation-rules/predict.js
@@ -0,0 +1,97 @@
+( async () => {
+ // Start the AI engine.
+ // eslint-disable-next-line no-console -- For testing only.
+ console.log( 'Starting...' );
+
+ async function predictLinks() {
+ const session = await window.ai.assistant.create();
+
+ const body = document.getElementsByTagName( 'body' )[ 0 ].innerHTML;
+
+ //const prompt = `Predict the five links users are most likely to visit on this page, returning ONLY the 5 full urls as a JSON object: ${ body }`;
+ // const prompt = `Given a web page's HTML, find the links and predict which is most likely to be clicked by a user. Return the top 5 links as a JSON object. Only return the JSON object as your complete answer. Here is the HTML: ${ body }`;
+ const prompt = `In order to prerender links so users get instant navigations, can you predict the three links users are most likely to visit on this page, returning ONLY the 3 full urls as a JSON object in the format ['url','url2','url3']. Here is the HTML: ${ body }`;
+
+ // eslint-disable-next-line no-console -- For testing only.
+ console.log( `The size of the prompt is ${ prompt.length }.` );
+
+ let result = false;
+ try {
+ result = await session.prompt( prompt );
+ } catch ( error ) {
+ // eslint-disable-next-line no-console -- For testing only.
+ console.error( error );
+ return;
+ }
+
+ if ( ! result ) {
+ // eslint-disable-next-line no-console -- For testing only.
+ console.log( 'No result.' );
+ return;
+ }
+
+ // Log result so far
+ // eslint-disable-next-line no-console -- For testing only.
+ console.log( result );
+
+ // Grab everything after "Output:" or "```json" strings etc...
+ const output =
+ result.split( 'Output:' )[ 1 ] ||
+ result.split( '```json' )[ 1 ] ||
+ result.split( 'Answer:' )[ 1 ] ||
+ result.split( 'Solution:' )[ 1 ];
+
+ // If there is no output, return.
+ if ( ! output ) {
+ // eslint-disable-next-line no-console -- For testing only.
+ console.log( 'No output.' );
+ return;
+ }
+
+ // Remove the two "```" formatting strings.
+ result = output.replace( /```JSON/g, '' );
+ result = output.replace( /```/g, '' );
+
+ // Remove any newlines.
+ result = result.replace( /\n/g, '' );
+
+ // Remove any whitespace.
+ result = result.replace( / /g, '' );
+
+ // eslint-disable-next-line no-console -- For testing only.
+ console.log( result );
+
+ // Add a prerender link for each URL using the Speculation Rules API
+ const resultData = JSON.parse( result );
+
+ for ( const link of resultData.links ) {
+ // eslint-disable-next-line no-console -- For testing only.
+ console.log( `Link: ${ link }` );
+ /**
+ * Add speculation rules API prerendering.
+ *
+ * It will be something like this:
+ *
+ *
+ */
+ const prerenderLink = document.createElement( 'link' );
+ prerenderLink.type = 'speculationrules';
+ const rules =
+ '{ "prerender": [ { "where": { "href_matches": "URL" }, "eagerness": "moderate" }] }';
+ prerenderLink.textContent = rules.replace( 'URL', link.href );
+ document.head.appendChild( prerenderLink );
+
+ // eslint-disable-next-line no-console -- For testing only.
+ console.log( `Prerendering link: ${ link }` );
+ }
+ }
+ await predictLinks();
+} )();