{"id":31923,"date":"2025-06-27T12:53:07","date_gmt":"2025-06-27T17:53:07","guid":{"rendered":"https:\/\/wpengine.com\/builders\/?p=31923"},"modified":"2025-07-15T11:17:38","modified_gmt":"2025-07-15T16:17:38","slug":"create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini","status":"publish","type":"post","link":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/","title":{"rendered":"Create a Headless WordPress chatbot with WP Engine&#8217;s AI Toolkit, RAG, and Google Gemini"},"content":{"rendered":"\n<p>In this step-by-step guide, we will build a full-stack application that uses WP Engine\u2019s AI Toolkit, Retrieval Augmented Generation (RAG), and Google Gemini to deliver accurate and contextually relevant responses in a chatbot within a Next.js framework.<\/p>\n\n\n\n<p>Before we discuss the technical steps, let\u2019s review the tools and techniques we will use.<\/p>\n\n\n\n<div class=\"wp-block-group has-polar-background-color has-background is-layout-flow wp-container-core-group-is-layout-1 wp-block-group-is-layout-flow\" style=\"padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--40)\">\n<p class=\"has-large-font-size\"><strong>Table of Contents<\/strong><\/p>\n\n\n\n<ul id=\"Prerequisites\" class=\"wp-block-list\">\n<li><a href=\"#RAG\">RAG<\/a><\/li>\n\n\n\n<li><a href=\"#WP-Engine\u2019s-AI-Toolkit\">WP Engine\u2019s AI Toolkit<\/a><\/li>\n\n\n\n<li><a href=\"#Google-Gemini-API\">Google Gemini API (AI API\u2019s)<\/a><\/li>\n\n\n\n<li><a href=\"#Prerequisites\">Prerequisites<\/a><\/li>\n\n\n\n<li><a href=\"#make-requests-to-wpe-smart-search-api\">Make Requests to the WP Engine Smart Search API<\/a><\/li>\n\n\n\n<li><a href=\"#Creating-the-R-in-RAG\">Creating the R in RAG<\/a><\/li>\n\n\n\n<li><a href=\"#API-Endpoint-for-Chat-UI-The-AG-in-RAG\">API Endpoint for Chat UI <\/a><\/li>\n\n\n\n<li><a href=\"#Create-UI-Components-for-Chat-Interface\">Create UI Components for Chat Interface<\/a><\/li>\n\n\n\n<li><a href=\"#Messages-Component\">Messages Component<\/a><\/li>\n\n\n\n<li><a href=\"#Chat-Input-Component\">Chat Input Component<\/a><\/li>\n\n\n\n<li><a href=\"#Update-the-page-tsx-template\">Update the page.tsx template<\/a><\/li>\n\n\n\n<li><a href=\"#Update-the-layout-tsx-file-with-metadata\">Update the layout.tsx file with metadata<\/a><\/li>\n\n\n\n<li><a href=\"#test-the-chatbot\">Test the ChatBot<\/a><\/li>\n\n\n\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"RAG\">RAG<\/h2>\n\n\n\n<p>Retrieval-augmented generation (RAG) is a technique that enables AI models to retrieve and incorporate new information.<\/p>\n\n\n\n<p>It modifies interactions with a large language model (LLM) so that the model responds to user queries with reference to a specified set of documents, using this information to supplement information from its pre-existing training data. This allows LLMs to use domain-specific and\/or updated information.<\/p>\n\n\n\n<p>Our use case in this article will include providing chatbot access to our data from Smart Search.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"WP-Engine\u2019s-AI-Toolkit\">WP Engine\u2019s AI Toolkit<\/h2>\n\n\n\n<p>Here\u2019s an overview of WP Engine\u2019s AI Toolkit and the core capabilities it brings to both traditional and headless WordPress sites:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Smart Search &amp; AI-Powered Hybrid Search<\/strong><\/li>\n<\/ul>\n\n\n\n<p>At its heart, the AI Toolkit includes WP Engine Smart Search\u2014a drop-in replacement for WordPress\u2019s native search that\u2019s typo-tolerant, weight-aware, and ultra-fast. Out of the box, you get three modes: Full-Text (stemming and fuzzy matching), Semantic (NLP-driven meaning over mere keywords), and Hybrid (a tunable blend of both). Behind the scenes, Smart Search automatically indexes your Posts, Pages, Custom Post Types, ACF fields, WooCommerce products, and more\u2014so you can serve richer, more relevant results without writing a line of search logic yourself.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Vector Database, Fully Managed<\/strong><\/li>\n<\/ul>\n\n\n\n<p>You don\u2019t need to stand up or scale your own vector store\u2014WP Engine\u2019s AI Toolkit manages that for you. As new content is published or edited, the plugin streams updates in real time to its vector database. Queries are encoded into embeddings, nearest-neighbor lookups happen in milliseconds, and the freshest site content is always just a search away. This under-the-hood Vector DB also powers the AI aspects of Hybrid Search, ensuring that semantic similarity and context ranking work against live data.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Headless Integration<\/strong><\/li>\n<\/ul>\n\n\n\n<p>For sites using WP Engine\u2019s Headless Platform, all of these features\u2014Smart Search querying, vector indexing, AI-powered hybrid ranking, and recommendations\u2014are exposed through GraphQL. The AI Toolkit installs and configures both WPGraphQL and Smart Search automatically, so your front-end app can orchestrate retrieval and generation without extra middleware.<br><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Recommendations<\/strong><\/li>\n<\/ul>\n\n\n\n<p>An AI-driven content discovery feature that helps you surface \u201cRelated\u201d or \u201cTrending\u201d posts (or custom post types) anywhere on your site\u2014whether you\u2019re using the Gutenberg editor or building a headless front end via WPGraphQL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Google-Gemini-API\">Google Gemini API (AI API\u2019s)<\/h2>\n\n\n\n<p>The Google Gemini API offers developers a powerful and versatile interface to access Google&#8217;s state-of-the-art Gemini AI models. These multimodal models are designed to seamlessly understand and generate content across various data types, including text, code, images, audio, and video.&nbsp;<\/p>\n\n\n\n<p>For our chatbot integration, the Gemini API provides advanced natural language understanding, allowing it to interpret user queries and generate human-like responses. It supports multi-turn conversations, maintaining context over extended interactions, which is crucial for building engaging and intelligent conversational experiences. We will leverage the API&#8217;s flexibility to customize chatbot behavior, tone, and style, enabling a wide range of use cases from customer service to creative content generation.<\/p>\n\n\n\n<p><br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Prerequisites\">Prerequisites<\/h2>\n\n\n\n<p>To benefit from this article, you should be familiar with the basics of working with the command line, <a href=\"https:\/\/wpengine.com\/builders\/headless-roadmap\/\">headless WordPress<\/a> development, <a href=\"https:\/\/nextjs.org\/docs\">Next.js<\/a>, and the <a href=\"https:\/\/wpengine.com\/support\/wp-engine-user-portal\/\">WP Engine User Portal<\/a>.<br><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Steps for setting up:<\/h3>\n\n\n\n<p>1. Set up <a href=\"https:\/\/wpengine.com\/wordpress-hosting\/\">an account on WP Engine<\/a> and get a WordPress install running.&nbsp;&nbsp;<\/p>\n\n\n\n<p>2. Add a Smart Search license. Refer to the docs <a href=\"https:\/\/wpengine.com\/support\/wp-engine-smart-search\/#Enable\">here<\/a> for adding a license.<\/p>\n\n\n\n<p><br>3. Navigate to the WP Admin of your install.&nbsp; Inside your WP Admin, go to <strong><code>WP Engine Smart Search &gt; Settings<\/code><\/strong>.&nbsp; You will find your Smart Search URL and access token here.&nbsp; Copy and save it.&nbsp; We will need it later.&nbsp; You should see this page:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"567\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2025\/06\/Screenshot-2025-06-27-at-10.14.49\u202fAM-1024x567.png\" alt=\"\" class=\"wp-image-31928\" srcset=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2025\/06\/Screenshot-2025-06-27-at-10.14.49\u202fAM-1024x567.png 1024w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2025\/06\/Screenshot-2025-06-27-at-10.14.49\u202fAM-300x166.png 300w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2025\/06\/Screenshot-2025-06-27-at-10.14.49\u202fAM-768x425.png 768w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2025\/06\/Screenshot-2025-06-27-at-10.14.49\u202fAM-1536x850.png 1536w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2025\/06\/Screenshot-2025-06-27-at-10.14.49\u202fAM-2048x1134.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>4. Next, navigate to <code>Configuration<\/code>, select the <code>Hybrid<\/code> card, and add the <code>post_content<\/code> field in the <code>Semantic settings<\/code> section. We are going to use this field as our AI-powered field for similarity searches. Make sure to hit <code>Save Configuration<\/code> afterward.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA\" alt=\"\"\/><\/figure>\n\n\n\n<p>5. After saving the configuration, head on over to the <code>Index data<\/code> page, then click <code>Index Now<\/code><em>.&nbsp; <\/em>It will give you this success message once completed<em> :<\/em><br><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXe37oM4pSLurBZzGtf6l6eZ344jy9vMsDOaIOEev2Y7dcp03T-q_S8LTQt8z8G8JwBltM9Z_XQudFfGTTp9KrfJQCKv_whPgWNuYg3ZKrNI0j1nxqXrKILphqr9UF_HNAeovazvcg?key=qNKp1XJj5ZE7i5HzOmh0EA\" alt=\"\"\/><\/figure>\n\n\n\n<p>6. Create an <a href=\"https:\/\/aistudio.google.com\/\">API account on Google Gemini<\/a> (Or whatever AI model you choose, e.g., <a href=\"https:\/\/openai.com\/api\/\">OpenAI API<\/a>).&nbsp; Once created, navigate to your project\u2019s dashboard. If you are using the Gemini API, go to the Google AI Studio. In your project\u2019s dashboard, go to API Keys.&nbsp; You should see a page like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXf-PXmctmj2to4zSu92y5LrDgDTxJ-uR3kdD6EcPlVfjSuZUA4oUMeQc9N_j4AO-fMFxR9Fbo-kUkcb8uEmTxh80s9Gz4U-rnO3uYZa8_YTG38iXhJ5vvFzpYSlr2VhhDjLBGOV1g?key=qNKp1XJj5ZE7i5HzOmh0EA\" alt=\"\"\/><\/figure>\n\n\n\n<p>Generate a new key, copy, and save your API key because we will need this later.&nbsp; The API key is free on Google Gemini,&nbsp; but the free tier has limits.<\/p>\n\n\n\n<p>7.&nbsp; Head over to your terminal or CLI and create a new <a href=\"http:\/\/next.js\">Next.js<\/a> project by pasting this utility command in:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-selector-tag\">npx<\/span> <span class=\"hljs-selector-tag\">create-next-app<\/span><span class=\"hljs-keyword\">@latest<\/span> name-of-your-app\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><br>You will receive prompts in the terminal asking you how you want your <a href=\"http:\/\/next.js\">Next.js<\/a> app scaffolded.&nbsp; Answer them accordingly:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>Would you like to use TypeScript? Yes\n<\/span><\/span><span class='shcb-loc'><span>Wold you like to use ESLint? Yes\n<\/span><\/span><span class='shcb-loc'><span>Would you like to use Tailwind CSS? Yes\n<\/span><\/span><span class='shcb-loc'><span>Would you like to use the <span class=\"hljs-string\">`src\/`<\/span> directory? Yes\n<\/span><\/span><span class='shcb-loc'><span>Would you like to use App Router? Yes\n<\/span><\/span><span class='shcb-loc'><span>Would you like to customize the <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">import<\/span> alias (@<span class=\"hljs-comment\">\/*)? No<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><br>Once your <a href=\"http:\/\/next.js\">Next.js<\/a> app is created, you will need to install the dependencies needed to ensure our app works.&nbsp; Copy and paste this command in your terminal:<br><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-keyword\">@ai-sdk<\/span>\/google ai openai-edge react-icons react-markdown \n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Once the Next project is done scaffolding, <code>cd<\/code> into the project and then open up your code editor.<\/p>\n\n\n\n<p>8. In your Next.js project, create a&nbsp; <code>.env.local<\/code> file with the following environment variables:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>GOOGLE_GENERATIVE_AI_API_KEY=<span class=\"hljs-string\">\"&lt;your key here&gt;\"<\/span> <span class=\"hljs-comment\"># if you chose another AI model, you can name this key whatever you want<\/span>\n<\/span><\/span><span class='shcb-loc'><span>SMART_SEARCH_URL=<span class=\"hljs-string\">\"&lt;your smart search url here&gt;\"<\/span>\n<\/span><\/span><span class='shcb-loc'><span>SMART_SEARCH_ACCESS_TOKEN=<span class=\"hljs-string\">\"&lt;your smart search access token here&gt;\"<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><a href=\"https:\/\/github.com\/ToughCrab24\/smart-search-rag-chatbot\/tree\/gemini-tools-integration\">Here is the link to the final code repo<\/a> so you can check step by step and follow along.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"make-requests-to-wpe-smart-search-api\">Make Requests to the WP Engine Smart Search API<\/h2>\n\n\n\n<p>The first thing we need to do is set up the request to the Smart Search API using the Similarity query.&nbsp; Create a file in the <code>src\/app<\/code> directory called <code>utils\/<a href=\"http:\/\/context.ts\">context.ts<\/a><\/code>.&nbsp; Copy the code below and paste it into that file:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-comment\">\/\/ These are the types that are used in the `getContext` function<\/span>\n<\/span><\/span><span class='shcb-loc'><span>type Doc = {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">id<\/span>: string;\n<\/span><\/span><span class='shcb-loc'><span>  data: Record&lt;string, unknown&gt;;\n<\/span><\/span><span class='shcb-loc'><span>  score: number;\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>type Similarity = {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">total<\/span>: number;\n<\/span><\/span><span class='shcb-loc'><span>  docs: Doc&#91;];\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> type GraphQLSimilarityResponse = {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">data<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">similarity<\/span>: Similarity;\n<\/span><\/span><span class='shcb-loc'><span>  };\n<\/span><\/span><span class='shcb-loc'><span>  errors?: { <span class=\"hljs-attr\">message<\/span>: string }&#91;];\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> QUERY = <span class=\"hljs-comment\">\/* GraphQL *\/<\/span> <span class=\"hljs-string\">`<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">  query GetContext($message: String!, $field: String!) {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    similarity(<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      input: { nearest: { text: $message, field: $field } }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    ) {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      total<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      docs {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        id<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        data<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        score<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">  }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">`<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getContext = <span class=\"hljs-keyword\">async<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>  message: string,\n<\/span><\/span><span class='shcb-loc'><span>): <span class=\"hljs-built_in\">Promise<\/span>&lt;GraphQLSimilarityResponse&gt; =&gt; {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> url   = process.env.SMART_SEARCH_URL;\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> token = process.env.SMART_SEARCH_ACCESS_TOKEN;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">if<\/span> (!url || !token) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-string\">\"SMART_SEARCH_URL and SMART_SEARCH_ACCESS_TOKEN must be defined.\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>    );\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(url, {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">\"POST\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">headers<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-string\">\"Content-Type\"<\/span>: <span class=\"hljs-string\">\"application\/json\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">Authorization<\/span>: <span class=\"hljs-string\">`Bearer <span class=\"hljs-subst\">${token}<\/span>`<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">body<\/span>: <span class=\"hljs-built_in\">JSON<\/span>.stringify({\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">query<\/span>: QUERY,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">variables<\/span>: { message, <span class=\"hljs-attr\">field<\/span>: <span class=\"hljs-string\">\"post_content\"<\/span> } <span class=\"hljs-keyword\">as<\/span> <span class=\"hljs-keyword\">const<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>    }),\n<\/span><\/span><span class='shcb-loc'><span>  });\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">if<\/span> (!res.ok) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Smart Search responded with <span class=\"hljs-subst\">${res.status}<\/span> <span class=\"hljs-subst\">${res.statusText}<\/span>`<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span> <span class=\"hljs-keyword\">return<\/span> res.json() <span class=\"hljs-keyword\">as<\/span> <span class=\"hljs-built_in\">Promise<\/span>&lt;GraphQLSimilarityResponse&gt;;\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This block defines TypeScript types (<code>Doc, Similarity, and Response<\/code>) to model the shape of a similarity\u2010search GraphQL response, and exports an async <code>getContext<\/code> function that performs the actual lookup. Inside <code>getContext<\/code>, it reads the Smart Search endpoint URL and access token from environment variables, then constructs a GraphQL query named <code>GetContext<\/code> that requests the nearest documents (by embedding similarity) for a given <code>message<\/code> against a specified field (<code>\u201cpost_content\u201d<\/code>).&nbsp;<\/p>\n\n\n\n<p>It sends that query and its variables in the body of a POST request\u2014complete with JSON content headers and a Bearer authorization header\u2014to the Smart Search API endpoint, and finally returns the parsed JSON result. By encapsulating the fetch logic and typing the response, this function provides a clean, reusable way to retrieve semantically related WordPress content for use in a RAG\u2010style chatbot.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Creating-the-R-in-RAG\">Creating the \u201cR\u201d in RAG<\/h2>\n\n\n\n<p>The next file we need to create is the \u201cRetrieval\u201d portion in our RAG pipeline.&nbsp; Create a <code>tools.ts<\/code> file in the <code>utils<\/code> folder and copy and paste this code block:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { tool } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"ai\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { z } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"zod\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { getContext } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/app\/utils\/context\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\">\/\/ Define the search tool<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> smartSearchTool = tool({\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">description<\/span>:\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-string\">\"Search for information about TV shows using WP Engine Smart Search. Use this to answer questions about TV shows, their content, characters, plots, etc., when the information is not already known.\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">parameters<\/span>: z.object({\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">query<\/span>: z\n<\/span><\/span><span class='shcb-loc'><span>      .string()\n<\/span><\/span><span class='shcb-loc'><span>      .describe(\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-string\">\"The search query to find relevant TV show information based on the user's question.\"<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      ),\n<\/span><\/span><span class='shcb-loc'><span>  }),\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">execute<\/span>: <span class=\"hljs-keyword\">async<\/span> ({ query }: { <span class=\"hljs-attr\">query<\/span>: string }) =&gt; {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">`&#91;Tool Execution] Searching with query: \"<span class=\"hljs-subst\">${query}<\/span>\"`<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">try<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">const<\/span> context = <span class=\"hljs-keyword\">await<\/span> getContext(query);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">if<\/span> (context.errors &amp;&amp; context.errors.length &gt; <span class=\"hljs-number\">0<\/span>) {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-built_in\">console<\/span>.error(\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-string\">\"&#91;Tool Execution] Error fetching context:\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>          context.errors\n<\/span><\/span><span class='shcb-loc'><span>        );\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-comment\">\/\/ Return a structured error message that the LLM can understand<\/span>\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-keyword\">return<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">`Error fetching context: <span class=\"hljs-subst\">${context.errors&#91;<span class=\"hljs-number\">0<\/span>].message}<\/span>`<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        };\n<\/span><\/span><span class='shcb-loc'><span>      }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">if<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>        !context.data?.similarity?.docs ||\n<\/span><\/span><span class='shcb-loc'><span>        context.data.similarity.docs.length === <span class=\"hljs-number\">0<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      ) {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"&#91;Tool Execution] No documents found for query:\"<\/span>, query);\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-keyword\">return<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">searchResults<\/span>: <span class=\"hljs-string\">\"No relevant information found for your query.\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        };\n<\/span><\/span><span class='shcb-loc'><span>      }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">const<\/span> formattedResults = context.data.similarity.docs.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">doc<\/span>) =&gt;<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-keyword\">if<\/span> (!doc) {\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-keyword\">return<\/span> {};\n<\/span><\/span><span class='shcb-loc'><span>        }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-keyword\">return<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">id<\/span>: doc.id,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">title<\/span>: doc.data.post_title,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">content<\/span>: doc.data.post_content,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">url<\/span>: doc.data.post_url,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">categories<\/span>: doc.data.categories.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">category: any<\/span>) =&gt;<\/span> category.name),\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">searchScore<\/span>: doc.score,\n<\/span><\/span><span class='shcb-loc'><span>        };\n<\/span><\/span><span class='shcb-loc'><span>      });\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-comment\">\/\/ console.log(\"&#91;Tool Execution] Search results:\", formattedResults);<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> { <span class=\"hljs-attr\">searchResults<\/span>: formattedResults }; <span class=\"hljs-comment\">\/\/ Return the formatted string<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    } <span class=\"hljs-keyword\">catch<\/span> (error: any) {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">\"&#91;Tool Execution] Exception:\"<\/span>, error);\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> { <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">`An error occurred while searching: <span class=\"hljs-subst\">${error.message}<\/span>`<\/span> };\n<\/span><\/span><span class='shcb-loc'><span>    }\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>});\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> weatherTool = tool({\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">description<\/span>:\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-string\">\"Get the current weather information for a specific location. Use this to answer questions about the weather in different cities.\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">parameters<\/span>: z.object({\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">location<\/span>: z\n<\/span><\/span><span class='shcb-loc'><span>      .string()\n<\/span><\/span><span class='shcb-loc'><span>      .describe(\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-string\">\"The location for which to get the current weather information.\"<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      ),\n<\/span><\/span><span class='shcb-loc'><span>  }),\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">execute<\/span>: <span class=\"hljs-keyword\">async<\/span> ({ location }: { <span class=\"hljs-attr\">location<\/span>: string }) =&gt; {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">`&#91;Tool Execution] Getting weather for location: \"<span class=\"hljs-subst\">${location}<\/span>\"`<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">try<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-comment\">\/\/ Simulate fetching weather data<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">const<\/span> weatherData = {\n<\/span><\/span><span class='shcb-loc'><span>        location,\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">temperature<\/span>: <span class=\"hljs-string\">\"22\u00b0C\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">condition<\/span>: <span class=\"hljs-string\">\"Sunny\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">humidity<\/span>: <span class=\"hljs-string\">\"60%\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">windSpeed<\/span>: <span class=\"hljs-string\">\"15 km\/h\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      };\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">const<\/span> formattedWeather = <span class=\"hljs-string\">`The current weather in <span class=\"hljs-subst\">${weatherData.location}<\/span> is <span class=\"hljs-subst\">${weatherData.temperature}<\/span> with <span class=\"hljs-subst\">${weatherData.condition}<\/span>. Humidity is at <span class=\"hljs-subst\">${weatherData.humidity}<\/span> and wind speed is <span class=\"hljs-subst\">${weatherData.windSpeed}<\/span>.`<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> { <span class=\"hljs-attr\">weather<\/span>: formattedWeather };\n<\/span><\/span><span class='shcb-loc'><span>    } <span class=\"hljs-keyword\">catch<\/span> (error: any) {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">\"&#91;Tool Execution] Exception:\"<\/span>, error);\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">`An error occurred while fetching weather data: <span class=\"hljs-subst\">${error.message}<\/span>`<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      };\n<\/span><\/span><span class='shcb-loc'><span>    }\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>});\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This module registers two \u201ctools\u201d with the AI SDK\u2014one for performing semantic searches against your WP Engine Smart Search index and another for fetching (simulated) weather data. The <code>smartSearchTool<\/code> uses Zod to validate a single query string, then calls your <code>getContext<\/code> helper to run a similarity\u2010search GraphQL request; it handles errors or empty results gracefully, formats any returned documents (including ID, title, content, URL, categories, and relevance score), and exposes them as a structured <code>searchResults<\/code> array.&nbsp;<\/p>\n\n\n\n<p><br>The <code>weatherTool<\/code> declares a location parameter, simulates a lookup of current conditions (temperature, humidity, wind speed), and returns a human\u2010readable summary. By wrapping each in the tool() factory\u2014complete with descriptions, parameter schemas, and execute functions\u2014this file makes both search and weather functionality available for the LLM to invoke during a conversation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"API-Endpoint-for-Chat-UI-The-AG-in-RAG\">API Endpoint for Chat UI &#8211; The AG in RAG<\/h2>\n\n\n\n<p>Next, let\u2019s create the chat endpoint for the Chat UI, which is the AG in RAG.&nbsp; In the <code>src\/app<\/code> directory, create a <code>api\/chat\/<\/code> subfolder, then add a <code>route.ts<\/code> file in there.&nbsp; Copy and paste this code into the file:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-comment\">\/\/ IMPORTANT! Set the runtime to edge<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> runtime = <span class=\"hljs-string\">\"edge\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { convertToCoreMessages, Message, streamText } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"ai\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { createGoogleGenerativeAI } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@ai-sdk\/google\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { smartSearchTool, weatherTool } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/app\/utils\/tools\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\">\/**<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\"> * Initialize the Google Generative AI API<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\"> *\/<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> google = createGoogleGenerativeAI();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">POST<\/span>(<span class=\"hljs-params\">req: Request<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">try<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> { messages }: { <span class=\"hljs-attr\">messages<\/span>: <span class=\"hljs-built_in\">Array<\/span>&lt;Message&gt; } = <span class=\"hljs-keyword\">await<\/span> req.json();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> coreMessages = convertToCoreMessages(messages);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> smartSearchPrompt = <span class=\"hljs-string\">`<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    - You can use the 'smartSearchTool' to find information relating to tv shows.<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      - WP Engine Smart Search is a powerful tool for finding information about TV shows.<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      - After the 'smartSearchTool' provides results (even if it's an error or no information found)<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      - You MUST then formulate a conversational response to the user based on those results but also use the tool if the users query is deemed plausible.<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        - If search results are found, summarize them for the user. <\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        - If no information is found or an error occurs, inform the user clearly.`<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> systemPromptContent = <span class=\"hljs-string\">`<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    - You are a friendly and helpful AI assistant <\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    - You can use the 'weatherTool' to provide current weather information for a specific location.<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    - Do not invent information. Stick to the data provided by the tool.`<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> response = streamText({\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">model<\/span>: google(<span class=\"hljs-string\">\"models\/gemini-2.0-flash\"<\/span>),\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">system<\/span>: &#91;smartSearchPrompt, systemPromptContent].join(<span class=\"hljs-string\">\"\\n\"<\/span>),\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">messages<\/span>: coreMessages,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">tools<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>        smartSearchTool,\n<\/span><\/span><span class='shcb-loc'><span>        weatherTool,\n<\/span><\/span><span class='shcb-loc'><span>      },\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">onStepFinish<\/span>: <span class=\"hljs-keyword\">async<\/span> (result) =&gt; {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-comment\">\/\/ Log token usage for each step<\/span>\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-keyword\">if<\/span> (result.usage) {\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-built_in\">console<\/span>.log(\n<\/span><\/span><span class='shcb-loc'><span>            <span class=\"hljs-string\">`&#91;Token Usage] Prompt tokens: <span class=\"hljs-subst\">${result.usage.promptTokens}<\/span>, Completion tokens: <span class=\"hljs-subst\">${result.usage.completionTokens}<\/span>, Total tokens: <span class=\"hljs-subst\">${result.usage.totalTokens}<\/span>`<\/span>\n<\/span><\/span><span class='shcb-loc'><span>          );\n<\/span><\/span><span class='shcb-loc'><span>        }\n<\/span><\/span><span class='shcb-loc'><span>      },\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">maxSteps<\/span>: <span class=\"hljs-number\">5<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>    });\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/\/ Convert the response into a friendly text-stream<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">return<\/span> response.toDataStreamResponse({});\n<\/span><\/span><span class='shcb-loc'><span>  } <span class=\"hljs-keyword\">catch<\/span> (e) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">throw<\/span> e;\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><br>This file defines an Edge\u2010runtime POST endpoint that wires up Google\u2019s Gemini model with two custom tools\u2014<code>smartSearchTool<\/code> for TV-show lookups via WP Engine Smart Search and <code>weatherTool<\/code> for fetching current weather. When a request arrives, it parses the incoming chat messages, converts them into the AI SDK\u2019s core message format, and assembles two system\u2010level prompts: one describing how to use the search tool, the other explaining the weather tool.&nbsp;<br><\/p>\n\n\n\n<p>It then invokes <code>streamText<\/code> with the Gemini \u201cflash\u201d model, the combined system prompt, the user\u2019s message history, and the tool definitions, allowing the LLM to call out to those tools during generation. A callback logs token usage after each reasoning step (up to five steps), and the function finally returns the AI\u2019s response as a streamed HTTP response.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Create-UI-Components-for-Chat-Interface\">Create UI Components for Chat Interface<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">The <code>Chat.tsx<\/code> file<\/h3>\n\n\n\n<p>Now, let\u2019s create the chat interface.&nbsp; In the <code>src\/app<\/code> directory, create a <code>components<\/code> folder.&nbsp; Then create a <code>Chat.tsx<\/code> file.&nbsp; Copy and paste this code block in that file:<br><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-string\">\"use client\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React, { ChangeEvent } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Messages <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/Messages\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { Message } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"ai\/react\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> LoadingIcon <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/Icons\/LoadingIcon\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> ChatInput <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/ChatInput\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>interface Chat {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">input<\/span>: string;\n<\/span><\/span><span class='shcb-loc'><span>  handleInputChange: <span class=\"hljs-function\">(<span class=\"hljs-params\">e: ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> <span class=\"hljs-keyword\">void<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>  handleMessageSubmit: <span class=\"hljs-function\">(<span class=\"hljs-params\">e: React.FormEvent&lt;HTMLFormElement&gt;<\/span>) =&gt;<\/span> <span class=\"hljs-keyword\">void<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>  messages: Message&#91;];\n<\/span><\/span><span class='shcb-loc'><span>  status: <span class=\"hljs-string\">\"submitted\"<\/span> | <span class=\"hljs-string\">\"streaming\"<\/span> | <span class=\"hljs-string\">\"ready\"<\/span> | <span class=\"hljs-string\">\"error\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> Chat: React.FC&lt;Chat&gt; = ({\n<\/span><\/span><span class='shcb-loc'><span>  input,\n<\/span><\/span><span class='shcb-loc'><span>  handleInputChange,\n<\/span><\/span><span class='shcb-loc'><span>  handleMessageSubmit,\n<\/span><\/span><span class='shcb-loc'><span>  messages,\n<\/span><\/span><span class='shcb-loc'><span>  status,\n<\/span><\/span><span class='shcb-loc'><span>}) =&gt; {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"chat\"<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex flex-col w-full mx-2\"<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Messages<\/span> <span class=\"hljs-attr\">messages<\/span>=<span class=\"hljs-string\">{messages}<\/span> \/&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      {status === \"submitted\" &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">LoadingIcon<\/span> \/&gt;<\/span>}<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{handleMessageSubmit}<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"ml-1 mt-5 mb-5 relative rounded-lg\"<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      &gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ChatInput<\/span> <span class=\"hljs-attr\">input<\/span>=<span class=\"hljs-string\">{input}<\/span> <span class=\"hljs-attr\">handleInputChange<\/span>=<span class=\"hljs-string\">{handleInputChange}<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">};<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Chat;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This file defines a client-side React Chat component that ties together your message list, input field, and loading indicator. It declares a <code>Chat<\/code> props interface\u2014containing the current input value, change and submit handlers, the array of chat messages, and a <code>status<\/code> flag\u2014and uses those props to control its rendering.<\/p>\n\n\n\n<p>Inside the component, it first renders the <code>&lt;Messages&gt;<\/code> list to show the conversation history. If the status is <code>\"submitted\"<\/code>, it displays a <code>&lt;LoadingIcon&gt; <\/code>spinner to indicate that a response is pending. <\/p>\n\n\n\n<p>Finally, it renders a <code>&lt;form&gt;<\/code> wrapping the <code>&lt;ChatInput&gt;<\/code> component wired to the provided input value and change handler, so users can type and submit new messages.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"Messages-Component\">Messages Component<\/h3>\n\n\n\n<p>Staying in the <code>src\/app\/components <\/code>directory, create a <code>Messages.tsx<\/code> file.&nbsp; Copy and paste this code block in:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { Message } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"ai\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { useEffect, useRef } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> ReactMarkdown <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react-markdown\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Messages<\/span>(<span class=\"hljs-params\">{ messages }: { messages: Message&#91;] }<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> messagesEndRef = useRef&lt;HTMLDivElement | <span class=\"hljs-literal\">null<\/span>&gt;(<span class=\"hljs-literal\">null<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    messagesEndRef.current?.scrollIntoView({ <span class=\"hljs-attr\">behavior<\/span>: <span class=\"hljs-string\">\"smooth\"<\/span> });\n<\/span><\/span><span class='shcb-loc'><span>  }, &#91;messages]);\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"border-1 border-gray-100 overflow-y-scroll flex-grow flex-col justify-end p-1\"<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">scrollbarWidth:<\/span> \"<span class=\"hljs-attr\">none<\/span>\" }}<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">    &gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">      {messages.map((msg, index) =&gt; (<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{index}<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{<\/span>`${<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">            <span class=\"hljs-attr\">msg.role<\/span> === <span class=\"hljs-string\">\"assistant\"<\/span> ? \"<span class=\"hljs-attr\">bg-green-500<\/span>\" <span class=\"hljs-attr\">:<\/span> \"<span class=\"hljs-attr\">bg-blue-500<\/span>\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">          } <span class=\"hljs-attr\">my-2<\/span> <span class=\"hljs-attr\">p-3<\/span> <span class=\"hljs-attr\">shadow-md<\/span> <span class=\"hljs-attr\">hover:shadow-lg<\/span> <span class=\"hljs-attr\">transition-shadow<\/span> <span class=\"hljs-attr\">duration-200<\/span> <span class=\"hljs-attr\">flex<\/span> <span class=\"hljs-attr\">slide-in-bottom<\/span> <span class=\"hljs-attr\">bg-blue-500<\/span> <span class=\"hljs-attr\">border<\/span> <span class=\"hljs-attr\">border-gray-900<\/span> <span class=\"hljs-attr\">message-glow<\/span>`}<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">        &gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"ml- rounded-tl-lg  p-2 border-r flex items-center\"<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">            {msg.role === \"assistant\" ? \"\ud83e\udd16\" : \"\ud83e\uddd2\ud83c\udffb\"}<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"ml-2 text-white\"<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ReactMarkdown<\/span>&gt;<\/span>{msg.content}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ReactMarkdown<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      ))}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{messagesEndRef}<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><br>The Messages component renders a scrollable list of chat messages, automatically keeping the view scrolled to the latest entry. It accepts a <code>messages<\/code> prop (an array of Message objects) and uses a <code>ref<\/code> to an empty <code>&lt;div&gt;<\/code> at the bottom; a <code>useEffect<\/code> hook watches for changes to the messages array and calls <code>scrollIntoView<\/code> on that ref so new messages smoothly come into view.&nbsp;<\/p>\n\n\n\n<p><br>Each message is wrapped in a styled <code>&lt;div&gt;<\/code> whose background color and avatar icon depend on the message\u2019s role (\u201cassistant\u201d vs. \u201cuser\u201d), and the text content is rendered via <code>ReactMarkdown<\/code> to support Markdown formatting.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"Chat-Input-Component\">Chat Input Component<\/h3>\n\n\n\n<p>Lastly, staying in the <code>components\/Chat<\/code> directory,&nbsp; we have the chat input.&nbsp; Create a <code>ChatInput.tsx<\/code> file and copy and paste this code block in:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { ChangeEvent } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> SendIcon <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/Icons\/SendIcon\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>interface InputProps {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">input<\/span>: string;\n<\/span><\/span><span class='shcb-loc'><span>  handleInputChange: <span class=\"hljs-function\">(<span class=\"hljs-params\">e: ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> <span class=\"hljs-keyword\">void<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Input<\/span>(<span class=\"hljs-params\">{ input, handleInputChange }: InputProps<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-gray-800 p-4 rounded-xl shadow-lg w-full max-w-2xl mx-auto\"<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{input}<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleInputChange}<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">Ask<\/span> <span class=\"hljs-attr\">Smart<\/span> <span class=\"hljs-attr\">Search<\/span> <span class=\"hljs-attr\">about<\/span> <span class=\"hljs-attr\">TV<\/span> <span class=\"hljs-attr\">shows...<\/span>\"}<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full bg-transparent text-gray-200 placeholder-gray-500 focus:outline-none text-md mb-3\"<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      \/&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex\"<\/span>&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"p-1 hover:bg-gray-700 rounded-md transition-colors ml-auto\"<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">aria-label<\/span>=<span class=\"hljs-string\">\"Send message\"<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{!input.trim()}<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        &gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SendIcon<\/span> \/&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Input;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This file exports an Input component that renders a styled text field and send button for your chat UI. It takes a <code>input<\/code> string and an <code>handleInputChange<\/code> callback to keep the input controlled, showing a placeholder prompt (<em>\u201cAsk Smart Search about TV shows\u2026\u201d<\/em>). The send button, decorated with a <code>SendIcon<\/code>, is disabled when the input is empty or just whitespace.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Update-the-page-tsx-template\">Update the <code>page.tsx<\/code> template<\/h2>\n\n\n\n<p>We need to modify the <code>src\/app\/page.tsx<\/code> file to add the Chat component to the page.&nbsp; In the <code>page.tsx<\/code> file copy and paste this code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-string\">\"use client\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Chat <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/Chat\/Chat\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { useChat } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@ai-sdk\/react\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { useEffect } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> Page: React.FC = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    messages,\n<\/span><\/span><span class='shcb-loc'><span>    input,\n<\/span><\/span><span class='shcb-loc'><span>    handleInputChange,\n<\/span><\/span><span class='shcb-loc'><span>    handleSubmit,\n<\/span><\/span><span class='shcb-loc'><span>    setMessages,\n<\/span><\/span><span class='shcb-loc'><span>    status,\n<\/span><\/span><span class='shcb-loc'><span>  } = useChat();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">if<\/span> (messages.length &lt; <span class=\"hljs-number\">1<\/span>) {\n<\/span><\/span><span class='shcb-loc'><span>      setMessages(&#91;\n<\/span><\/span><span class='shcb-loc'><span>        {\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">role<\/span>: <span class=\"hljs-string\">\"assistant\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">content<\/span>: <span class=\"hljs-string\">\"Welcome to the Smart Search chatbot!\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-string\">\"welcome\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        },\n<\/span><\/span><span class='shcb-loc'><span>      ]);\n<\/span><\/span><span class='shcb-loc'><span>    }\n<\/span><\/span><span class='shcb-loc'><span>  }, &#91;messages, setMessages]);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex flex-col justify-between h-screen bg-white mx-auto max-w-full\"<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex w-full flex-grow overflow-hidden relative bg-slate-950\"<\/span>&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Chat<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">input<\/span>=<span class=\"hljs-string\">{input}<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">handleInputChange<\/span>=<span class=\"hljs-string\">{handleInputChange}<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">handleMessageSubmit<\/span>=<span class=\"hljs-string\">{handleSubmit}<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">messages<\/span>=<span class=\"hljs-string\">{messages}<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">status<\/span>=<span class=\"hljs-string\">{status}<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        \/&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">};<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Page;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><br>This file defines our page component that leverages the <code>useChat<\/code> hook from the <code>@ai-sdk\/react<\/code> package to manage chat state, including messages, input text, submission handler, and status.&nbsp;<\/p>\n\n\n\n<p>Upon initial render, a <code>useEffect<\/code> hook checks if there are no messages and injects a default assistant greeting. The component returns a full-viewport flexbox layout with a styled background area in which it renders the <code>Chat<\/code> component, passing along the chat state and handlers.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Update-the-layout-tsx-file-with-metadata\">Update the <code>layout.tsx<\/code> file with metadata<\/h2>\n\n\n\n<p>We need to add metadata to our layout.&nbsp; Copy and paste this code block in the <code>src\/app\/layout.tsx <\/code>file:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> type { Metadata } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { Inter } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/font\/google\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">\".\/globals.css\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> inter = Inter({ <span class=\"hljs-attr\">subsets<\/span>: &#91;<span class=\"hljs-string\">\"latin\"<\/span>] });\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> metadata: Metadata = {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">\"Smart Search RAG\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">description<\/span>: <span class=\"hljs-string\">\"Lets make a chatbot with Smart Search\"<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>};\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">RootLayout<\/span>(<span class=\"hljs-params\">{<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-params\">  children,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-params\">}: Readonly&lt;{<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-params\">  children: React.ReactNode;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-params\">}&gt;<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"en\"<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{inter.className}<\/span>&gt;<\/span>{children}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This file configures the global layout and metadata for the app: it imports global styles, loads the Inter font, and sets the page title and description. The default <code>RootLayout<\/code> component wraps all page content in <code>&lt;html&gt;<\/code> and <code>&lt;body&gt;<\/code> tags, applying the Inter font\u2019s class to the body.<\/p>\n\n\n\n<p><strong><em>CSS Note: <\/em><\/strong><em>The last thing to add for the styling is the globals.css file. Visit the <a href=\"https:\/\/github.com\/ToughCrab24\/smart-search-rag-chatbot\/blob\/gemini-tools-integration\/src\/app\/globals.css\">code block here<\/a> and copy and paste it into your proje<\/em>ct.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"test-the-chatbot\">Test the ChatBot<\/h2>\n\n\n\n<p>The chatbot should be completed and testable in this state. In your terminal, run <code>npm run dev<\/code> and navigate to <code>http:\/\/localhost:3000<\/code>.  Try asking the chatbot a few questions.&nbsp; You should see this in your browser:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXeg9IlxWyxm97kCs7gqndYF914dg0USnUAh-oEEh40oJxPd-kNBh_Ds97svTei6zI1pNkpC1PvUAKF0H_AKzDBHMkRYTYpgH8kB45McA6OmjHLsOHplNvmDHTyTAXz9ihgPai0U?key=qNKp1XJj5ZE7i5HzOmh0EA\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h2>\n\n\n\n<p>We hope this article helped you understand how to create a chatbot with WP Engine\u2019s AI toolkit in headless WordPress!&nbsp; Stay tuned for the next article on embedding this and using it in traditional WordPress!!<\/p>\n\n\n\n<p>As always, we\u2019re super stoked to hear your feedback and learn about the headless projects you\u2019re working on, so hit us up in <a href=\"https:\/\/wpeng.in\/devrel-discord\/\">the Headless WordPress Discord<\/a>!<\/p>\n\n\n\n<p><br><\/p>\n\n\n\n<p><br><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this step-by-step guide, we will build a full-stack application that uses WP Engine\u2019s AI Toolkit, Retrieval Augmented Generation (RAG), and Google Gemini to deliver accurate and contextually relevant responses [&hellip;]<\/p>\n","protected":false},"author":20,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"footnotes":""},"categories":[23],"tags":[],"class_list":["post-31923","post","type-post","status-publish","format-standard","hentry","category-headless"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Create a Headless WordPress chatbot with WP Engine&#039;s AI Toolkit, RAG, and Google Gemini - Builders<\/title>\n<meta name=\"description\" content=\"Build a headless WordPress chatbot with WP Engine AI Toolkit, RAG, and Google Gemini API to deliver real-time, context-aware responses from your site content.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Create a Headless WordPress chatbot with WP Engine&#039;s AI toolkit, RAG, and Google Gemini\" \/>\n<meta property=\"og:description\" content=\"Create a smart, headless WordPress chatbot by combining WP Engine\u2019s AI Toolkit with RAG and Google Gemini API, so you can surface the right answers from your content in real time.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/\" \/>\n<meta property=\"og:site_name\" content=\"Builders\" \/>\n<meta property=\"article:published_time\" content=\"2025-06-27T17:53:07+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-07-15T16:17:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2025\/06\/WPE-Builders-YouTube-ScreenshotNavy-1920x1080-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Francis Agulto\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@wpebuilders\" \/>\n<meta name=\"twitter:site\" content=\"@wpebuilders\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Francis Agulto\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/\"},\"author\":{\"name\":\"Francis Agulto\",\"@id\":\"https:\/\/wpengine.com\/builders\/#\/schema\/person\/bcdcb4ac0b215c34b6b30e440a24dc54\"},\"headline\":\"Create a Headless WordPress chatbot with WP Engine&#8217;s AI Toolkit, RAG, and Google Gemini\",\"datePublished\":\"2025-06-27T17:53:07+00:00\",\"dateModified\":\"2025-07-15T16:17:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/\"},\"wordCount\":2139,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/wpengine.com\/builders\/#organization\"},\"image\":{\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA\",\"articleSection\":[\"Headless\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/\",\"url\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/\",\"name\":\"Create a Headless WordPress chatbot with WP Engine's AI Toolkit, RAG, and Google Gemini - Builders\",\"isPartOf\":{\"@id\":\"https:\/\/wpengine.com\/builders\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA\",\"datePublished\":\"2025-06-27T17:53:07+00:00\",\"dateModified\":\"2025-07-15T16:17:38+00:00\",\"description\":\"Build a headless WordPress chatbot with WP Engine AI Toolkit, RAG, and Google Gemini API to deliver real-time, context-aware responses from your site content.\",\"breadcrumb\":{\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#primaryimage\",\"url\":\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA\",\"contentUrl\":\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/wpengine.com\/builders\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Create a Headless WordPress chatbot with WP Engine&#8217;s AI Toolkit, RAG, and Google Gemini\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/wpengine.com\/builders\/#website\",\"url\":\"https:\/\/wpengine.com\/builders\/\",\"name\":\"Builders\",\"description\":\"Reimagining the way we build with WordPress.\",\"publisher\":{\"@id\":\"https:\/\/wpengine.com\/builders\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/wpengine.com\/builders\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/wpengine.com\/builders\/#organization\",\"name\":\"WP Engine\",\"url\":\"https:\/\/wpengine.com\/builders\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png\",\"contentUrl\":\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png\",\"width\":348,\"height\":68,\"caption\":\"WP Engine\"},\"image\":{\"@id\":\"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/wpebuilders\",\"https:\/\/www.youtube.com\/channel\/UCh1WuL54XFb9ZI6m6goFv1g\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/wpengine.com\/builders\/#\/schema\/person\/bcdcb4ac0b215c34b6b30e440a24dc54\",\"name\":\"Francis Agulto\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/wpengine.com\/builders\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/c24a68b84c9ad2b53c633d14917d8298?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/c24a68b84c9ad2b53c633d14917d8298?s=96&d=mm&r=g\",\"caption\":\"Francis Agulto\"},\"description\":\"Fran Agulto is a Developer Advocate at WP Engine. He is a lover of all things headless WordPress, Rock Climbing, and overall being stoked for people that love what they do and share that stoke with others! Follow me on Twitter for cool stoked headless WP!\",\"url\":\"https:\/\/wpengine.com\/builders\/author\/francis-agultowpengine-com-2-2-2-2-2-2-2-2-2-2-2-3\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Create a Headless WordPress chatbot with WP Engine's AI Toolkit, RAG, and Google Gemini - Builders","description":"Build a headless WordPress chatbot with WP Engine AI Toolkit, RAG, and Google Gemini API to deliver real-time, context-aware responses from your site content.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/","og_locale":"en_US","og_type":"article","og_title":"Create a Headless WordPress chatbot with WP Engine's AI toolkit, RAG, and Google Gemini","og_description":"Create a smart, headless WordPress chatbot by combining WP Engine\u2019s AI Toolkit with RAG and Google Gemini API, so you can surface the right answers from your content in real time.","og_url":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/","og_site_name":"Builders","article_published_time":"2025-06-27T17:53:07+00:00","article_modified_time":"2025-07-15T16:17:38+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2025\/06\/WPE-Builders-YouTube-ScreenshotNavy-1920x1080-1.png","type":"image\/png"}],"author":"Francis Agulto","twitter_card":"summary_large_image","twitter_creator":"@wpebuilders","twitter_site":"@wpebuilders","twitter_misc":{"Written by":"Francis Agulto","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#article","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/"},"author":{"name":"Francis Agulto","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/bcdcb4ac0b215c34b6b30e440a24dc54"},"headline":"Create a Headless WordPress chatbot with WP Engine&#8217;s AI Toolkit, RAG, and Google Gemini","datePublished":"2025-06-27T17:53:07+00:00","dateModified":"2025-07-15T16:17:38+00:00","mainEntityOfPage":{"@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/"},"wordCount":2139,"commentCount":0,"publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"image":{"@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#primaryimage"},"thumbnailUrl":"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA","articleSection":["Headless"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/","url":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/","name":"Create a Headless WordPress chatbot with WP Engine's AI Toolkit, RAG, and Google Gemini - Builders","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/#website"},"primaryImageOfPage":{"@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#primaryimage"},"image":{"@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#primaryimage"},"thumbnailUrl":"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA","datePublished":"2025-06-27T17:53:07+00:00","dateModified":"2025-07-15T16:17:38+00:00","description":"Build a headless WordPress chatbot with WP Engine AI Toolkit, RAG, and Google Gemini API to deliver real-time, context-aware responses from your site content.","breadcrumb":{"@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#primaryimage","url":"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA","contentUrl":"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfPSAjg4QZU_jBbZFI6UPq21KJ4kiKK23IKOUEgLCw9s7g_fp9d4fDsIDXI2aYNusQlkW_F6mh0MLViUbTy0vWNtUvb_ap6O4SSGH2DALW-_wkX16jwcxmw3G0wfqjO9_VkwXnJdA?key=qNKp1XJj5ZE7i5HzOmh0EA"},{"@type":"BreadcrumbList","@id":"https:\/\/wpengine.com\/builders\/create-a-headless-wordpress-chatbot-with-wp-engines-ai-toolkit-rag-and-google-gemini\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/wpengine.com\/builders\/"},{"@type":"ListItem","position":2,"name":"Create a Headless WordPress chatbot with WP Engine&#8217;s AI Toolkit, RAG, and Google Gemini"}]},{"@type":"WebSite","@id":"https:\/\/wpengine.com\/builders\/#website","url":"https:\/\/wpengine.com\/builders\/","name":"Builders","description":"Reimagining the way we build with WordPress.","publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wpengine.com\/builders\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/wpengine.com\/builders\/#organization","name":"WP Engine","url":"https:\/\/wpengine.com\/builders\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/","url":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png","contentUrl":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png","width":348,"height":68,"caption":"WP Engine"},"image":{"@id":"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/wpebuilders","https:\/\/www.youtube.com\/channel\/UCh1WuL54XFb9ZI6m6goFv1g"]},{"@type":"Person","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/bcdcb4ac0b215c34b6b30e440a24dc54","name":"Francis Agulto","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/c24a68b84c9ad2b53c633d14917d8298?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c24a68b84c9ad2b53c633d14917d8298?s=96&d=mm&r=g","caption":"Francis Agulto"},"description":"Fran Agulto is a Developer Advocate at WP Engine. He is a lover of all things headless WordPress, Rock Climbing, and overall being stoked for people that love what they do and share that stoke with others! Follow me on Twitter for cool stoked headless WP!","url":"https:\/\/wpengine.com\/builders\/author\/francis-agultowpengine-com-2-2-2-2-2-2-2-2-2-2-2-3\/"}]}},"_links":{"self":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/31923","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/comments?post=31923"}],"version-history":[{"count":0,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/31923\/revisions"}],"wp:attachment":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/media?parent=31923"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/categories?post=31923"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/tags?post=31923"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}